我有一个使用通用外键的模型,使用" content_type"用于存储内容类型的字段和" object_id"存储对象ID。需要使用CRUD API操作此模型,并且我正在使用DRF。我有一个模型的序列化器,但我遇到了一些问题。如果我只是将content_type添加到像这样的字段列表
class MySerializer(ModelSerializer): class Meta: fields = ('name', 'state', 'content_type', 'object_id')
序列化程序将JSON表示设置为ContentType模型实例的ID。 API的用户不知道这些ID,我不想用另一个API公开ContentType模型。 API用户确实知道他们想要链接的对象类型,因此他们可以发送内容类型名称。所以,我已经定义了像这样的序列化器
class MySerializer(ModelSerializer): content_type = serializers.CharField(source="content_type.name") class Meta: fields = ('name', 'state', 'content_type', 'object_id')
序列化模型工作得很好。如果我使用通用关系链接User实例,我会得到类似{'name': 'test', 'state': 'NY', 'content_type': 'user', 'object_id': 123}
的内容。但是当我使用JSON结构提交PUT或POST请求时,DRF将其转换为类似{'name': 'test', 'state': 'NY', 'content_type': {'name': {'name': 'user'}}, 'object_id': 123}
的内容。我可以写点像
def create(self, validated_data): ct_model = validated_data['content_type']['name']['name'] validated_data['content_type'] = ContentType.objects.get(model=ct_model) return MyModel.objects.create(**validated_data)
但它看似随意而脆弱。处理这种情况的正确方法是什么?
更新#1:目前,我已通过使用此代码覆盖to_internal_value()来解决问题
def to_internal_value(self, data): content_type = data.get('content_type', None) validated_data = super().to_internal_value(data) try: validated_data['content_type'] = ContentType.objects.get(model=content_type) except ContentType.DoesNotExist: raise serializers.ValidationError("invalid content type %s" % content_type) return validated_data
显示相关对象似乎是一种丑陋的黑客行为。
答案 0 :(得分:0)
您可能需要自定义,提供自己的字段类,使用to_representation
和to_internal_value
方法来序列化此类关系。它并不复杂,试一试。
考虑使用uri表示法/api/resource/object_id
作为序列化格式。
将内容类型转换为资源uris并返回可能有点挑战(如果您有多种可能的类型)但我确信必须有一些简单的方法来实现它。