简体   繁体   English

在get_queryset()中使用序列化程序验证的数据

[英]Use serializer validated data in get_queryset()

I want to write custom get_queryset() method for serializer based on query params. 我想基于查询参数为序列化程序编写自定义get_queryset()方法。

Here is my serializer: 这是我的序列化器:

class SearchRequestSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=255, required=False)
    nickname = serializers.RegexField(
        r'^(?!(.*?\_){2})(?!(.*?\.){2})[A-Za-z0-9\._]{3,24}$',
        max_length=24,
        min_length=3,
        required=False,
    )
    modelA_id = serializers.CharField(max_length=11, min_length=11,
                                      required=False)

    def validate_modelA_id(self, value):
        queryset = modelA.objects.filter(id=value)
        if queryset.exists():
            return queryset.first()
        else:
            raise serializers.ValidationError(_('Not found'))

If object of modelA exists - validation will return an instance. 如果modelA的对象存在 - 验证将返回一个实例。 But I don't want to perform the same query in get_queryset() in my if branch. 但我不想在我的if分支中的get_queryset()中执行相同的查询。

def get_queryset(self):
    name = self.request.query_params.get('name', None)
    nickname = self.request.query_params.get('nickname', None)
    queryset = User.objects.filter(Q(name__contains=name)|Q(nickname__contains=nickname))
    if 'modelA_id' in self.request.query_params:
       # in this case will be annotated extra field to queryset
       # extra field will be based on 'modelA' instance which should be returned by serializer
    return queryset

I found only one solution - add the following line in my GET method: 我发现只有一个解决方案 - 在我的GET方法中添加以下行:

self.serializer = self.get_serializer()

Than it will be possible to get validated values in my get_queryset() method. 可以在我的get_queryset()方法中获取经过验证的值。 But PyCharm don't like this solution 但PyCharm不喜欢这个解决方案

I'm under strong impression that you are misusing the Serializer. 我强烈反对您滥用序列化程序。 After quick analysis of your issue i think you need DRF filtering 在快速分析您的问题后,我认为您需要DRF过滤

Serializers process request.data which under the hood is just Django request.POST and request.FILES yet in your get_queryset implementation you make lookups in request.query_params which in Django terms is request.GET . 序列化程序处理request.data ,它只是Django request.POSTrequest.FILES在你的get_queryset实现中你在request.query_params中进行查找,在Django术语中是request.GET Check the DRF docs on this. 检查DRF文档。

In order to achieve what you need with Serializers you would have to abuse the Views, Serializer Fields and Serializer itself. 为了通过Serializers实现您所需的功能,您必须滥用Views,Serializer Fields和Serializer本身。 It is simply not what its supposed to do. 根本不是它应该做的事情。 Additionaly I don't think that you need so much validation on search. 另外我认为你不需要在搜索上进行如此多的验证。

Customization and use of Django Filter should solve your problem. 定制和使用Django Filter应该可以解决您的问题。

class UserFilter(filters.FilterSet):
    class Meta:
        model = User
        fields = ['name', 'nickname', 'modelA_id']

    def filter_queryset(self, queryset):
        name = self.form.cleaned_data.get('name', None)
        nickname = self.form.cleaned_data.get('nickname', None)
        queryset = queryset.filter(Q(name__contains=name)|Q(nickname__contains=nickname))
        if 'modelA_id' in self.form.cleaned_data:
            # in this case will be annotated extra field to queryset
            # extra field will be based on 'modelA' instance which should be returned by serializer
        return queryset


class UserListView(generics.ListAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    filter_backends = (django_filters.rest_framework.DjangoFilterBackend,)
    filterset_class = UserFilter

NOTE I did not test code above but it should show you how to tackle this problem. 注意我没有测试上面的代码,但它应该告诉你如何解决这个问题。

How is about user = get_object_or_404(queryset, id=ModelA_id) . 如何关于user = get_object_or_404(queryset, id=ModelA_id) It looks better as for me. 它对我来说看起来更好。 get_object_or_404 will catch an object you need, or will raise Not Found responce. get_object_or_404将捕获您需要的对象,或者将引发Not Found响应。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM