4

我正在尝试以最有效的方式在 Django 中进行非常复杂的查询,但我不知道如何开始。我有这些模型(这是简化版)

class Status(models.Model):
    status = models.CharField(max_length=200)

class User(models.Model):
    name = models.CharField(max_length=200)

class Event(models.Model):
    user = models.ForeignKey(User)

class EventItem(models.Model):
    event = models.ForeignKey(Event)
    rev1 = models.ForeignKey(Status, related_name='rev1', blank=True, null=True)
    rev2 = models.ForeignKey(Status, related_name='rev2', blank=True, null=True)
    active = models.BooleanField()

我想创建一个查询,该查询将生成具有最多事件的用户列表,其中所有依赖的 EventItems 都具有rev1并且rev2不是空白或 nulland active = True

我知道我可以通过遍历用户列表然后检查他们的所有事件是否匹配rev1,rev2active条件然后返回这些事件来做到这一点,但这对数据库来说很重。有什么建议么?

谢谢!

4

3 回答 3

6

您的模型已损坏,但这应该以更简洁的方式总结您所做的事情。

class Status(models.Model):
    status = models.CharField(max_length=200)

class User(models.Model):
    name = models.CharField(max_length=200)
    events = models.ManyToManyField('Event')

class Event(models.Model):
    rev1 = models.ForeignKey(Status, related_name='rev1', blank=True, null=True)
    rev2 = models.ForeignKey(Status, related_name='rev2', blank=True, null=True)
    active = models.BooleanField()

和查询

User.objects.filter(events__active=True).exclude(Q(events__rev1=None)|Q(events__rev2=None)).annotate(num_events=Count('events')).order_by('-num_events')

这将返回一个用户列表,按其集合中的事件数排序。

有关更多信息,请查看多对多字段。

于 2013-02-27T06:29:30.947 回答
3

我想创建一个查询,该查询将生成具有最多事件的用户列表,其中所有相关的 EventItems 都具有 rev1 和 rev2 不是空白或 null 并且活动 = True。

首先,您需要Event始终具有这种类型的对象EventItem

events = Event.objects.filter(active=True)
events = events.exclude(eventitem__rev1__isnull=True)
events = events.exclude(eventitem__rev1='')
events = events.exclude(eventitem__rev2__isnull=True)
events = events.exclude(eventitem__rev2='')

此外,您没有指定是否要处理Event没有EventItem. 您可以使用以下方法过滤掉它们:

events = events.exclude(eventitem__isnull=True)

请注意,events可能包含大量重复项。如果你愿意,你可以抛出一个events.distinct(),但只有在你需要它可读时才应该这样做。

一旦你有了这些,你现在可以提取User你想要的对象:

users = User.objects.filter(event__in=events)

请注意,在某些数据库后端 *ahem* MySQL *ahem* 上,您可能会发现该.filter(field__in=QuerySet)模式非常缓慢。对于这种情况,代码应该是:

users = User.objects.filter(event__in=list(events.values_list('pk', flat=True)))

Event然后,您可以按附加对象的数量对事物进行排序:

from django.db.models import Count
active_users = users.annotate(num_events=Count('event')).order_by('-num_events')
于 2013-02-28T01:48:08.177 回答
0

您可以尝试以下方法:

EventItem.objects.exclude(rev1=None).exclude(rev2=None).filter(active=True).values_list('event__user', flat=True)

这将为您提供用户 id 的平面列表,其中每个 id 的频率是用户拥有多少 EventItem 对象。

您可能可以做得更好,并使用 将其集成到查询中.annotate(),但我现在不知道该怎么做。

于 2013-02-27T06:41:42.147 回答