Reputation: 20848
We would like to access related ManyToManyField
data pre-save within the Model.save
method, however the data isn't available yet via the Django ORM because it's related ManyToManyField
data and doesn't get set until post-save
of the primary record.
Here's some example code of the relationship and where the related ManyToMany
records are accessed in Model.save
class Friend(models.Model):
name = models.CharField(max_length=50)
class Person(models.Model):
name = models.CharField(max_length=50)
friends = models.ManyToManyField(Friend)
def save(self, *args, **kwargs):
friends = self.friends.all()
# 'friends' is an empty QuerySet at this point
# I'd like to do something with friends here,
# but it gets set after save
super(Friend, self).save(*args, **kwargs)
Example use case where friends
are passed in on save
:
friend = Friend.objects.all()[0]
friend2 = Friend.objects.all()[1]
friends = [friend, friend2]
Person.objects.create(friends=friends)
Upvotes: 1
Views: 1349
Reputation: 7717
m2m relations establish after instance saved and get it's own id,so you can't access it within override save method,two way to archieve:
one: after django 1.9,transaction tools provide new method to listen db communication,doc is here.demo code is:
from django.db import transaction
class Person(models.Model):
name = models.CharField(max_length=50)
friends = models.ManyToManyField(Friend)
def save(self, *args, **kwargs):
instance = super(Person, self).save(*args, **kwargs)
transaction.on_commit(self.update_friend)
return instance
def update_friend(self):
for friend in self.friends.all():
print(friend.__str__())
second way is use signal,here is demo:
from django.db.models.signals import m2m_changed
@receiver(m2m_changed, sender=Person.friends.through)
def friends_change(sender, action, pk_set, instance=None, **kwargs):
if action in ['post_add', 'post_remove']:
queryset = instance.friends.all()
for friend in queryset:
print(friend.__str__())
Upvotes: 4