【问题标题】:How to update a many to many field in Django using the Signals如何使用信号更新 Django 中的多对多字段
【发布时间】:2021-06-08 15:48:38
【问题描述】:

我有两个模型:

class Website(models.Model):
    url = models.URLField()
    users = models.ManyToManyField(User)

    def __str__(self):
        return str(self.url)



class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    bio = models.TextField(null=True, blank=True)

    def __str__(self):
        return str(self.user.username)

这是我试图完成的信号:

@receiver(m2m_changed, sender=Website.users.through)
def update_bio_when_websites_updated(sender, instance, action, reverse, **kwargs):
    pass

当网站修改或更新时,我需要创建一个信号来更新用户的个人简介

但我不知道。 怎么可能?

【问题讨论】:

    标签: python django django-signals


    【解决方案1】:

    以下可能是解决方案但未使用的信号,而是覆盖中的保存方法 网站模型。

    class Website(models.Model):
        url = models.URLField()
        users = models.ManyToManyField(User)
    
        def __str__(self):
            return str(self.url)
    
        def save(self, *args, **kwargs):
            if not self.pk: # work only for updates
                for user in self.users.all():# it may slow down if no of users is high.
                 user.bio  = 'some thing'
                 user.save()
        super().save(*args, **kwargs) # calling the save
    

    注意:如果网站的用户数量过多, 遍历所有连接到网站的用户会减慢 应用程序,然后更新用户的简历可以作为后台 任务。

    【讨论】:

      【解决方案2】:

      你可以这样做。

      from django.db.models.signals import post_save, m2m_changed
      from django.dispatch import receiver
      
      from django.contrib.auth.models import User
      from .models import Profile, Website
      
      
      @receiver(post_save, sender=User)
      def save_profile(sender, instance, created, **kwargs):
          if created:
              Profile.objects.create(user=instance)
      
      
      @receiver(m2m_changed, sender=Website.users.through)
      def update_bio_when_websites_updated(sender, instance, action, reverse, **kwargs):
          if action == 'post_add':
              if reverse:
                  instance.profile.bio = '\n'.join(list(map(lambda x: x.url, instance.website_set.all().order_by('url'))))
                  instance.profile.save()
              else:
                  for user in instance.users.all():
                      user.profile.bio = '\n'.join(list(map(lambda x: x.url, user.website_set.all().order_by('url'))))
                      user.profile.save()
      

      另外,还有另一种方法可以试一试。您可以将update_bio_when_websites_updated 的输入打印到正文中,看看需要采取什么行动。

      def update_bio_when_websites_updated(sender, instance, action, reverse, pk_set, **kwargs):
          if action == 'post_add':
              # Add user to website - instance: website
              if not reverse:
                     print(instance)
                     print(pk_set)
              # Add website to user - instance: user
              else:
                     print(instance)
                     print(pk_set)
      

      通过运行此程序,您将知道该怎么做。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-11-14
        • 1970-01-01
        • 2020-08-13
        • 1970-01-01
        • 1970-01-01
        • 2012-01-11
        • 1970-01-01
        • 2012-12-01
        相关资源
        最近更新 更多