[英]'Dynamic' fields in DRF serializers
我的目标是建立一个端点,它可以使用 GenericForeignKey 创建模型对象。 由于模型还包括 ContentType,因此我们将引用的模型的实际类型在对象创建之前是未知的。
我将提供一个例子:
我有一个“Like”模型,它可以引用一组其他模型,如“Book”、“Author”。
class Like(models.Model):
created = models.DateTimeField()
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
序列化器可能如下所示:
class LikeSerializer(serializers.ModelSerializer):
class Meta:
model = models.Like
fields = ('id', 'created', )
我想要实现的是根据请求中传递的键来确定 Like 的类型。 问题是如果没有在Serializer
器字段中明确指定,DRF 不会从请求中传递这些密钥。 例如,POST 请求正文包含:
{
"book":2
}
我想做下一个
def restore_object(self, attrs, instance=None)
if attrs.get('book', None) is not None:
# create Like instance with Book contenttype
elif attrs.get('author', None) is not None:
# create Like instance with Author contenttype
在这种情况下,将执行第一个 if 子句。 可以看到,根据请求传入的key确定的类型,没有指定特殊的Field。
有什么办法可以做到这一点?
谢谢
每当您的视图被调用时,您可以尝试实例化您的序列化器,方法是将其包装在一个函数中(您创建一个序列化器工厂):
def like_serializer_factory(type_of_like):
if type_of_like == 'book':
class LikeSerializer(serializers.ModelSerializer):
class Meta:
model = models.Like
fields = ('id', 'created', )
def restore_object(self, attrs, instance=None):
# create Like instance with Book contenttype
elif type_of_like == 'author':
class LikeSerializer(serializers.ModelSerializer):
class Meta:
model = models.Like
fields = ('id', 'created', )
def restore_object(self, attrs, instance=None):
# create Like instance with Author contenttype
return LikeSerializer
然后在您的视图中覆盖此方法:
def get_serializer_class(self):
return like_serializer_factory(type_of_like)
基本上,您可以在 GenericAPIView 类上添加一个名为 get_context_serializer 的方法。默认情况下,您的视图、请求和格式类将传递给您的序列化程序 DRF 代码以获得 get_context_serializer
def get_serializer_context(self):
"""
Extra context provided to the serializer class.
"""
return {
'request': self.request,
'format': self.format_kwarg,
'view': self
}
你可以像这样在你的视图上覆盖它
def get_serializer_context(self):
data = super().get_serializer_context()
# Get the book from post and add to context
data['book'] = self.request.POST.get('book')
return data
并在您的序列化程序类上使用它
def restore_object(self, attrs, instance=None):
# Get book from context to use
book = self.context.get('book', None)
author = attrs.get('author', None)
if book is not None:
# create Like instance with Book contenttype
pass
elif author is not None:
# create Like instance with Author contenttype
pass
在您的序列化程序上添加一个字段
class LikeSerializer(serializers.ModelSerializer):
# New field and should be write only, else it will be
# return as a serializer data
book = serializers.IntegerField(write_only=True)
class Meta:
model = models.Like
fields = ('id', 'created', )
def save(self, **kwargs):
# Remove book from validated data, so the serializer does
# not try to save it
self.validated_data.pop('book', None)
# Call model serializer save method
return super().save(**kwargs)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.