40min
40min

Reputation: 147

Django Rest Framework Serializers: exclude from validation related entity

I have m2m related entities:

class Tag(models.Model):
    name = models.CharField(
       max_length=80,
       blank=False,
       unique=True
)

class File(models.Model):
    tags = models.ManyToManyField(Tag)
    uploader = models.ForeignKey(User, on_delete=models.DO_NOTHING)

    name = models.CharField(
        max_length=255,
        blank=False,
        unique=True,
    )

and serializers for them:

class TagSerializer(serializers.ModelSerializer):
    class Meta:
        model = Tag
        fields = ('id', 'name')
        extra_kwargs = {
            'name': {
                'validators': [],
            },
        }

class FileSerializer(serializers.ModelSerializer):
    tags = TagSerializer(many=True, read_only=False)

    class Meta:
        model = File
        fields = ('id', 'name', 'tags')

    def update(self, instance, validated_data):
        tags_data = validated_data.pop('tags')

        if 'name' in validated_data:
           instance.name = validated_data['name']


        instance_tags = instance.tags.all()
        new_tag_list = []

        # add new tags
        for tag in tags_data:
            tag, created = Tag.objects.get_or_create(name=tag['name'])
            new_tag_list.append(tag)
            if tag not in instance_tags:
                instance.tags.add(tag)

        # remove old tags
        for instance_tag in instance_tags:
            if instance_tag not in new_tag_list:
                instance.tags.remove(instance_tag)

        return instance

as you can see I turned off all validation for Tag.name field in TagSerializer by this code setting: extra_kwargs = {'name': {'validators': []}} This is because of validation errors during saving updated File:

serializer = FileSerializer(file, data=request.data, partial=True)
if serializer.is_valid(): 
    ...

If you have File with list of tags and just want to add or remove some tags, you'll have error 'tag with such name already exists'.

So this spike is working, but for now I don't have unique check for Tag.name. I tried to write something like what in FileSerializer:

class FileSerializer(serializers.ModelSerializer):
    class Meta:
       model = File
       extra_kwargs = {
           'tags': {
                'validators': [],
            },
        }

but of course it's not working. Question is about any possibilities to not validate Tag entities at all when I add/remove its bindings with file.

Upvotes: 4

Views: 6606

Answers (2)

papulic
papulic

Reputation: 11

You can also get tags from instance, no need to send whole request through context.

tags_data = self.initial_data.get('tags', [])

Upvotes: 0

user8060120
user8060120

Reputation:

You can try, this way for update, but if this solution correct for you, you need also override the create method.

class FileSerializer(serializers.ModelSerializer):
    tags = TagSerializer(many=True, read_only=True)
    #                                       ^^^^^^

    class Meta:
        model = File
        fields = ('id', 'name', 'tags')

    def update(self, instance, validated_data):
        # Override tags_data = validated_data.pop('tags')
        # this way
        request = self.context['request']
        tags_data = request.data.get('tags', [])

        # Next your current code

in serializer initial add extra-context , when you use views from drf context added by get_serializer method.

serializer = FileSerializer(file, data=request.data, partial=True, context={'request': request})

Upvotes: 2

Related Questions