django rest framework - 当主键也是外键时POST - "此字段是必需的。"或者' RelatedManager'对象不可迭代

时间:2014-09-29 16:50:43

标签: django django-rest-framework

我在对以下型号进行POST时遇到问题 -

class Tskmst(models.Model):
    tskmst_id = models.IntegerField(db_column='tskmst_id', primary_key=True)
    tskmst_name = models.CharField(max_length=30)
    tskmst_desc = models.TextField(blank=True)
    tskmst_type = models.SmallIntegerField(blank=True, null=True)
    owner_id = models.ForeignKey(Owner, db_column='owner_id')
    tskmst_public = models.CharField(max_length=1, blank=True)
    tskmst_lstchgtm = models.DateTimeField(blank=True, null=True)
    nodmst_id = models.ForeignKey(Nodmst, db_column='nodmst_id', blank=True, null=True)
    servicemst_id = models.ForeignKey(Servicemst, db_column='servicemst_id', related_name='Tskmst_Servicemst_id', blank=True, null=True)
    def __unicode__(self):
        return self.tskmst_name   
    class Meta:
        managed = False
        db_table = 'tskmst'

class Tskmail(models.Model):
    tskmail_id = models.ForeignKey(Tskmst, db_column='tskmail_id', related_name='action_email_details', primary_key=True)
    tskmail_to_int = models.TextField(blank=True)
    tskmail_to_ext = models.TextField(blank=True)
    tskmail_subject = models.TextField(blank=True)
    tskmail_memo = models.TextField(blank=True) # This field type is a guess.
    tskmail_priority = models.SmallIntegerField(blank=True, null=True)
    tskmail_attach = models.TextField(blank=True)
    class Meta:
        managed = False
        db_table = 'tskmail'

在GET上它可以正常反向关系 - 这是我的序列化器

class ActionMailSerializer(serializers.ModelSerializer):

    class Meta:
        model = Tskmail
        resource_name = 'tskmail'
        fields = ('tskmail_id', 'tskmail_to_int', 'tskmail_to_ext', 'tskmail_subject', 'tskmail_memo',
                'tskmail_priority', 'tskmail_attach')

class ActionSerializer(serializers.ModelSerializer):
    owner_name = serializers.Field(source='owner_id.owner_name')
    nodmst_name = serializers.Field(source='nodmst_id.nodmst_name')
    servicemst_name = serializers.Field(source='servicemst_id.servicemst_name')
    action_email_details = ActionMailSerializer

    class Meta:
        model = Tskmst
        resource_name = 'tskmst'
        depth = 1
        fields = ('tskmst_id', 'tskmst_name', 'tskmst_desc', 'tskmst_type', 'owner_name', 'tskmst_public',
                'tskmst_lstchgtm', 'nodmst_name', 'servicemst_name', 'action_email_details')

但在POST时,它会在验证阶段抱怨以下内容 -

{
    "action_email_details": [
        {
            "tskmail_id": "This field is required."
        }
    ]
}

tskmail_id肯定存在,我对其他模型没有问题,其中PK与用于反向关系的FK不同。我该如何解决这个问题?

如果我将反向关系中的序列化代码更改为此 -

class ActionSerializer(serializers.ModelSerializer):
    owner_name = serializers.Field(source='owner_id.owner_name')
    nodmst_name = serializers.Field(source='nodmst_id.nodmst_name')
    servicemst_name = serializers.Field(source='servicemst_id.servicemst_name')
    action_email_details = ActionMailSerializer(required=False)

    class Meta:
        model = Tskmst
        resource_name = 'tskmst'
        depth = 1
        fields = ('tskmst_id', 'tskmst_name', 'tskmst_desc', 'tskmst_type', 'owner_name', 'tskmst_public',
                'tskmst_lstchgtm', 'nodmst_name', 'servicemst_name', 'action_email_details')

然后在POST上发出另一条消息 - RelatedManager对象不可迭代。

Traceback:
File "D:\Python27\lib\site-packages\django\core\handlers\base.py" in get_response
  112.                     response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "D:\Python27\lib\site-packages\django\views\generic\base.py" in view
  69.             return self.dispatch(request, *args, **kwargs)
File "D:\Python27\lib\site-packages\django\views\decorators\csrf.py" in wrapped_view
  57.         return view_func(*args, **kwargs)
File "D:\Python27\lib\site-packages\rest_framework\views.py" in dispatch
  400.             response = self.handle_exception(exc)
File "D:\Python27\lib\site-packages\rest_framework\views.py" in dispatch
  397.             response = handler(request, *args, **kwargs)
File "D:\Tidal\API\views.py" in put
  193.         if serializer.is_valid():
File "D:\Python27\lib\site-packages\rest_framework\serializers.py" in is_valid
  553.         return not self.errors
File "D:\Python27\lib\site-packages\rest_framework\serializers.py" in errors
  545.                 ret = self.from_native(data, files)
File "D:\Python27\lib\site-packages\rest_framework\serializers.py" in from_native
  996.         instance = super(ModelSerializer, self).from_native(data, files)
File "D:\Python27\lib\site-packages\rest_framework\serializers.py" in from_native
  368.             attrs = self.restore_fields(data, files)
File "D:\Python27\lib\site-packages\rest_framework\serializers.py" in restore_fields
  283.                 field.field_from_native(data, files, field_name, reverted_data)
File "D:\Python27\lib\site-packages\rest_framework\serializers.py" in field_from_native
  472.                 if serializer.is_valid():
File "D:\Python27\lib\site-packages\rest_framework\serializers.py" in is_valid
  553.         return not self.errors
File "D:\Python27\lib\site-packages\rest_framework\serializers.py" in errors
  521.                     identities = [self.get_identity(self.to_native(obj)) for obj in objects]

Exception Type: TypeError at /deploy/action/
Exception Value: 'RelatedManager' object is not iterable

1 个答案:

答案 0 :(得分:1)

如果您没有整数PK字段,Django不喜欢它。如果ForeignKey字段的名称与其db_column相同,我认为它也会遇到冲突。在这种情况下,传统的数据库设计使其变得困难。除了您描述的解决方法之外:

  

我想我可能会“欺骗”这个系统。我所做的是创建一个名为tskmail = models.IntegerField(db_column='tskmail_id', primary_key=True)的新字段,我从ForiegnKey中删除了primary_key=True,所以基本上我正在显示两次字段。

我可能会尝试将tskmail_id声明为整数PK字段,并将tskmail声明为ForeignKey db_column='tskmail_id'(或保留db_column未指定,以便默认选择适用)。可能值得检查Django如何实现子类非抽象模型 - 它们可能有一个PK字段也是父表的FK。