Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django Rest Framework view get_queryset is called twice

I have this ModelViewset and a ModelSerializer

class GenerarFacturaViewset(viewsets.ModelViewSet):
    serializer_class = serializer.FacturaSerializer 

    def get_queryset(self):
        self.queryset = []


        _nro = self.request.query_params.get('nro', None)
        venta_id = self.request.query_params.get('ventaid', None)

        if (venta_id is None or _nro is None):
            raise exceptions.ParseError("Parametros invalidos")

        nro = int(_nro)
        venta = models.Venta.objects.get(id=venta_id)

        if models.Factura.objects.filter(numero=nro):
            raise exceptions.ParseError("Ya existe una factura con ese numero")

        venta.generar_factura(nro)
        print("Factura generada con nro: ", nro)

        self.queryset = models.Factura.objects.filter(numero=nro)

        return self.queryset

Then when this ModelViewset is called the first time every work correctly until the return sentence then the get_queryset method is called again. I want to know why?

Other detail is that when the second exception is raised in the first get_queryset call, this is show as rest framework normal template but if it is raised in the second called, it is show in the django error template with the traceback and error messages.

thanks in advance

EDIT: I found a best way to do that i want The Linovia answer is correct and then i improve somethings.

To clarify, i need two parameters "venta_id" and "numero" to create a object "factura". In my first attempt i try get this parameters from request data, validate it and call the model method to create the object. All on get_queryset method. But i think it is not a good way to do it.

Then i create a new view and a serializer for this porpuse.

class AddProductoViewset(viewsets.ModelViewSet):
serializer_class = serializer.AddProductoSerializer
queryset = models.Venta.objects.all()
http_method_names = ['post', 'head']

def create(self, request, *args, **kwargs):
    venta_id = request.data.get('venta_id', None)
    producto_id = request.data.get('producto_id', None)
    cantidad = request.data.get('cantidad', None)

    serializer_r = serializer.AddProductoSerializer(data=request.data)
    if (serializer_r.is_valid(raise_exception=True)):
        print("Datos validos")
        venta = models.Venta.objects.get(id=venta_id)

        if models.Venta.productos.filter(id=producto_id):
            vpd = VentaProductoDetalle.objects.filter(venta_id=venta_id, producto_id=producto_id)[0]
            vpd.cantidad += int(cantidad)
            vpd.save()
        else:
            vpd = VentaProductoDetalle()
            vpd.venta = venta
            vpd.producto = models.Producto.objects.get(id=producto_id)
            vpd.cantidad = int(cantidad)
            vpd.save()
    queryset = models.Venta.objects.get(id=venta_id)
    serializer_r = serializer.VentaSerializer(queryset)
    return Response(serializer_r.data)

The serializer class:

class PostFacturaSerializer(serializers.Serializer):

venta_id = serializers.IntegerField()
numero = serializers.IntegerField()

class Meta:
    model = models.Factura

def validate(self, attrs):

    try:
        venta_id = attrs['venta_id']
        numero = attrs['numero']

    except KeyError as e:
        print("Error: ", e)
        raise serializers.ValidationError(
            "Campos no recibidos correctamente")


    if (models.Factura.objects.filter(numero=numero)):
        print("ya existe")
        raise serializers.ValidationError(
            "Ya existe una factura con ese nombre"
        )

    return attrs

then i remove the get_queryset override method, it is not necessary anymore.

Now, how you can see, i validate data on serializer so i just call the is_valid method on view's create method.I think this is a best way.

P.D:apologies for my bad english.

like image 806
RodixPy Avatar asked Jan 26 '17 00:01

RodixPy


1 Answers

Then when this ModelViewset is called the first time every work correctly until the return sentence then the get_queryset method is called again. I want to know why?

If you're using the BrowsableAPI, it'll call the get_queryset again in order to display the forms.

Other detail is that when the second exception is raised in the first get_queryset call, this is show as rest framework normal template but if it is raised in the second called, it is show in the django error template with the traceback and error messages.

No idea about that one. This may be the sign that you have another exception during the processing of the initial exception. However, get_queryset is not supposed to raise exceptions.

like image 184
Linovia Avatar answered Oct 20 '22 22:10

Linovia