#19731 closed Uncategorized (invalid)
previous values of ManyToManyField in model's save method
Reported by: | Owned by: | nobody | |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 1.4 |
Severity: | Normal | Keywords: | manytomanyfield, save, previous |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Hello,
I'm terribly sorry for bothering you, but I believe this behavior may be incorrect. I've already asked at django-users mailing list and I've had no answer.
How to reproduce it:
class Tag(models.Model): name = models.CharField(max_length=50, unique=True, db_index=True) parent = ForeignKey('self', null=True, blank=True, related_name='children') class Album(models.Model): name = models.CharField(max_length=64, blank=True) tags = models.ManyToManyField(Tag, blank=True) def tags_(self): return ', '.join([t.name for t in self.tags.all()]) def save(self, *args, **kwargs): super(Album, self).save(*args, **kwargs) f = open('/tmp/test.txt', 'wt') f.write('%s\n%s\n' % (self.name, self.tags_())) f.close
Now let's go to django admin and create two tags: tag1, tag2. After that let's create an album 'Album_1' with tag 'tag1' and save the album. In the file /tmp/test.txt we see:
Album_1
Let's add tag2 to the album, change it's name to Album_2 and save. The file will be:
Album_2
tag1
Let's remove both tags and save:
Album_2
tag1, tag2
Let's save it again:
Album_2
So, while everything looks good in Django admin, we get old values of album.tags_() method in Album.save(), even if we call super(Album, self).save(*args, * *kwargs) before.
I've also tried to use signals like this:
@receiver(post_save, sender=Album) def album_save_handler(sender, instance, **kwargs): f = open('/tmp/test.txt', 'wt') f.write('%s\n%s\n' % (instance.name, instance.tags_())) f.close
And even like this:
@receiver(post_save, sender=Album) def album_save_handler(sender, instance, **kwargs): t = Album.objects.get(pk = instance.id).tags_() f = open('/tmp/test.txt', 'wt') f.write('%s\n%s\n' % (instance.name, t)) f.close
Still no luck, results are the same: previous tags instead of the current ones.
Change History (2)
comment:1 by , 12 years ago
Resolution: | → invalid |
---|---|
Status: | new → closed |
comment:2 by , 12 years ago
Russellm, thank you very much for your response! Since I'd read your explanation it was quite simple to find the solution: the 'm2m_changed' signal do the trick.
You've been caught by a leaky abstraction. M2M relationships aren't saved as part of the save() method.
In the admin, the main object is saved, and then the m2m relation is saved; so, by serializing the list of tags in the save method, you're printing the value of the tags before the new values have been saved.
If you want to install "post m2m save" behavior, you'd need to override the update view on the admin itself.