While I was making one of my first projects on Django, I had to create two models. One of them, Image
, has a field tags
which is a ManyToManyField
referring to the other model, Tag
. I wanted to add elements to the tags
field with a post_save
signal. No problem occur during this process (in particular, the elements I want to add exist), but at the end no element is added.
Here is a snipplet of the models.py
I've written so far :
# (Importing the modules ...)
class Image(models.Model):
id = models.AutoField(primary_key=True)
image = models.ImageField(upload_to="media/")
tags = models.ManyToManyField("Tag", related_name="images", blank=True)
class Tag(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=255)
def __str__(self):
return self.name
@receiver(post_save, sender=Image)
def create_tags(sender, instance, created, **kwargs):
if created:
print(f"Before : {instance.tags.all()}")
tag = Tag.objects.get(name="mytag")
instance.tags.add(tag)
instance.save()
print(f"After : {instance.tags.all()}")
When I add an element through the admin panel, the following is printed :
Before : <QuerySet []>
After : <QuerySet [<Tag: mytag>]>
But if I check the freshly added element, no tag is selected.
Could you please help me figuring out what I am doing wrong ? Thanks in advance and have a nice day !
EDIT : I have added the following at the end of create_tags
:
print(f"Instances with tag 'mytag' : {Tag.objects.get(name='mytag').images.all()}")
Every time I add an element, this only displays the element I am currently adding. Would this mean that the modification is not carried out of create_tags
?
EDIT 2 : I finally figured out where the problem was. See my answer.
I've finally found the problem ! At least for ManyToManyField
, tt turns out that adding an element should be done using a transaction. For this, one has to import from django.db import transaction
. Then, instead of just writing instance.tags.add(tag)
, this operation should be enveloped as follows :
def add_tag():
instance.tags.add(tag)
transaction.on_commit(add_tag)
If someone encounters the same problem, I hope this might help :)