简体   繁体   中英

How to save a nested relationship in django rest framework?

I am trying to save a nested relationship in Django REST Framework following the Django REST Framework guide but I couldn't do that.

I have a class "Asiento" which is a foregin key for another class "Apunte". When I get every "Asiento" Django REST Framework returns them and all of their "Apunte" objects. This works, but when I try to create/update an "Asiento" with writable nested serializers I get that AsientoSerializer(data=data).is_valid() == False .

class Apunte(TxerpadBase):
    debe = models.DecimalField(null=True, blank=True, max_digits=18, decimal_places=6)
    haber = models.DecimalField(null=True, blank=True, max_digits=18, decimal_places=6)
    cuenta = models.ForeignKey(Cuenta, related_name='mayor', on_delete=models.PROTECT)
    partner = models.ForeignKey(Partner, null=True, blank=True, on_delete=models.PROTECT)
    asiento = models.ForeignKey(Asiento, related_name='apuntes')
    fecha = models.DateField()
    recc = models.BooleanField(blank=True, default=False)
    conciliacion = models.ForeignKey('Conciliacion', null=True, blank=True, on_delete=models.SET_NULL)
    estado = FSMField(default='borrador')


class Asiento(TxerpadBase):
    numero = models.PositiveIntegerField(null=True, blank=True)
    fecha = models.DateField(blank=True, default=datetime.datetime.now)
    libro = models.ForeignKey('Libro', on_delete=models.PROTECT)
    periodo = models.ForeignKey(Periodo, on_delete=models.PROTECT)
    estado = FSMField(default='borrador')

class ApunteSerializer(serializers.ModelSerializer):
    fecha = serializers.DateField(
        format='%d-%m-%Y', input_formats=('%d-%m-%Y',),
        error_messages={'invalid': 'La fecha del apunte no esta en el formato correcto.'}
    )

    class Meta:
        model = Apunte


class AsientoSerializer(serializers.ModelSerializer):
    fecha = serializers.DateField(
        format='%d-%m-%Y', input_formats=('%d-%m-%Y',),
        error_messages={'invalid': 'La fecha del asiento no esta en el formato correcto.'}
    )
    apuntes = ApunteSerializer(many=True)

    class Meta:
        model = Asiento

    def create(self, data):
        apuntes_data = data['apuntes']
        asiento_data = data
        asiento_data['fecha'] = datetime.datetime.strptime(asiento_data['fecha'], '%d-%m-%Y').date()
        del asiento_data['apuntes']
        asiento = Asiento.objects.create(**asiento_data)
        for apunte in apuntes_data:
            apunte['fecha'] = datetime.datetime.strptime(apunte['fecha'], '%d-%m-%Y').date()
            Apunte.objects.create(asiento=asiento, **apunte)

class AsientoViewSet(viewsets.ModelViewSet):
    queryset = Asiento.objects.all()
    serializer_class = AsientoSerializer

    def create(self, validated_data):
        # JSON dictionary is inside validated_data.data
        serializer = AsientoSerializer(data=validated_data.data)
        if serializer.is_valid():
            return Response(serializer.data)
        else:
            raise AttributeError('Error al validar')

This is JSON that I send with my request:

{
    u'name': u'prueba 3000', 
    u'periodo': 13, 
    u'fecha': u'18-02-2016', 
    u'numero': None, 
    u'estado': u'borrador', 
    u'libro': 1, 
    u'apuntes': [
        {
            u'name': u'a', 
            u'recc': False, 
            u'debe': u'1', 
            u'haber': u'0.00', 
            u'cuenta': u'5', 
            u'partner': 8, u'fecha': 
            u'18-02-2016', 
            u'conciliacion': u''
        }
    ]
}

If I debug the code only "create" method which executes is viewset's method, but it doesn't run "create" method from serializer.

With this code I can't save an "Asiento" neither an "Apunte". What am I doing wrong? Thank you for any answere!

I am using python 2.7 (I can't update it for external reasons) and Django REST Framework 3.3.2.

Ok, I found that my problem was that "asiento" attribute in "Apunte" object can't be null and I wasn't sending it. Now, I have changed "asiento" attribute in "Apunte" object and serializer finally works, and it is no needed "create" method on ViewSet.

Thanks to everyone for your answeres.

First thing you should do in case of invalid serialization is to look at the returned message (serializer.data). It'll help you understand what's going wrong.

My blind guess here is that you're missing the queryset argument relating to the nested serializer. If not set, DRF will consider those fields as read only.

Edit: After the OP edition, the issue comes from the viewset. You need to call serializer.save() if the serializer is valid. Have a look at how the CreateMixin does it.

Not sure if thats the solution. But the create method of a serializer has to return the created object. Try adding return to your last line

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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