设置学生入学制度。 对于学生和课程,我们有N:M关系命名为attandance。 还有一个具有抵抗状态的模型(存在,缺席,合理,......)。
level( id, name, ... )
student ( id, name, ..., id_level )
course( id, name, ... )
status ( id, name, ...) #present, absemt, justified, ...
attandance( id, id_student, id_course, id_status, date, hour )
unique_together = ((id_student, id_course, id_status, date, hour),)
我正在查找按%排序的水平> 20%缺席的学生列表。类似的东西:
present = status.objects.get( name = 'present')
justified = status.objects.get( name = 'justified')
absent = status.objects.get( name = 'absent')
#here the question. How to do this:
Student.objects.filter( level = level ).annotate(
nPresent =count( attandence where status is present or justified ),
nAbsent =count( attandence where status is absent ),
pct = nAbsent / (nAbsent + nPresent ),
).filter( pct__gte = 20 ).order_by( "-pct" )
如果无法使用查询API进行查询,则任何解决方法(列表,集合,词典,...)都会很好用!
谢谢!
----此时我手写了一个脏的原始sql --------------------------
select
a.id_alumne,
coalesce ( count( p.id_control_assistencia ), 0 ) as p,
coalesce ( count( j.id_control_assistencia ), 0 ) as j,
coalesce ( count( f.id_control_assistencia ), 0 ) as f,
1.0 * coalesce ( count( f.id_control_assistencia ), 0 ) /
( coalesce ( count( p.id_control_assistencia ), 0 ) + coalesce ( count( f.id_control_assistencia ), 0 ) ) as tpc
from
alumne a
inner join
grup g
on (g.id_grup = a.id_grup )
inner join
curs c
on (c.id_curs = g.id_curs)
inner join
nivell n
on (n.id_nivell = c.id_nivell)
inner join
control_assistencia ca
on (ca.id_estat is not null and
ca.id_alumne = a.id_alumne )
inner join
impartir i
on ( i.id_impartir = ca.id_impartir )
left outer join
control_assistencia p
on (
p.id_estat in ( select id_estat from estat_control_assistencia where codi_estat in ('P','R' ) ) and
p.id_control_assistencia = ca.id_control_assistencia )
left outer join
control_assistencia j
on (
j.id_estat = ( select id_estat from estat_control_assistencia where codi_estat = 'J' ) and
j.id_control_assistencia = ca.id_control_assistencia )
left outer join
control_assistencia f
on (
f.id_estat = ( select id_estat from estat_control_assistencia where codi_estat = 'F' ) and
f.id_control_assistencia = ca.id_control_assistencia )
where
n.id_nivell = {0} and
i.dia_impartir >= '{1}' and
i.dia_impartir <= '{2}'
group by
a.id_alumne
having
1.0 * coalesce ( count( f.id_control_assistencia ), 0 ) /
( coalesce ( count( p.id_control_assistencia ), 0 ) + coalesce ( count( f.id_control_assistencia ), 0 ) )
> ( 1.0 * {3} / 100)
order by
1.0 * coalesce ( count( f.id_control_assistencia ), 0 ) /
( coalesce ( count( p.id_control_assistencia ), 0 ) + coalesce ( count( f.id_control_assistencia ), 0 ) )
desc
'''.format( nivell.pk, data_inici, data_fi, tpc )
答案 0 :(得分:2)
如果您不关心它是否在事后使用查询api或python,请使用itertools.groupby。
attendances = Attendance.objects.select_related().filter(student__level__exact=level)
students = []
for s, g in groupby(attendances, key=lambda a: a.student.id):
g = list(g) # g is an iterator
present = len([a for a in g if a.status == 'present'])
absent = len([a for a in g if a.status == 'absent'])
justified = len([a for a in g if a.status == 'justified'])
total = len(g)
percent = int(absent / total)
students.append(dict(name=s.name, present=present, absent=absent, percent=percent))
students = (s for s in sorted(students, key=lambda x: x['percent']) if s['percent'] > 25)
您可以将生成的dicts列表传递给视图,方法与任何其他查询集相同。