保存与Django Rest Framework具有嵌套关系的模型序列化程序

时间:2015-05-30 23:02:29

标签: django django-rest-framework

我有以下内容:

class ClientSubscription(models.Model):

    activity = models.ForeignKey(Activity)
    client = models.ForeignKey(Client)
    subscription_date_start = models.DateField(blank = True, null = True)
    subscription_date_end = models.DateField(blank = True, null = True)

    class Meta:
        unique_together = ('activity', 'client')

以及以下序列化程序:

class ActivitySerializer(serializers.ModelSerializer):
    activity_slug = serializers.CharField(read_only = True, required=False)
    activity_type = serializers.PrimaryKeyRelatedField(read_only = True)
    activity_name = serializers.CharField(read_only = True, source = 'activity_type', required=False)\
    is_active = serializers.BooleanField(required=False)

    class Meta:
        model = Activity
        fields = ('id', 'activity_type', 'is_active', 'activity_name', 'activity_slug')

class ClientSubscriptionSerializer(serializers.ModelSerializer):
    activity = ActivitySerializer(read_only=False)
    client = serializers.PrimaryKeyRelatedField(queryset=Client.objects.all())
    subscription_date_start = serializers.DateField(format="%Y-%m-%d")
    subscription_date_end = serializers.DateField(format="%Y-%m-%d")

    class Meta:
        model = ClientConcernedSubscriptions
        fields = ('id', 'activity', 'client', 'subscription_date_start', 'subscription_date_end')

序列化方面的一切都很好 - 但我无法验证或保存反序列化的数据,并收到以下错误:

TypeError: int() argument must be a string or a number, not 'OrderedDict'

我查看了this,但我似乎无法使用此解决方案。

这是收到的数据:

{u'subscription_date_end': u'2015-10-01', 
'client': 8, 
u'subscription_date_start': u'2014-10-01', 
u'activity': {u'activity_name': u'Name', u'is_active': True, u'id': 14597, u'activity_slug': u'slug', u'activity_type': u'9'}, 
u'id': 58782}

我确信这是必须相当普遍的事情,而且我做的事情很愚蠢。我希望能够保存我的对象,以及能够改变相关领域的字段。

1 个答案:

答案 0 :(得分:4)

这是因为rest_framework中的唯一验证器需要嵌套关系的整数值,如果为相关字段创建自定义序列化程序,则反序列化会提供dict而不是主键值。

所以我做了这个解决方案,希望对你也有所帮助。

像这样创建一个Custom Validator

class UniqueTogetherNestedValidator(object):

def __init__(
        self, queryset=None, simple_fields=None, dict_fields=None,
        message='Not unique together value'):
    if queryset is None or simple_fields is None or dict_fields is None:
        raise TypeError(
            '__init__() missing 3 required positional arguments: \
\'queryset\', \'simple_fields\' and \'dict_fields\''
        )
    else:
        self.queryset = queryset
        self.simple_fields = simple_fields
        self.dict_fields = dict_fields
        self.message = message

def __call__(self, value):
    unique = {}
    for f in self.simple_fields:
        unique[f] = value[f]
    for f in self.dict_fields:
        unique['{}__id'.format(f)] = value[f]['id']
    print(unique)
    if self.queryset.filter(**unique).exists():
        raise serializers.ValidationError(self.message)

然后从序列化程序中的Meta调用它,至少提供queryset,simple_fields(来自de model的字段)和dict_fields(嵌套字段)。