Pedro Rout
Pedro Rout

Reputation: 3

Serializers crash when return an instance

I am trying to add a new variable in my endpoint. Before I used cliente, but now I want to add user (for finding the cliente). The problem is that user is not in my Pedido model, so I add using user = serializers.IntegerField(). I can use it in the method without a problem, but when return the instance pedido, something is wrong.

serializers.py

class PedidoWriterSerializer(serializers.ModelSerializer):
    user = serializers.SerializerMethodField()
    lineas = DetallePedidoSimpleSerializer(many=True, required=False)
    class Meta:
        model = Pedido
        exclude = ('monto','entrega_realizada','pedido_confirmado', 'cliente',)
        extra_kwargs = { 'user': {'write_only': True} }

    def create(self, validated_data):
        if 'lineas' in validated_data:
            lineas = validated_data.pop('lineas')
        if 'entrega_solicitada' in validated_data:
            entregas_solicitadas = validated_data.pop('entrega_solicitada')
        user = self._kwargs.get('data').get('user')
        bandera = True
        c = Cliente.objects.get(usuario_id=user)
        validated_data['cliente'] = c
        if (not c.habilitado):
            bandera = False
        if bandera:
            total = 0
            for l in lineas:
                print(2)
                print(l)
                p = Producto.objects.get(pk=l['producto'].id)
                if ((not p.activo) or (not p.stock) or (not(l['cantidad']>0 and
                    l['cantidad'] <1000))):
                    bandera = False
                else:
                    today = datetime.now()
                    prom = p.ofertas.filter(activa=True,
                                                  desde__lte=today,
                                                  hasta__gte=today).last()
                    if prom:
                        monto_descuento = (p.precio * prom.descuento) / 100
                        total = (p.precio - monto_descuento) * l['cantidad']\
                                + \
                                total
                    else:
                        total = p.precio * l['cantidad'] + total
            if total < c.ciudad.monto_minimo:
                bandera = False
        if bandera:
            for e in entregas_solicitadas:
                he = Horario_Entrega.objects.get(pk=e.id)
                if (not he.activo):
                    bandera = False
        if bandera:
            pedido = Pedido.objects.create(cliente=c)
            for linea in lineas:
                linea['pedido'] = pedido
                Detalle_Pedido.objects.create(**linea)
            for entrega in entregas_solicitadas:
                pedido.entrega_solicitada.add(entrega)
            print('algo')
            self._kwargs.get('data').pop('user')
            pedido.save()
            # Everything is ok until this line 
            return pedido
        else:
            return None

viewset.py

class PedidoViewSet(viewsets.ModelViewSet):
    queryset = Pedido.objects.select_related('cliente',
                                             'entrega_pactada').prefetch_related('entrega_solicitada')
    serializer_class = PedidoSerializer
    filter_backends = (DjangoFilterBackend,)
    filter_fields = ('cliente__id',)
    authentication_classes = [JSONWebTokenAuthentication, ]
    permission_classes = [permissions.IsAuthenticated, ]

    def get_serializer_class(self):
        if self.action == 'retrieve':
            return PedidoSerializer
        if self.action == 'list':
            return PedidoSerializer
        return PedidoWriterSerializer

    def get_queryset(self):
        queryset = super(PedidoViewSet,self).get_queryset()
        today = timezone.now()
        queryset = queryset.filter(fecha__gte = today - timedelta(days=30),
                                   cliente__usuario__dni = self.request.user.dni).order_by(
        '-fecha')
        return queryset

this is the error messages:

ERROR Internal Server Error: /pedido/
Traceback (most recent call last):
  File "/home/pedro/.virtualenvs/superEnv/lib/python3.5/site-packages/rest_framework/fields.py", line 444, in get_attribute
    return get_attribute(instance, self.source_attrs)
  File "/home/pedro/.virtualenvs/superEnv/lib/python3.5/site-packages/rest_framework/fields.py", line 103, in get_attribute
    instance = getattr(instance, attr)
AttributeError: 'Pedido' object has no attribute 'user'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/pedro/.virtualenvs/superEnv/lib/python3.5/site-packages/django/core/handlers/exception.py", line 41, in inner
    response = get_response(request)
  File "/home/pedro/.virtualenvs/superEnv/lib/python3.5/site-packages/django/core/handlers/base.py", line 187, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/home/pedro/.virtualenvs/superEnv/lib/python3.5/site-packages/django/core/handlers/base.py", line 185, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/pedro/.virtualenvs/superEnv/lib/python3.5/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
    return view_func(*args, **kwargs)
  File "/home/pedro/.virtualenvs/superEnv/lib/python3.5/site-packages/rest_framework/viewsets.py", line 90, in view
    return self.dispatch(request, *args, **kwargs)
  File "/home/pedro/.virtualenvs/superEnv/lib/python3.5/site-packages/rest_framework/views.py", line 489, in dispatch
    response = self.handle_exception(exc)
  File "/home/pedro/.virtualenvs/superEnv/lib/python3.5/site-packages/rest_framework/views.py", line 449, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/home/pedro/.virtualenvs/superEnv/lib/python3.5/site-packages/rest_framework/views.py", line 486, in dispatch
    response = handler(request, *args, **kwargs)
  File "/home/pedro/.virtualenvs/superEnv/lib/python3.5/site-packages/rest_framework/mixins.py", line 22, in create
    headers = self.get_success_headers(serializer.data)
  File "/home/pedro/.virtualenvs/superEnv/lib/python3.5/site-packages/rest_framework/serializers.py", line 534, in data
    ret = super(Serializer, self).data
  File "/home/pedro/.virtualenvs/superEnv/lib/python3.5/site-packages/rest_framework/serializers.py", line 263, in data
    self._data = self.to_representation(self.instance)
  File "/home/pedro/.virtualenvs/superEnv/lib/python3.5/site-packages/rest_framework/serializers.py", line 488, in to_representation
    attribute = field.get_attribute(instance)
  File "/home/pedro/.virtualenvs/superEnv/lib/python3.5/site-packages/rest_framework/fields.py", line 463, in get_attribute
    raise type(exc)(msg)
AttributeError: Got AttributeError when attempting to get a value for field `user` on serializer `PedidoWriterSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `Pedido` instance.
Original exception text was: 'Pedido' object has no attribute 'user'.

Upvotes: 0

Views: 197

Answers (1)

Jorge Limas
Jorge Limas

Reputation: 168

The problem is that you are using a SerializerMethodField() for the user field. These kind of fields assume that you will have a method in the serializer with the same name and the return of that method is the value used for that field.

Example

class PedidoWriterSerializer(serializers.ModelSerializer):
    user = serializers.SerializerMethodField()

    def get_user(self, obj):
        return "any logic needed to get the user value"

    class Meta:
         model = PedidoWriter

So then when you get the serialized information you will have a field called "user" with that information, by the way the second argument "obj" is an instance of the ModelSerializer so you can access any other field of the Model using that variable.

Upvotes: 1

Related Questions