[英]django-rest-framework override get_queryset and pass additional data to serializer along queryset
This is a toy example of the problem that I am facing.这是我面临的问题的一个玩具示例。 For some reason, I am unable to pass the expected data to my serializer and that is raising the following error.出于某种原因,我无法将预期的数据传递给我的序列化程序,这引发了以下错误。
AttributeError at /my-end-point/ /my-end-point/ 处的 AttributeError
Got AttributeError when attempting to get a value for field main_data
on serializer ParentSerializer
.尝试获取序列化ParentSerializer
main_data
上的字段main_data
的值时出现ParentSerializer
。 The serializer field might be named incorrectly and not match any attribute or key on the str
instance.序列化器字段可能命名不正确,并且与str
实例上的任何属性或键都不匹配。 Original exception text was: 'str' object has no attribute 'main_data'.原始异常文本是:“str”对象没有属性“main_data”。
class MainModelSerializer(serializers.ModelSerializer):
class Meta:
model = MainModel
class ParentSerializer(serializers.Serializer):
main_data = MainModelSerializer(many=True)
extra_data = serializers.FloatField()
class View(ListCreateAPIView):
serializer = ParentSerializer
def get_queryset(self):
# extra_data would have some calculated value which would be a float
extra_data = some_calculated_value()
queryset = MainModel.objects.filter(some filters)
return {
'main_data': queryset,
'extra_data': extra_data
}
# expected data that is passed to the ParentSerializer
# {
# 'main_data': queryset,
# 'extra_data': extra_data
# }
Look's like you have two problems:看起来你有两个问题:
get_queryset
method get_queryset
方法的返回值不正确As for the first one you simply should not override that method or return a queryset.至于第一个,您根本不应该覆盖该方法或返回查询集。 Depending on how extra data is being computing there can be the tradeoffs like annotating value on queryset and specifying it in serializer fields list .根据计算额外数据的方式,可以进行权衡,例如在查询集上注释值并在序列化器字段列表中指定它。
For the second one - if annotation is not an option and you'd like to calculate value one's, the possible solution is to add extra data to serializer context and use it as return value of serializer method field .对于第二个 - 如果注释不是一个选项并且您想计算一个值,可能的解决方案是将额外的数据添加到序列化器上下文并将其用作序列化器方法 field 的返回值。 In this case extra data will be placed on the same level with model records data (extra field for each model record):在这种情况下,额外的数据将与模型记录数据放在同一级别(每个模型记录的额外字段):
{
'model_field_1': 'value',
...
'extra_field': 'value',
}
Or you can continue using your approach with nested relationships by override list
(and create
, if needed) - just add extra data to serializer validated data, so that the result will look like this:或者,您可以通过覆盖list
(并create
,如果需要)继续使用嵌套关系的方法 - 只需将额外数据添加到序列化程序验证的数据中,结果将如下所示:
{
'extra_data': 'value',
'main_data': [
{'id': 1, 'field1': 'value', ...}
...
]
}
class View(ListCreateAPIView):
serializer = ParentSerializer
def list(self, request, *args, **kwargs):
# extra_data would have some calculated value which would be a float
extra_data = some_calculated_value()
qs = self.get_queryset()
data = self.get_serializer(qs, many=True).data
data['extra_data'] = extra_data
return Response({'data': data}, status=status.HTTP_200_OK, content_type = 'application/json' )
I think what you want to achieve is to pass some extra data to the ParentSerializer
to be returned by the list action
on your view.But you have multiple problems in your code:我认为您想要实现的是将一些额外的数据传递给ParentSerializer
,以便您的视图上的list action
返回。但是您的代码中存在多个问题:
get_queryset
is only used to return an instance of models.QuerySet
, which is used to determine which model objects the view is allowed to perform any kind of actions on. get_queryset
仅用于返回models.QuerySet
的实例,用于确定允许视图对哪些模型对象执行任何类型的操作。get_queryset
is not used to pass data to the serializer, this is done during the Serializer
initialization.这是对第一点的跟进, get_queryset
不用于将数据传递给序列化程序,这是在Serializer
程序初始化期间完成的。ModelSerializer
but you're not specifying the fields
attribute on the Meta
class which is not allowed anymore since drf version 3.3
, you have to define either a fields
attribute or an exclude
attribute.您正在使用ModelSerializer
但您没有在Meta
类上指定fields
属性,因为drf version 3.3
不再允许,您必须定义fields
属性或exclude
属性。As for actually how to pass that extra data to the Serializer, you can do that in multiple ways:至于实际上如何将额外数据传递给序列化程序,您可以通过多种方式做到这一点:
class ParentSerializer(serializers.Serializer):
main_data = MainDataSerializer(many=True)
extra_data = serializers.SerializerMethodField(method_name="some_calculated_value")
def some_calculated_value(self, obj):
# calculate value here
return value
Note that this field is a read only field.请注意,此字段是只读字段。
class ParentSerializer(serializers.Serializer):
main_data = MainDataSerializer(many=True)
def validate(self, attrs):
attrs["extra_data"] = some_calculated_value()
return attrs
list
function on the View and change the data passed to the serializer.您还可以通过覆盖视图上的list
函数并更改传递给序列化程序的数据来实现。 I personally prefer option number 1 since SerializerMethodField
fits the purpose, while the validate
function should be used only for validation to abide by the single responsibility concept.我个人更喜欢选项 1,因为SerializerMethodField
符合目的,而validate
函数应该仅用于验证以遵守单一职责概念。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.