Quiero escribir el método get_queryset () personalizado para el serializador basado en parámetros de consulta.

Aquí está mi serializador:

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'))

Si existe el objeto de modelA, la validación devolverá una instancia. Pero no quiero realizar la misma consulta en get_queryset () en mi rama if.

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

Encontré solo una solución: agregue la siguiente línea en mi método GET:

self.serializer = self.get_serializer()

Entonces será posible obtener valores validados en mi método get_queryset (). Pero a PyCharm no le gusta esta solución

2
Ernst 16 oct. 2018 a las 16:39

2 respuestas

La mejor respuesta

Tengo la fuerte impresión de que estás haciendo un mal uso del serializador. Después de un análisis rápido de su problema, creo que necesita filtrado DRF

Los serializadores procesan request.data que bajo el capó es solo Django request.POST y request.FILES pero en su implementación de get_queryset realiza búsquedas en request.query_params que en términos de Django es request.GET. Consulte los documentos DRF sobre esto.

Para lograr lo que necesita con los serializadores, tendría que abusar de las vistas, los campos del serializador y el serializador mismo. Simplemente no es lo que se supone que debe hacer. Además, no creo que necesite tanta validación en la búsqueda.

La personalización y el uso de filtro Django deberían resolver su problema.

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

NOTA No probé el código anterior, pero debería mostrarte cómo abordar este problema.

4
Kamil Niski 18 oct. 2018 a las 17:16

Qué tal user = get_object_or_404(queryset, id=ModelA_id). Me parece mejor a mí. get_object_or_404 capturará un objeto que necesita o generará una respuesta de Not Found.

0
D. Make 16 oct. 2018 a las 17:09