【问题标题】:Django signals not sending on save() for models inheriting from a parent class?对于从父类继承的模型,Django 未在 save() 上发送信号?
【发布时间】:2019-10-02 11:46:10
【问题描述】:

我刚刚在我的模型上设置了继承,这对我的项目更有意义 - 一切都继承自 Item 类,具有公共元素。然后将其他字段添加到子类 - 视频、播客、文章等...

以前,在 Item.save() 上,我设置了一些 pre_save 和 post_save 信号,它们在我的 Item 模型对象上解析/执行各种任务。

 @receiver(pre_save, sender=Item)
def some_function(sender, instance, *args, **kwargs):
   print("I am working")

但是,现在我的对象都是 Item 的子类,这些信号似乎没有被触发。

>Article.objects.get_or_create(title='some title')

 @receiver(pre_save, sender=Article)
def some_function(sender, instance, *args, **kwargs):
   print("I am not doing anything")

models.py



class Item(models.Model, AdminVideoMixin):
    title = models.TextField(max_length=2000)
    slug = models.SlugField(max_length=500, default='')
    link = models.URLField(max_length=200)

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(get_random_string(length=5,allowed_chars='1234567890') + '-' + self.title)
        super().save(*args, **kwargs)

    def get_absolute_url(self):
        return reverse('curate:item_detail',args=[self.slug])

    def __str__(self):
        return self.title

class Video(Item):
    video_embed = EmbedVideoField(max_length=300)
    channel = models.TextField(max_length=500, blank=True

    def __str__(self):
        return self.title.upper()

class Article(Item):
    authors = models.CharField(max_length=10000)
    movies = models.TextField(max_length=10000)

    def __str__(self):
        return self.title.upper()

class Podcast(Item):
    authors = models.CharField(max_length=10000)
    itune_image = models.CharField(max_length=10000)
    owner_name = models.CharField(max_length=10000)

    def __str__(self):
        return self.title.upper()


class Episode(Item):
    authors = models.CharField(max_length=10000)
    itune_image = models.CharField(max_length=10000)
    owner_name = models.CharField(max_length=10000)
    enclosure_url = models.URLField(max_length=2000)
    owner = models.ForeignKey(Podcast, on_delete=models.CASCADE,max_length=2000)

    class Meta:
        pass

    def __str__(self):
        return self.title.upper()

我什至按照this thread 将接收器堆叠起来,以防它应该由父类和子类触发,但它仍然没有保存。

@receiver(post_save, sender=Video)
@receiver(post_save, sender=Item)
@receiver(post_save, sender=Article)
def some_function(sender, instance, *args, **kwargs):

    print('This still didn't fire')

还尝试使用 post_save.connect(some_function, sender=Article),但无法触发信号。我正在使用 get_or_create(attributes) 创建对象

我是否必须手动编写一些东西才能进入并执行预发布/保存,还是我做错了什么?我看到了a solution,但这建议将信号发送给所有子类——不管是哪个——但这不是我想要的。我想设置模型特定的 post_save / pre_save 信号而不是一揽子规则。

【问题讨论】:

  • save() 不会将保存前/保存后信号发送到父类(因为不能保证父表会实际保存,因为这只需要在字段打开时发生父模型受到影响)。 delete() 确实传播到父类 btw,因此信号处理程序适用于例如post_delete。但是,将所有类堆叠为接收器应该可以工作,所以不起作用的原因在于其他地方。您确定您的信号处理程序已处理(在启动时读取的文件中)吗?更改后您是否重新启动了服务器?
  • 您提到的解决方案也不是“向所有子类发送信号”,它将接收器连接到所有子类,正是您想要的(基本上与堆叠接收器相同,但没有以后创建新子类时要记住添加一个的麻烦)。
  • 我使用与以前完全相同的 signals.py 脚本(在应用程序文件夹内) - 我在脚本顶部导入了我可能需要的所有信号。 from django.contrib.auth.models import User from django.db.models.signals import post_save, pre_save
  • 我可以确认对象正在保存 - 它们在我的管理页面中,我可以在 shell 中与它们互动。
  • 感谢您的帮助 - 您是对的,问题来自其他地方。我正在使用一个名为报纸的包 - 但它实际上是作为文章导入的。所以我的signals.py 中有两个“Article”对象,Python/Django 没有抛出错误。我以不同的名称重新导入报纸 ArticleNewspaper

标签: python django model signals


【解决方案1】:

当我想为我的所有子模型类添加一个 pre_save 信号但我只想在一个地方实现时,我认为遇到了类似的问题。该解决方案可以使用 python 3.6+,因为它需要 __init_subclass__ 魔术方法。

子模型子类没有自动注册信号的问题。因此,您可以在 init_subclass 函数中为子模型注册信号,而不是手动注册信号

下面的代码示例显示了实现的要点:

Class BaseModel:
      common_field = models.CharField(...)
      
     @classmethod
        def __init_subclass__(cls, **kwargs):
            super().__init_subclass__(**kwargs)
            # automatically bind the pre_save for the sub model
            pre_save.connect(generate_common_field, cls)
    
    
   def generate_common_field:
     pass

Class SubModel(BaseModel):
    pass

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-07
    • 2011-12-09
    • 1970-01-01
    • 2015-03-05
    相关资源
    最近更新 更多