Search code examples
djangodjango-rest-frameworkdjango-serializer

How to manage serializers in Django Rest Framework?


I use the following serializer in my ViewSet to create some Instance:

class InstanceCreateSerializer(ModelSerializer):
    class Meta:
        model = Instance
        fields = [
            "id",
            "name", "description", "company",
            "err_msg", "is_valid",
        ]

The fields author, company, is_valid and err_msg must be set by the service, not by the user. But if i use read_only_fields, as in the code below, then these fields cannot be changed by the service either.

class InstanceCreateSerializer(ModelSerializer):
    class Meta:
        model = Instance
        fields = [
            "id",
            "name", "description",
            "author", "company",
            "err_msg", "is_valid",
        ]
        read_only_fields = [
            "author", "company",
            "err_msg", "is_valid", 
        ]

How can I manage serializers or prevent the user from submitting values for these fields?


Additionally, these fields are available for input in the DRF Browsable API and Swagger, which is something I also want to fix.


Solution

  • You can use the HiddenField to not accept any data from user but populate it in validated_data.

    For example, you want the current user to be set as the author for your model. You can use HiddenField like this.

    class InstanceCreateSerializer(ModelSerializer):
        author = serializers.HiddenField(default=serializers.CurrentUserDefault())
    
        class Meta:
            model = Instance
            fields = [
                ...
                "author",
            ]
    

    As mentioned by others, you can also use validate method to validate/set your values.

    class InstanceCreateSerializer(ModelSerializer):
        ...
    
        def validate(self, attrs: dict) -> dict:
            attrs["company"] = attrs["author"].company
            return attrs
    
    

    If you want to set values only while creating/updating, use the respective create or update methods.

    class InstanceCreateSerializer(ModelSerializer):
        ...
        def create(self, validated_data: dict):
            validated_data["company"] = validated_data["author"].company
            instance = super().create(validated_data)
            return instance
    
        def update(self, instance, validated_data: dict):
            validated_data["company"] = validated_data["author"].company
            instance = super().update(instance, validated_data)
            return instance