首页 文章

序列化与Django Rest Framework的通用关系,具有写支持

提问于
浏览
2

我有以下型号:

class TaggedItem(models.Model):
    tag = models.SlugField()
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')

我试图以我可以通过API endpoints 分配内容对象的方式序列化此模型

到目前为止,我已经这样做了:

class TaggedItemSerializer(serializers.ModelSerializer):
    content_object = serializers.RelatedField(read_only=True)

    class Meta:
        model = TaggedItem

然而,这是只读 . 如果我删除了read_only参数,我必须为该字段指定查询集 . 但是,我有这种通用关系的许多不同的模型类型 . 如果我在序列化程序和模型中的其他地方指定所有可能的模型类型,似乎我正在复制代码 .

我也可以通过object_id和content_type字段设置内容对象,但是当我这样做时,我得到一个错误 .

例如:

{
    ...
    object_id: 1,
    content_type: 'auth.User'
}

使用 "detail": "JSON parse error - Expected object or value" 返回400响应

如何通过DRF API使这个content_object可写?

1 回答

  • 3

    像这样覆盖 .to_internal_value.validate.create 方法:

    from django.apps import apps
    
    class TaggedItemSerializer(serializers.ModelSerializer):
    
        class Meta:
            model = TaggedItem
            read_only_fields = ('content_type', 'object_id', 'content_object')
    
        def to_internal_value(self, data):
            object_id = data.pop('object_id')
            content_type = data.pop('content_type')
    
            ret = super(ConfigCalcSerializer, self).to_internal_value(data)
    
            ret['object_id'] = object_id
            ret['content_type'] = content_type
    
            return ret
    
        def validate(self, data):
            object_id = data.pop('object_id')
            content_type = data.pop('content_type')
    
            Model = apps.get_model(content_type)
    
            try:
                content_object = Model.objects.get(id=object_id)
            except Model.DoesNotExist:
                raise serializers.ValidationError('Not found')
            else:
                data['content_object'] = content_object
    
            return data
    
        def create(self, validate_data):
            return TaggedItem.objects.create(**validate_data)
    

相关问题