我有以下模特:
class SchoolClass(models.Model):
title = models.CharField()
max_students = models.IntegerField(default=10)
is_published = models.BooleanField(default=False)
class Session(models.Model):
school_class = models.ForeignKey(SchoolClass, related_name="sessions")
start_date = models.DateField()
enrolled_students = models.IntegerField()
一个SchoolClass可以有多个Sessions(例如,周一,周二和周五的“Dummies数学”= 3个会话)。
在我的索引页面(ListView)上,我想只显示所有即将开始的类(至少有一个会话),因为有很多会话的类会使概述变得混乱。
如何创建会话对象列表(我可以通过session.school_class获取相关课程信息),符合以下要求:
start_date__gte=datetime.now().date()
school_class.is_published=True
oder_by('start_date')[0]
)谢谢!
PS:我正在运行MySQL作为数据库,因此不同的('field')将不起作用..
修改
以下是我当前的解决方案,它可以工作,但不是很干净(DB上的冗余命中)
def get_sessions_mixin(filter_args):
session_qs = []
qs = SchoolClass.objects.filter(**filter_args)
for schoolclass in qs:
session_qs.append(schoolclass.get_first_session())
#session_qs = Session.objects.filter(course_meta__is_deleted=False, date_from__gte=datetime.now().date()).\
# annotate(Max('date_from'))
#session_qs = qs.order_by('get_first_session__date_from')
return session_qs
和models.py
内class Sessions(models.Model):
# ...
def get_first_session(self):
if self.is_published:
tmp_sessions = self.sessions.filter(date_from__gte=datetime.now().date())
if tmp_sessions:
return tmp_sessions.order_by('date_from')[0]
return None
答案 0 :(得分:1)
我无法想到在单个Django ORM查询中执行所需操作的方法。我可能会做的是,首先,获取所有相关的Session
对象:
sessions = Session.objects.filter(school_class__is_published=True,
start_date__gte=datetime.now().date())
.select_related('school_class')
.order_by('start_date')
您现在可以从单个查询中获得所需的一切,包括相关的SchoolClass
数据。您只需要在Python中做一些工作来过滤数据。有很多方法可以做到这一点,这里有一个简单的方法:
first_sessions = collections.OrderedDict()
for session in sessions:
if session.school_class.pk not in first_sessions:
first_sessions[session.school_class.pk] = session
现在first_sessions.values()
有你想要的。您可以将其包装在自定义Manager
上的方法中。
在涉及数据库时很难对性能进行猜测(特别是不知道典型Sessions
有多少SchoolClass
),但我怀疑这种单一查询方法会更快更简单而不是你当前的解决方案,它会多次击中数据库。
答案 1 :(得分:0)
似乎这种查询可能有效:
SchoolClass.objects.filter(sessions__start_date__gte=datetime.now().date(), is_published=True)\
.annotate(session_count=Count('sessions'))\
.filter(session_count__gte=1)
但我不确定第三点是什么意思。