如何解决如何在Django中为计数注释实现交叉连接
我提供了我的问题的简化版本。我有场地和时间段以及用户和预订,如下面的模型描述所示。时隙在所有场所都是通用的,用户可以在该场所预订时隙,直到达到场所容量为止。
class Venue(models.Model):
name = models.Charfield(max_length=200)
capacity = models.PositiveIntegerField(default=0)
class TimeSlot(models.Model):
start_time = models.TimeField()
end_time = models.TimeField()
class Booking(models.Model):
user = models.ForeignKey(User)
time_slot = models.ForeignKey(TimeSlot)
venue = models.ForeignKey(Venue)
现在,我想尽可能高效地获取“场地”和“时间段”的所有可能组合,并注释每种组合的预定数量,包括预定数量为0的情况。
我已经通过在Venue和TimeSlot表上使用交叉联接设法在原始SQL中实现了这一目标。有以下效果。但是,尽管进行了详尽的搜索,仍无法找到django的等效项。
SELECT venue.name,timeslot.start_time,timeslot.end_time,count(booking.id)
FROM myapp_venue as venue
CROSS JOIN myapp_timeslot as timeslot
LEFT JOIN myapp_booking as booking on booking.time_slot_id = timeslot.id
GROUP BY venue.name,timeslot.end_time
我还可以为查询添加注释,以检索组合确实存在的预订数量。但是那些预订为0的组合被排除在外。示例:
qs = Booking.objects.all().values(
venue=F('venue__name'),start_time=F('time_slot__start_time'),end_time=F('time_slot__end_time')
).annotate(bookings=Count('id')) \
.order_by('venue','start_time','end_time')
如何使用django ORM达到CROSS JOIN查询的效果?
解决方法
我不认为Django有能力进行交叉联接而不还原为原始SQL。我可以给您提供两个思路,尽管它们可以为您指明正确的方向:
-
查询和python循环的组合。
venues = Venue.objects.all() time_slots = TimeSlot.objects.all() qs = ** your customer query above ** # Loop through both querysets,to create a master list. venue_time_slots = [] for venue in venues: for time_slot in time_slots: venue_time_slots.append(venue.name,time_slot.start_time,time_slot.end_time,0) # Loop through master list and then compare to custom qs to update the count. for venue_time in venue_time_slots: for vt in qs: # Check if venue and time found. if venue_time[0] == qs.venue and venue_time[1] == qs.start_time: venue_time[3] += qs.bookings break
-
我没有解决方案的最困难的一个是使用filter,exclude和union的组合。我只用了3个表(两个父表带有一个子链接表),其中有4个表(包括用户)。因此,我只能提供逻辑,而不能提供示例。
# Get all results that exist in table using .filter(). first_query.filter() # Get all results that do not exist by using .exclude(). # You can use your results from the first query to exclude also,but # would need to create an interim list. exclude_ids = [fq_row.id for fq_row in first_query] second_query.exclude(id__in=exclude_ids) # Combine both queries query = first_query.union(second_query) return query
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。