How am I misunderstanding Django's get_or_create function?

We have a Django project that has a bunch of experiments, and each experiment can have zero or more text tags. The tags are stored in a table, and there is a many-to-many relationship between experiments and tags:

class Tag(models.Model):
    text = models.TextField(max_length=32, null=False, validators=[validate_unicode_slug], db_index=True, unique=True)

class Experiment(models.Model):
    ...
    tags = models.ManyToManyField(Tag)

If I add a tag to an experiment with get_or_create() it does the right thing, filling in the tag table and the joining table. If I remove the tag from the experiment with remove() it also does the right thing by removing just the row from the joining table and leaving the tag table intact. But if I later come to re-add the tag to the experiment, it throws a uniqueness constraint error because it’s trying to re-add the tag to the tag table. E.g:

    tag, created = experiment.tags.get_or_create(text="B")
    experiment.tags.remove(*experiment.tags.filter(text="B"))
    tag, created = experiment.tags.get_or_create(text="B")  # It fails the uniqueness test here.

Removing the uniqueness constraint just means it adds a new tag with identical text.

So is it possible to add and remove tags arbitrarily by just modifying the joining table if a tag already exists?

>Solution :

Seperate this process, because it’s not that simple with relations.

tag, created = experiment.tags.get_or_create(text="B")
experiment.tags.remove(*experiment.tags.filter(text="B"))
tag, created = Tag.objects.get_or_create(text="B")
experiment.tags.add(tag)

Leave a Reply