当我的SQL数据库中有一个计算列的表时,我遇到了尝试POST / PUT的问题。
我制作了一个非常通用的TemporalModelSerializer,TemporalModel和TemporalModelViewSet,为了简单起见我继承了它,它适用于基本表。
我的问题是 Description 计算列的情况,其计算值为Ticker + MaturityDate + Coupon。
我尝试将read_only_fields添加到我的Serializer但是仍然收到服务器错误
错误:
column column cannot be modified
model.py
class BondMaster(TemporalModel):
isin = models.CharField(db_column='ISIN', max_length=12)
ccy = models.CharField(db_column='CCY', max_length=3)
cty = models.CharField(db_column='CTY', max_length=4)
ticker = models.CharField(db_column='Ticker', max_length=20)
coupon = models.DecimalField(db_column='Coupon', max_digits=6, decimal_places=3, blank=True, null=True)
maturitydate = models.DateTimeField(db_column='MaturityDate')
description = models.CharField(db_column='Description', max_length=8000, blank=True, null=True)
class Meta:
managed = False
db_table = 'BondMaster'
views.py
class BondMasterViewSet(TemporalModelViewSet):
model = BondMaster
queryset = BondMaster.objects.filter(vflag=1)
def get_serializer_class(self):
TemporalModelSerializer.Meta.model = BondMaster
TemporalModelSerializer.Meta.read_only_fields = ('description',)
return TemporalModelSerializer
请提出想法
回溯
Internal Server Error: /bondmaster/1/
Traceback (most recent call last):
File "/backend/virtpy/local/lib/python2.7/site-packages/django/core/handlers/exception.py", line 41, in inner
response = get_response(request)
File "/backend/virtpy/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 187, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/backend/virtpy/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 185, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/backend/virtpy/local/lib/python2.7/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
return view_func(*args, **kwargs)
File "/backend/virtpy/local/lib/python2.7/site-packages/rest_framework/viewsets.py", line 95, in view
return self.dispatch(request, *args, **kwargs)
File "/backend/virtpy/local/lib/python2.7/site-packages/rest_framework/views.py", line 494, in dispatch
response = self.handle_exception(exc)
File "/backend/virtpy/local/lib/python2.7/site-packages/rest_framework/views.py", line 454, in handle_exception
self.raise_uncaught_exception(exc)
File "/backend/virtpy/local/lib/python2.7/site-packages/rest_framework/views.py", line 491, in dispatch
response = handler(request, *args, **kwargs)
File "/backend/virtpy/local/lib/python2.7/site-packages/rest_framework/mixins.py", line 70, in update
self.perform_update(serializer)
File "/backend/virtpy/local/lib/python2.7/site-packages/rest_framework/mixins.py", line 80, in perform_update
serializer.save()
File "/backend/virtpy/local/lib/python2.7/site-packages/rest_framework/serializers.py", line 209, in save
self.instance = self.update(self.instance, validated_data)
File "/backend/temporal.py", line 66, in update
self.delete_me(old_record)
File "/backend/temporal.py", line 76, in delete_me
obj = self.Meta.model.objects.create(**old_record)
File "/backend/virtpy/local/lib/python2.7/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/backend/virtpy/local/lib/python2.7/site-packages/django/db/models/query.py", line 394, in create
obj.save(force_insert=True, using=self.db)
File "/backend/virtpy/local/lib/python2.7/site-packages/django/db/models/base.py", line 807, in save
force_update=force_update, update_fields=update_fields)
File "/backend/virtpy/local/lib/python2.7/site-packages/django/db/models/base.py", line 837, in save_base
updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
File "/backend/virtpy/local/lib/python2.7/site-packages/django/db/models/base.py", line 923, in _save_table
result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
File "/backend/virtpy/local/lib/python2.7/site-packages/django/db/models/base.py", line 962, in _do_insert
using=using, raw=raw)
File "/backend/virtpy/local/lib/python2.7/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/backend/virtpy/local/lib/python2.7/site-packages/django/db/models/query.py", line 1076, in _insert
return query.get_compiler(using=using).execute_sql(return_id)
File "/backend/virtpy/local/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 1099, in execute_sql
cursor.execute(sql, params)
File "/backend/virtpy/local/lib/python2.7/site-packages/django/db/backends/utils.py", line 80, in execute
return super(CursorDebugWrapper, self).execute(sql, params)
File "/backend/virtpy/local/lib/python2.7/site-packages/django/db/backends/utils.py", line 65, in execute
return self.cursor.execute(sql, params)
File "/backend/virtpy/local/lib/python2.7/site-packages/django/db/utils.py", line 94, in __exit__
six.reraise(dj_exc_type, dj_exc_value, traceback)
File "/backend/virtpy/local/lib/python2.7/site-packages/django/db/backends/utils.py", line 65, in execute
return self.cursor.execute(sql, params)
File "/backend/virtpy/local/lib/python2.7/site-packages/sql_server/pyodbc/base.py", line 545, in execute
return self.cursor.execute(sql, params)
ProgrammingError: ('42000', '[42000] [FreeTDS][SQL Server]The column "Description" cannot be modified because it is either a computed column or is the result of a UNION operator. (271) (SQLExecDirectW)')
编辑2
以下是自我和版本的打印。 “delete_me”方法中的self.Meta.fields
TemporalModelSerializer(<BondMaster: BondMaster object>, context={u'view': <Theodore.views.BondMasterViewSet object>, u'request': <rest_framework.request.Request object>, u'format': None}, data={u'ismbs': u'N', u'yellowkey': u'Govt', u'description': u'PSPCAP 1.73 21-Jun-2022', u'cusip': u'69363TAL6', u'coupon': u'1.730', u'secondaryid': None, u'ccy': u'CAD', u'islinker': u'N', u'cty': u'CA', u'pricingsource': u'BGN', u'sedol': u' ', u'isgreen': u'N', u'pricingfactor': 100, u'maturitydate': u'2022-06-21T00:00:00.000Z', u'isin': u'69363TAL6', u'djangoid': 1, u'couponfrequency': 2, u'ticker': u'PSPCAP', u'issuername': u'Public Sector Pension Investment Board', u'isfloater': u'N'}, partial=False):
djangoid = IntegerField(read_only=True)
vf = HiddenField(default=datetime.datetime(2018, 3, 22, 5, 8, 13, 250155, tzinfo=<UTC>))
vt = HiddenField(default=datetime.datetime(3000, 12, 31, 23, 0))
vflag = HiddenField(default=1)
vu = HiddenField(default='Theodore')
isin = CharField(max_length=12, required=True)
yellowkey = CharField(max_length=10)
ccy = CharField(max_length=3)
cty = CharField(max_length=4)
ticker = CharField(max_length=20)
issuername = CharField(max_length=100)
isfloater = CharField(max_length=1)
islinker = CharField(max_length=1)
isgreen = CharField(max_length=1)
ismbs = CharField(max_length=1)
coupon = DecimalField(allow_null=True, decimal_places=3, max_digits=6, required=False)
couponfrequency = IntegerField(allow_null=True, required=False)
maturitydate = DateTimeField()
pricingsource = CharField(allow_blank=True, allow_null=True, max_length=20, required=False)
pricingfactor = IntegerField()
cusip = CharField(allow_blank=True, allow_null=True, max_length=9, required=False)
sedol = CharField(allow_blank=True, allow_null=True, max_length=7, required=False)
secondaryid = CharField(allow_blank=True, allow_null=True, max_length=12, required=False)
description = CharField(read_only=True)
class Meta:
validators = [<UniqueTogetherValidator(queryset=BondMaster.objects.all(), fields=(u'isin', u'vt'))>]
答案 0 :(得分:0)
看起来不是一个理想的解决方案。
然而,我在SQL数据库中显示计算列的工作只是通过模型上的计算属性复制它(因此它不再引用SQL数据库列)。
然后将其设置为我的序列化程序类
中的read_only_fields最终产品
<强>视图集强>
class BondMasterViewSet(TemporalModelViewSet):
model = BondMaster
queryset = BondMaster.objects.filter(vflag=1)
def get_serializer_class(self):
TemporalModelSerializer.Meta.model = BondMaster
fields = [f.name for f in BondMaster._meta.get_fields()]
fields.append('description')
TemporalModelSerializer.Meta.fields = fields
TemporalModelSerializer.Meta.read_only_fields = ('description',)
return TemporalModelSerializer
<强>模型强>
class BondMaster(TemporalModel):
isin = models.CharField(db_column='ISIN', max_length=12)
yellowkey = models.CharField(db_column='YellowKey', max_length=10)
ccy = models.CharField(db_column='CCY', max_length=3)
cty = models.CharField(db_column='CTY', max_length=4)
ticker = models.CharField(db_column='Ticker', max_length=20)
issuername = models.CharField(db_column='IssuerName', max_length=100)
coupon = models.DecimalField(db_column='Coupon', max_digits=6, decimal_places=3, blank=True, null=True)
couponfrequency = models.SmallIntegerField(db_column='CouponFrequency', blank=True, null=True)
maturitydate = models.DateTimeField(db_column='MaturityDate')
pricingsource = models.CharField(db_column='PricingSource', max_length=20, blank=True, null=True)
pricingfactor = models.IntegerField(db_column='PricingFactor')
cusip = models.CharField(db_column='CUSIP', max_length=9, blank=True, null=True)
sedol = models.CharField(db_column='SEDOL', max_length=7, blank=True, null=True)
secondaryid = models.CharField(db_column='SecondaryId', max_length=12, blank=True, null=True)
# description = models.CharField(db_column='Description', max_length=255, blank=True, null=True)
@property
def description(self):
return ' '.join([str(self.isin), str(self.coupon), str(self.maturitydate)])
class Meta:
managed = False
db_table = 'BondMaster'