是否可以对预取查询进行注释/计数?
我在下面的初步查询是基于电路的,然后我意识到,如果一个站点没有任何电路,我就不会有“无”类别,这会将站点显示为Down。
conn_data = Circuits.objects.all() \
.values('circuit_type__circuit_type') \
.exclude(active_link=False) \
.annotate(total=Count('circuit_type__circuit_type')) \
.order_by('circuit_type__monitor_priority')
所以我改为查询网站并使用预取,现在对于没有活动链接的任何网站,它都有一个空的circuits_set。是否有一种Django方法可以在conn_data中针对各种loops_set创建新的总数?我打算手动遍历所有站点并以这种方式添加总计,但想知道是否有办法在QuerySet中执行此操作?
我的最终结果应该是:
[
{'circuit_type__circuit_type': 'Fibre', 'total': 63},
{'circuit_type__circuit_type': 'DSL', 'total': 29},
{'circuit_type__circuit_type': 'None', 'total': 2}
]
预取查询:
conn_data = SiteData.objects.prefetch_related(
Prefetch(
'circuits_set',
queryset=Circuits.objects.exclude(active_link=False).select_related('circuit_type'),
)
)
答案 0 :(得分:0)
我不认为这会奏效。它是否应该起作用值得商榷。我们来看prefetch_related
做什么。
返回一个QuerySet,它将在一个批处理中自动检索每个指定查找的相关对象。
所以这里发生的是调度两个查询并实现两个列表。然后将这些列表分区在内存中并分组到正确的父记录中。
Count()
和annotate()
是解析为SQL
Select Count(id) from conn_data
由于annotate
和prefetch_related
的工作方式,我认为它们不太可能在一起发挥出色。 prefetch_related
只是方便。从实际角度来看,运行两个单独的ORM查询并将它们自己分配给SiteData
记录实际上是同样的事情。所以......就像......
#Gets all Circuits counted and grouped by SiteData
Circuits.objects.values('sitedata_id)'.exclude(active_link=False).select_related('circuit_type').annotate(Count('site_data_id'));
然后,您只需遍历SiteData
条记录并指定计数。
答案 1 :(得分:0)
好的,我得到了我想要的东西,可能是一个更好的方法,但它的工作从未如此:
from collections import Counter
import operator
class ConnData(object):
def __init__(self, priority='', c_type='', count=0 ):
self.priority = priority
self.c_type = c_type
self.count = count
def __repr__(self):
return '{} {}'.format(self.__class__.__name__, self.c_type)
# get all the site data
conn_data = SiteData.objects.exclude(Q(site_type__site_type='Data Centre') | Q(site_type__site_type='Factory')) \
.prefetch_related(
Prefetch(
'circuits_set',
queryset=Circuits.objects.exclude(active_link=False).select_related('circuit_type'),
)
)
# create a list for the conns
conns = []
# add items to list of dictionaries with all required fields
for conn in conn_data:
try:
conn_type = conn.circuits_set.all()[0].circuit_type.circuit_type
prioritiy = conn.circuits_set.all()[0].circuit_type.monitor_priority
conns.append({'circuit_type' : conn_type, 'priority' : prioritiy})
except:
# create category for down sites
conns.append({'circuit_type' : 'Down', 'priority' : 10})
# crate new list for class data
conn_counts = []
# create counter data
conn_count_data = Counter(((d['circuit_type'], d['priority']) for d in conns))
# loop through counter data and add classes to list
for val, count in conn_count_data.items():
cc = ConnData()
cc.priority = val[1]
cc.c_type = val[0]
cc.count = count
conn_counts.append(cc)
# sort the classes by priority
conn_counts = sorted(conn_counts, key=operator.attrgetter('priority'))