【问题标题】:Formulating an efficient DB query with highly challenging requirements (Django app)制定具有高度挑战性要求的高效数据库查询(Django 应用程序)
【发布时间】:2015-11-08 07:15:47
【问题描述】:

这是一个艰难的过程。我有一个基于 django 的网络应用程序,用户可以在其中发布有趣的 URL,并让观众在每个帖子下发表评论。此外,我使用stealth banning 来对付行为不端的用户。

有趣的 URL 由Link 模型表示;帖子下的cmets由Publicreply模特代表。

以下是这些模型相互关联的方式:

class Link(models.Model): 
    submitter = models.ForeignKey(User)
    submitted_on = models.DateTimeField(auto_now_add=True)
    url = models.URLField(max_length=250)

class Publicreply(models.Model):
    submitted_by = models.ForeignKey(User)
    answer_to = models.ForeignKey(Link)
    submitted_on = models.DateTimeField(auto_now_add=True)
    description = models.TextField(validators=[MaxLengthValidator(250)])

Users我禁止去这里:

class HellBanList(models.Model):
    condemned = models.ForeignKey(User)
    when = models.DateTimeField(auto_now_add=True)

我的问题是什么?我正在尝试编写表现最好的优化的查询,让我:

1. 具有绝对最新时间戳publicreply 来自所有不同的links 用户自己发布的,或者所述用户在其下方留下了一个publicreply

2. 但是如果 1 中的 publicreply 对象属于 HellBanList 的一部分(即被谴责的属性),我想忽略那个特定的 publicreply 并挖掘下一个最近的。如果这也是被禁止的用户,我会跳到下一个(依此类推)。

3. 最后,我只需要来自publicreply 对象的submitted_bysubmitted_on 属性值,在满足1 和2 之后我最终得到。


那么到目前为止我尝试了什么?这个:

freshest_link = Link.objects.filter(Q(submitter=self.request.user)|Q(publicreply__submitted_by=self.request.user)).distinct().annotate(date=Max('publicreply__submitted_on')).latest('date')
freshest_reply = Publicreply.objects.filter(answer_to=freshest_link).latest('submitted_by')

这段代码有什么问题?它不满足要求 2 的事实。我想我应该以某种方式在 publicreplys 上运行 exclude() usersHellBanList 之前计算 freshest_reply (为了满足要求 2)。无论如何,我不知道该怎么做。其次,专家可能比我尝试的方式更有效地构建整个查询,目标是尽可能减少数据库往返。

你能帮忙吗?如果你觉得我对我想要达到的目标的描述不透明,请要求澄清。

注意:我的数据库是 postgres

【问题讨论】:

    标签: python django performance postgresql query-optimization


    【解决方案1】:

    获取被禁止的用户列表,如:

    banlist = HellBanList.objects.values_list('condemned',flat=True)
    

    修改freshest_reply查询,如:

    freshest_reply = Publicreply.objects.filter(answer_to=freshest_link).exclude(submitted_by_id__in=banlist).latest('submitted_on')
    

    第二种方法:

    在您的查询中,首先您会获得具有最新公开回复的Link,然后在下一个查询中您会获得该Link 的最新Publicreply。取而代之的是,我们可以在一个查询中获得最新的回复,例如:

    latest_reply = Publicreply.objects.filter(Q(answer_to__submitter=self.request.user)|Q(submitted_by=self.request.user)).exclude(submitted_by_id__in=banlist).latest('submitted_on')
    

    如果我错过了什么,请告诉我。

    【讨论】:

    • 太好了,阿努什!第二种方法的配置文件非常好(我又添加了一个 exclude() - 用于 self.request.user - 但那不在 reqs 中,所以不用担心)。谢谢你插话的朋友。我还有你的另一个回复,我还没有测试和接受。很快!
    猜你喜欢
    • 2016-02-17
    • 1970-01-01
    • 1970-01-01
    • 2013-07-18
    • 2013-04-16
    • 1970-01-01
    • 1970-01-01
    • 2011-09-19
    • 2013-01-23
    相关资源
    最近更新 更多