django-rest-framework: serializer from DATA don

2019-08-01 01:44发布

问题:

I've a simple serializer like this:

class CategoryCreationSerializer(serializers.ModelSerializer):

    class Meta:
        model = Category

Category has an id field (Django primary key) and I don't get why the Serializer is not updating it.

Scenario: I've a BlogPost with a given category. I'm updating the BlogPost with a different Category (already created on the database). So the POST request will have all the BlogPost information with the new Category JSON object with the updated id:

{
    "id": 1,
    "title": "My first blog post",
    "category": {
        "id": 3,
        "name": "Techology"
    }
}

The problem is that when I'm doing this:

category_data = data.get('category')
    if category_data is not None:
        category_serializer = CategoryCreationSerializer(data=category_data)
        if category_serializer.is_valid():
            blog_post.category = category_serializer.object

inside category title will be updated but the id field will be NONE. Can you explain me why?

Cheers, Emanuele.

回答1:

By default, the id field that is automatically generated by Django REST Framework is read-only. Because of this, the id will always be none and it will try to create a new Category if there isn't already one attached.

You can override this by adding you own id field to the serializer that is not read-only.

class CategoryCreationSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField()

    class Meta:
        model = Category


回答2:

This is the official answer from the issue I created on django rest-framework git repository: https://github.com/tomchristie/django-rest-framework/issues/2114

Short answer though is that by default ModelSerializer will generate a read-only field for the id. (In the generic views you'll see that the id is set explicitly by the view code, based on the id in the URL) You'll want to explicitly declare the id field on the serializer so that you can make it read-write.

So I managed to solve my problem leaving the Serializer like the one in my question ( without id = serializers.IntegerField() )

category_data = data.get('category', None)
if category_data is not None:
    category_serializer = CategoryCreationSerializer(blog_post.category, data=category_data)
    if category_serializer.is_valid():
        category_serializer.object.id = category_data.get("id", None)
        blog_post.category = category_serializer.object