简体   繁体   中英

Access related ManyToManyField data pre-save in the Django Model.save method

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)

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__())

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM