首页 > 解决方案 > Django 发出跟随/取消关注的信号

问题描述

我有一个看起来像这样的信号:

@receiver([post_save, post_delete], sender=Following)
def increment_follow_count(instance, created=False, **kwargs):
    if created:
        instance.follower.following_count += 1
        instance.target.follower_count += 1
    else:
        instance.follower.following_count -= 1
        instance.target.follower_count -= 1

当一个用户关注另一个用户时,它可以正常工作。但是,当同一用户取消关注该用户时,只有该用户关注的人(目标)的关注者计数减少,但用户的关注计数不减少。为什么会发生这种行为,我该如何解决?

模型:

class Following(models.Model):
    target = models.ForeignKey('User', related_name='followers', on_delete=models.CASCADE, null=True)
    follower = models.ForeignKey('User', related_name='targets', on_delete=models.CASCADE, null=True)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return '{} is followed by {}'.format(self.target, self.follower)

关注/取消关注用户的代码

def follow_unfollow(follower, target):
    # Query to see if the following exists or not
    following = target.followers.filter(follower=follower)

    if following.exists():
        following.delete()
    else:
        target.followers.create(follower=follower)

    target.save()
    follower.save()

标签: pythondjangodjango-modelsdjango-signals

解决方案


increment_follow_count信号包含增量逻辑但没有保存逻辑并且保存完成是另一种follow_unfollow方法吗?


首先,增量最好是原子的,以确保不会丢失任何更改。

使用F() 表达式可以实现原子增量。

from django.db.models import F

@receiver([post_save, post_delete], sender=Following)
def increment_follow_count(instance, created=False, **kwargs):
    if created:
        User.objects.filter(
            pk=instance.follower_id
        ).update(
            following_count=F('following_count') + 1
        )
        User.objects.filter(
            pk=instance.target_id
        ).update(
            following_count=F('following_count') + 1
        )
    else:
        User.objects.filter(
            pk=instance.follower_id
        ).update(
            following_count=F('following_count') - 1
        )
        User.objects.filter(
            pk=instance.target_id
        ).update(
            following_count=F('following_count') - 1
        )

这里的增量不仅是原子的,而且更改会立即以相同的方法保存在数据库中。

另外,我建议删除target.save()follower.save()infollow_unfollow - 因为它用内存中的值覆盖数据库中的实例,这不应该是这种情况,至少following_count因为它的增量逻辑是信号。如果在follow_unfollow方法中对字段进行了一些更改,而不是followng_count完成 - 那么save()应该使用update_fieldslist调用以仅更新更改的字段。


+= 1则取当前内存中的实例字段值,即count=5增量(count=6),稍后,当调用保存时,它被保存为更新count=6。并且在此期间,数据库中的值可能已经多次更改(并且无论如何 update 会将其设置为 6),尤其是在负载/同时操作下。

使用原子增量逻辑从 python 移动到数据库 - 并将在进行事务时增加实际值。


推荐阅读