排除Django应用程序中被阻止用户提出的问题的最有效方法

时间:2014-01-04 01:27:36

标签: django django-models

我有一个Q& A应用程序,允许用户阻止/隐藏他们觉得烦人或冒犯的其他用户。当current_user查看所有问题时 - Question.objects.all() - 我想从查询集中排除被current_user阻止的用户提出的所有问题 - Block.objects.filter(user_is_blocking = current_user)

最有效的方法是什么?如果它对您的答案产生影响,我会将相同的排除列表应用于其他模型,例如Answers,其中还包括User作为FK。

型号:

class Question(models.Model):
    user = models.ForeignKey(User)  
    question = models.CharField()

class Block(models.Model):
    user_is_blocking = models.ForeignKey(User, related_name="user_blocking")
    user_is_blocked = models.ForeignKey(User, related_name="user_blocked")

更新: 由于sk1p,我得到了这个工作。然后我想要排除双向 - 所以我只看到我没有阻止的用户的问题和没有阻止我的人。对于那些对组合子查询感兴趣的人,我这样做了如下:

from itertools import chain

i_am_blocking = User.objects.filter(user_blocked__user_is_blocking=request.user)
is_blocking_me = User.objects.filter(user_blocking__user_is_blocked=request.user) 
blocked_users = list(chain(i_am_blocking, is_blocking_me))

questions = Question.objects.exclude(user__in=blocked_users)
...

1 个答案:

答案 0 :(得分:2)

您可以使用__in字段查找:

class Question(models.Model):
    user = models.ForeignKey(User)  
    question = models.CharField()

class Block(models.Model):
    user_blocking = models.ForeignKey(User, related_name="blocks_set")
    user_blocked = models.ForeignKey(User, related_name="blocks_received")

blocked_users = User.objects.filter(blocks_received__user_blocking=current_user)
questions = Question.objects.exclude(user__in=blocked_users)

(我冒昧地重命名你的相关名字和字段,以便更好地理解问题,你当然不必更改你的名字......)

__in查找将被转换为子查询,因此数据库将完成大部分工作。

实际性能取决于您的数据库。关于MySQL的错误优化的Django文档warns,特别是,我建议对生产数据库的副本运行生成的查询,并查看EXPLAIN或{的查询计划{1}}(在PostgreSQL上)。

如果基于子查询的方法与数据库不兼容,则可以将其重写为原始SQL查询并比较性能:

EXPLAIN ANALYZE

Proof-of-concept SQLFiddle

想法是将阻止表加入问题的作者,如果存在,则丢弃问题。 SELECT q.* FROM app_question q, auth_user author LEFT JOIN app_block b ON (b.user_blocked_id = author.id) LEFT JOIN auth_user ON (b.user_blocking_id = auth_user.id AND auth_user.id = %s) WHERE author.id = q.user_id AND auth_user.id IS NULL; 是当前用户id的参数;一定要not use string formatting!