将额外的参数传递给 Django Rest Framework 中的序列化程序类
Posted
技术标签:
【中文标题】将额外的参数传递给 Django Rest Framework 中的序列化程序类【英文标题】:Pass extra arguments to Serializer Class in Django Rest Framework 【发布时间】:2014-05-24 05:01:26 【问题描述】:我想从 Viewset 向 DRF Serializer 类传递一些参数,所以我已经尝试过:
class OneZeroSerializer(rest_serializer.ModelSerializer):
def __init__(self, *args, **kwargs):
print args # show values that passed
location = rest_serializer.SerializerMethodField('get_alternate_name')
def get_alternate_name(self, obj):
return ''
class Meta:
model = OneZero
fields = ('id', 'location')
观看次数
class OneZeroViewSet(viewsets.ModelViewSet):
serializer_class = OneZeroSerializer(realpart=1)
#serializer_class = OneZeroSerializer
queryset = OneZero.objects.all()
基本上我想将一些基于查询字符串的值从视图传递到序列化器类,然后这些值将分配给字段。
这些字段实际上不包含在模型中动态创建的字段。
这个问题***的情况相同,但我无法理解答案。
任何人都可以在这种情况下帮助我或建议我更好的选择。
【问题讨论】:
@PauloScardine 你能给我提供简单的例子或任何我可以得到帮助的链接吗?我是 django 新手,所以听不懂你的话。 你提到的问题的答案是对的,去阅读get_serializer
方法的文档并重写它以返回一个自定义的序列化器实例。
Dynamically modifying serializer fields in Django Rest Framework的可能重复
我也提到了这个问题作为参考,但没有任何细节可以帮助我
我已阅读文档,但找不到任何传递额外参数的示例。只有示例如何使用不同的序列化类。这就是为什么我在这里发布问题
【参考方案1】:
“ModelSerializer”构造函数的“context”arg 非常简单。
例如:
在视图中:
my_objects = MyModelSerializer(
input_collection,
many=True,
context='user_id': request.user.id
).data
在序列化器中:
class MyModelSerializer(serializers.ModelSerializer):
...
is_my_object = serializers.SerializerMethodField('_is_my_find')
...
def _is_my_find(self, obj):
user_id = self.context.get("user_id")
if user_id:
return user_id in obj.my_objects.values_list("user_id", flat=True)
return False
...
所以你可以使用“self.context”来获取额外的参数。
Reference
【讨论】:
这不起作用..当我在序列化程序中传递带有额外字段的上下文时,这个额外的字段丢失并且上下文看起来像:'request': <rest_framework.request.Request object at 0x103a2ba20>, 'view': <api.views.CourseAssignmentViewSet object at 0x10326b828>, 'format': None
@redcyb 你能帮我解决这个问题吗***.com/questions/62039305/…【参考方案2】:
您可以在 YourView 中像这样覆盖 get_serializer_context
方法:
class YourView(GenericAPIView):
def get_serializer_context(self):
context = super().get_serializer_context()
context["customer_id"] = self.kwargs['customer_id']
context["query_params"] = self.request.query_params
return context
或类似:
class YourView(GenericAPIView):
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.context["customer_id"] = request.user.id
serializer.context["query_params"] = request.query_params
serializer.is_valid(raise_exception=True)
...
和 anywhere 在您的序列化程序中,您可以获得它。例如在自定义方法中:
class YourSerializer(ModelSerializer):
def get_alternate_name(self, obj):
customer_id = self.context["customer_id"]
query_params = self.context["query_params"]
...
【讨论】:
你能帮我解决这个问题吗***.com/questions/62039305/… @banky,我在***.com/a/62040334/6077223下方添加了评论 拯救了我的一天!这个找了好久【参考方案3】:要实现 redcyb 的答案 - 考虑在您的视图中使用来自 GenericAPIView
的 get_serializer_context
方法,如下所示:
def get_serializer_context(self):
return 'user': self.request.user.email
【讨论】:
只覆盖get_serializer_context
不会削减它,因为validated_data
使用上下文更新的真实位置是serializer.save()
方法,由ViewSet.update() -> ViewSet.perform_update()
和ViewSet.create() -> ViewSet.perform_create()
调用。但问题是他们没有将**kwargs
与上下文一起传递给save()
。因此,为了混合上下文,我们必须覆盖 perform_create
和 perform_update
以便它们将上下文传递给 save()
。
@andilabs 你能帮我解决这个问题吗? ***.com/questions/62039305/…【参考方案4】:
我写的一个旧代码,可能对过滤嵌套序列化程序有帮助:
class MySerializer(serializers.ModelSerializer):
field3 = serializers.SerializerMethodField('get_filtered_data')
def get_filtered_data(self, obj):
param_value = self.context['request'].QUERY_PARAMS.get('Param_name', None)
if param_value is not None:
try:
data = Other_model.objects.get(pk_field=obj, filter_field=param_value)
except:
return None
serializer = OtherSerializer(data)
return serializer.data
else:
print "Error stuff"
class Meta:
model = Model_name
fields = ('filed1', 'field2', 'field3')
如何覆盖 get_serializer_class:
class ViewName(generics.ListAPIView):
def get_serializer_class(self):
param_value = self.context['request'].QUERY_PARAMS.get('Param_name', None)
if param_value is not None:
return Serializer1
else:
return Serializer2
def get_queryset(self):
.....
希望这有助于人们寻找这个。
【讨论】:
正是我获取查询参数所需要的,谢谢!请注意,显示的代码已被弃用。要获取参数值,它现在看起来像self.context['request'].query_params.get()
。【参考方案5】:
如果您的查询是元素列表,则为元素列表:
my_data = DataSerializers(queryset_to_investigate,
many=True, context='value_to_pass': value_passed
如果关闭单条数据查询:
my_data = DataSerializers(queryset_to_investigate,
context='value_to_pass': value_passed
然后在序列化器中:
class MySerializer(serializers.ModelSerializer):
class Meta:
fields = '__all__'
model = 'Name_of_your_model'
def on_representation(self, value):
serialized_data = super(MySerializer, self).to_representation(value)
value_as_passed = self.context['value_to_pass']
# ..... do all you need ......
return serialized_data
您可以看到在on_representation
中打印自我,您可以看到:query_set: <object (x)>, context='value_to_pass': value_passed
这是一种更简单的方法,您可以在参数列表中包含 self 的序列化器的任何函数中执行此操作。
【讨论】:
【参考方案6】:这些答案远非复杂;如果您有任何类型的身份验证,则将此属性添加到您的序列化程序并调用它以访问发送请求的用户。
类 BaseSerializer(serializers.ModelSerializer):
@property
def sent_from_user(self):
return self.context['request'].user
【讨论】:
以上是关于将额外的参数传递给 Django Rest Framework 中的序列化程序类的主要内容,如果未能解决你的问题,请参考以下文章