Django Rest Framework& SQL Server - “无法修改列列,因为它是计算的”

时间:2018-03-16 04:37:42

标签: python django-models django-rest-framework calculated-columns

当我的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'))>]

1 个答案:

答案 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'