我的数据库模型包含事件,每个事件都连接到一个场所。 当我检索事件列表时,我使用:
venue = VenueSerializer(read_only=True)
当我发布到drf端点时,我使用:
venue = serializers.SlugRelatedField(
allow_null=True,
queryset=Venue.objects.all(),
required=False,
slug_field='id')
但是,这导致在我从发帖请求中收到的响应中,场地被序列化为一个子字段。我希望它使用VenueSerialiser进行响应。
我遇到过https://stackoverflow.com/a/49035208/5683904,但它仅适用于Viewset本身。
#serializer_class = EventSerializer
read_serializer_class = EventSerializer
create_serializer_class = EventCreateUpdateSerializer
由于与其他组件共享,我需要将此功能内置到序列化器本身中。
答案 0 :(得分:1)
问题
对SlugRelatedField的to_representation
方法进行了编码,以返回初始化期间传递给它的slug_field
关键字参数的值。
解决方法
扩展SlugRelatedField
并覆盖其to_representation
方法以返回完整的对象而不是子对象。这可能有些棘手,因为实际的模型实例不是该类的一部分。
具有两个字段,一个字段用于块,另一个字段用于实际的对象。这样更容易实现。
这是实现第二种解决方法的方法:
venue = VenueSerializer(read_only=True)
venue_id = serializers.SlugRelatedField(
write_only=True
allow_null=True,
queryset=Venue.objects.all(),
required=False,
slug_field='id')
更新:这显然是DRF中非常想要的功能。我也找到了一种实现第一个解决方法的方法。它处理PrimaryKeyRelatedField
,但您可能也可以对其进行修改以与SlugRelatedField
一起使用。在这里:
from collections import OrderedDict
from rest_framework import serializers
class AsymetricRelatedField(serializers.PrimaryKeyRelatedField):
def to_representation(self, value):
return self.serializer_class(value).data
def get_queryset(self):
if self.queryset:
return self.queryset
return self.serializer_class.Meta.model.objects.all()
def get_choices(self, cutoff=None):
queryset = self.get_queryset()
if queryset is None:
return {}
if cutoff is not None:
queryset = queryset[:cutoff]
return OrderedDict([
(
item.pk,
self.display_value(item)
)
for item in queryset
])
def use_pk_only_optimization(self):
return False
@classmethod
def from_serializer(cls, serializer, name=None, args=(), kwargs={}):
if name is None:
name = f"{serializer.__class__.name}AsymetricAutoField"
return type(name, [cls], {"serializer_class": serializer})
然后您可以像下面这样使用此字段:
class FooSerializer(serilizers.ModelSerializer):
bar = AsymetricRelatedField(BarSerializer)
class Meta:
model = Foo
您可以找到有关此here
的原始讨论