返回跨越多个表的结果的最有效的Django查询

2024-04-19 21:08:50 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图以最有效的方式在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()

我想创建一个查询,该查询将生成一个用户列表,其中用户拥有的事件最多,其中所有相关事件项的rev1和{}不为空或为null且active = True。在

我知道我可以通过迭代用户列表,然后检查他们的所有事件是否符合匹配的rev1rev2和{}条件,然后返回这些事件,但这对数据库来说很繁重。有什么建议吗?在

谢谢!在


Tags: 用户nametruemodelmodelsstatus事件null
3条回答

你的模型是坏的,但这应该以一种更清晰的方式总结你所做的。在

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')

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

有关详细信息,请查看Many-To-Many字段。在

你可以尝试一下:

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

这将给您一个简单的用户id列表,其中每个id的频率是用户拥有的EventItem对象的数量。在

您可能可以做得更好,并使用.annotate()将其集成到查询中,但我现在不确定如何进行。在

I want to create a query that will result in a list of Users that have the most events in which all their dependent EventItems have rev1 and rev2 are not blank or null and active = 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='')

另外,您没有指定是否要处理没有EventItemEvent对象。你可以用以下方法过滤掉:

^{pr2}$

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

一旦有了这些,现在就可以提取所需的User对象:

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

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

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')

相关问题 更多 >