首页 > 解决方案 > 连接到 pre_delete 信号后未调用 Django 信号接收器

问题描述

目标

我正在尝试实现一个投票系统来跟踪用户何时对数据库中的特定对象进行投票。我正在使用一个中间UserVote模型来跟踪这一点,该模型具有实际包含所有投票的对象的外键。每当UserVote被删除时,我想删除对相关对象的投票。

我试过的

由于批量删除不调用model.delete()方法pre_delete,我想通过监听信号来完成上述操作。

当我使用 Django 测试运行器测试以下接收器功能时,一切都按预期运行

from myapp.models.users import UserVote
from django.db.models.signals import pre_delete
from django.dispatch import receiver


@receiver(pre_delete)
def user_vote_handler(sender, instance, **kwargs):
    if sender in UserVote.__subclasses__():
        # remove the vote from the related model

问题

当我delete()在views.py 中调用模型实例时,不会调用该函数。如果我如下向接收器函数添加打印语句,则不会打印任何语句。

from myapp.models.users import UserVote
from django.db.models.signals import pre_delete
from django.dispatch import receiver


@receiver(pre_delete)
def user_vote_handler(sender, instance, **kwargs):
    print('function called')
    if sender in UserVote.__subclasses__():
        print('condition met')
        # remove the vote from the related model

我已经阅读了Signal Documention,但没有找到问题的根源。我已经将接收器功能放入myapp.signals和放入myapp.models.users,并且行为是相同的。我有一种感觉,我做了一些愚蠢的事情,却没有意识到。任何人都可以阐明可能出了什么问题吗?我正在使用 Django 2.2。

代码

# models.records.py
...


class Record(models.Model):
    ...
    # some functions for all Record subclasses
    ....


class Author(Record):
    name = models.CharField(max_length=255)
    comments = models.ManyToManyField(
        Comment,
        through='ForumComment',
        through_fields=('author', 'comment'),
    )
    ...
    # some functions specific to this
    ....

...
# more records
...
# models.comments.py
...


class RecordComment(models.Mode):
    text = label = models.CharField(max_length=255)
    ...
    # some methods
    ...


class AuthorComment(RecordComment):
    ...
    # methods specific to AuthorComment
    ...

...
# more RecordComment subclass
...


class Comment(models.Model):
    class Meta:
        abstract = True

    up_votes = models.PositiveIntegerField(blank=True, default=0)
    down_votes = models.PositiveIntegerField(blank=True, default=0)


class ForumComment(Comment):
    author = models.ForeignKey('myapp.Author', on_delete=models.CASCADE, verbose_name='related record')
    comment = models.ForeignKey(AuthorComment, on_delete=models.CASCADE)
...
# more types of comments
...
# models.users.py
...


class User(AbstractUser):
    pass


class UserVote(models.Model):
    """shared fields and functions for UserVote models"""
    class Meta:
        abstract = True

    DOWN_VOTE = 'DOWN'
    UP_VOTE = 'UP'
    VOTE_CHOICES = [
        (DOWN_VOTE, 'Down vote'),
        (UP_VOTE, 'Up vote'),
    ]
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    vote = models.CharField(choices=VOTE_CHOICES, default=UP_VOTE, max_length=255)
    ...
    # methods to handle voting
    ...


class ForumCommentUserVote(UserVote):
    forum_comment = models.ForeignKey('myapp.ForumComment', on_delete=models.CASCADE)

        class Meta:
        constraints = [
            models.UniqueConstraint(fields=['forum_comment', 'user'], name='unique_author_tag_assignment_user_vote')
        ]
    ...
    # some more methods
    ...
...
# more UserVote subclasses
...

标签: pythondjangosignals

解决方案


在您的应用程序 app.py 文件中为信号添加导入,它应该如下所示

class UsersConfig(AppConfig):
    name = 'users'

    def ready(self):
        import users.signals

在 settings.py 你应该像这样添加你的应用程序

'users.apps.UsersConfig',

这应该会触发 pre_delete 信号,:D 我花了一整天的时间以为我做错了什么,而实际上我只是忘记了这两个大声笑


推荐阅读