0

I'm trying to implement the update-method for nested representations in Django Rest Framework.

from django.db import models
from django.utils import timezone

from rest_framework import serializers


class Foo(models.Model):
    pass


class Bar(models.Model):
    foo = models.ForeignKey(Foo, on_delete=models.CASCADE, null=False, related_name='bars')
    name = models.CharField(max_length=255)
    create_date = models.DateField(null=False)


class BarSerializer(serializers.ModelSerializer):
    create_date = serializers.DateField(default=timezone.now)

    class Meta:
        model = Bar
        fields = ('name', 'create_date',)


class FooSerializer(serializers.ModelSerializer):
    bars = BarSerializer(many=True, required=False)

    def create(self, validate_data):
        bars_data = validated_data.pop('bars', [])
        foo = Foo.objects.create(**validated_data)

        for bar_data in bars_data:
            Bar.objects.create(foo=foo, **bar_data)

        return foo

    def update(self, instance, validated_data):
        bars_data = validated_data.pop('bars', None)
        if bars_data is not None:
            Bar.objects.filter(foo=instance).delete()
            for bar_data in bars_data:
                Bar.objects.create(foo=instance, **bar_data)

        return super().update(instance, validated_data)

    class Meta:
        model = Foo
        fields = ('bars',)

When creating an object I get the expected results, but whenever I want to update the bars list, without providing a create_date, I get an error saying that create_date cannot be None (which is correct):

django.db.utils.IntegrityError: NOT NULL constraint failed: myapp_bar.create_date

If I print bars_data inside update I can see that it doesn't get its default value from timezone.now. It isn't in the dictionary at all.

How do I access the default value here? It should have gone through the validation of the serializer, why isn't the default value added?

2 Answers 2

2

From docs:

The default is not applied during partial update operations. In the partial update case only fields that are provided in the incoming data will have a validated value returned.

So, you are going to have to add the value manually:

Bar.objects.create(foo=instance, **bar_data, create_date=timezone.now)
Sign up to request clarification or add additional context in comments.

Comments

0

You receive that error because in your Bar model the create_date attribute has null=False, if you want a default value prefer use auto_now or auto_now_add arguments in the created_date attr on your Bar model like this:

class Bar(models.Model):
    ...
    created_date = models.DateField(auto_now_add=True)

With this every time when you create a new instance of Bar the create_date will be added automatically.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.