Ycon Ycon - 2 months ago 12
Python Question

Custom create method to prevent duplicates

I would like to add some logic to my serializer.py.

Currently it creates duplicate tags (giving a new ID to the item, but often it will match a tag name already).

In plain english



if exists:
# Find the PK that matches the "name" field
# "link" the key with Movie Class item
else:
# Create the "name" inside of Tag class
# "link" the key with Movie Class item


The data being posted looks like this:



{
"title": "Test",
"tag": [
{
"name": "a",
"taglevel": 1
}
],
"info": [

]
}


Models.py



class Tag(models.Model):
name = models.CharField("Name", max_length=5000, blank=True)
taglevel = models.IntegerField("Tag level", blank=True)
def __str__(self):
return self.name

class Movie(models.Model):
title = models.CharField("Whats happening?", max_length=100, blank=True)
tag = models.ManyToManyField('Tag', blank=True)
def __str__(self):
return self.title





Serializers



class MovieSerializer(serializers.ModelSerializer):
tag = TagSerializer(many=True, read_only=False)
class Meta:
model = Movie
fields = ('title', 'tag', 'info')

def create(self, validated_data):
tags_data = validated_data.pop('tag')
movie = Movie.objects.create(**validated_data)
for tag_data in tags_data:
movie.tag.create(**tag_data)
return movie

Answer

This will probably solve your issue:

tag = Tag.objects.get_or_create(**tag_data)[0]
movie.tag.add(tag)

get_or_create function returns tuple (instance, created), so you have to get instance with [0].

So the full code is:

def create(self, validated_data):
    tags_data = validated_data.pop('tag')
    movie = Movie.objects.create(**validated_data)
    for tag_data in tags_data:
        tag = Tag.objects.get_or_create(**tag_data)[0]
        movie.tag.add(tag)
    return movie