挣扎,似乎应该是一个简单的问题......
从本质上讲,我有一些网站在几年内发生了物体计数:
例:
site_id = Site1: (Year:2012,Count:133), (Year:2011, Count:150), (Year:2010, Count :110)
site_id = Site2: (Year:2010, Count:300), (Year:2010, Count 333)
数据在时间上是不连贯的(不是常规的 - 有些网站被计算了几年......其他网站没有......(..此外,有时这些地方每年被计算几次
我想做的是获取每个站点的最新计数,如果有多个计数,我想获得最高计数。然后我想在HTML中显示它。
这是我的模型。.PY
class Counts(models.Model):
count_id = models.AutoField(primary_key=True)
site = models.ForeignKey('Site', blank=True, null=True)
year = models.IntegerField(blank=True, null=True)
count = models.FloatField(blank=True, null=True)
class Meta:
db_table = 'counts'
class Site(models.Model):
site_id = models.TextField(primary_key=True)
site_code = models.TextField(blank=True, null=True)
site_name = models.TextField(blank=True, null=True)
class Meta:
db_table = 'site'
这是我尝试在视图中使用的查询。.PY
p = ['Site1','Site2'] ## Just for reference for the example... values come from a POST or a GET
A = Site.objects.filter(site_id__in = p).annotate(latest=Max('counts__year'))
context = RequestContext(request, {'dat':A})
template = loader.get_template('styles/searchResults.html')
return HttpResponse(template.render(context))
以上只给了我最近几年:
[{'site_id': u'Site1','latest': 2012}, {'site_id': u'Site2','latest': 2010}]
我想要的是:
[{'site_id': u'Site1','latest': 2012,'count':133}, {'site_id': u'Site2','latest': 2010,'count':333}]
但是 - 我希望它作为查询集(而不是 ValuesQuerySet(,因为我想在我的 HTML 模板中引用它,如下所示:
<table>
{% for x in dat %}
<tr><td>{{x.count|floatformat}}</td><td>{{x.year}}</tr>
{%endfor%}
</table>
我已经尝试了以下内容(从上面创建 A 后(: B = Counts.objects.filter(year__in = A.values('latest'(,site__site_id__in = p(.annotate(site_code=Max('site__site_id'((
但这基本上导致:
[{'site_id': u'Site1','latest': 2012,'count':133},{'site_id': u'Site1','latest': 2010,'count':110}, {'site_id': u'Site2','latest': 2010,'count':333},{'site_id': u'Site2','latest': 2010,'count':300}]
换句话说,它正在提取两个站点的 YEAR = 2010 或 2012 的所有值。
同样,我正在寻找的是最新year. Max(count), Max(year)
的最高计数 - 我敢肯定以某种方式发挥作用......
谢谢!
按年份和计数排序并使用 .distinct(( 只获取每个站点的第一条记录怎么样?
A = Counts.objects.filter(site_id__in = p).order_by('site_id','-year','-count').distinct('site_id')
如果您需要相应的站点信息,可以在模板中访问
<table>
{% for x in dat %}
<tr><td>{{x.count|floatformat}}</td><td>{{x.year}}</td><td>{{x.site.site_name}}</td></tr>
{%endfor%}
</table>
或者使用 .values(( 指定视图中每个模型所需的值。结果也可以在模板中迭代。
已编辑:
虽然下面的答案对我有用,但我担心性能......所以我根据 user5219763 重新散列 - 现在更干净了......
我捣鼓了一下,发现这很有效...
from itertools import chain
### First create an empty list to push querysets
qlist = []
### Iterate through each selected ID
for x in p:
### Find the value for the latest year for each site id selected
A = Site.objects.filter(site_id = x).aggregate(Max('counts__year'))['counts__year__max']
if A:
### Find value of the highest count for year identified above for the selected site
B = Counts.objects.filter(year = A, site__site_id=x).aggregate(Max('count'))['count__max']
### Now, resample the Site where the year is the max and count is max, then annotate the queryset
### with the values from year and count in the Counts table...
C = Site.objects.filter(counts__year=A,counts__count=B).annotate(year = Max('counts__year'), count = Max('counts__count'))
### push this query to the list
qlist.append(C)
else:
continue
### use itertools chain command to merge these into a single queryset
qs = list(chain.from_iterable(qlist))
现在我正在使用:
qs = Counts.objects.filter(site__site_id__in = p).order_by('site__site_id','-year','-count').distinct('site__site_id').select_related()
然后,在我的 HTML 中,我像这样引用它:
{% for x in dat %}
<tr ><td>{{ x.site.site_name }}</td><td>{{x.site.site_code}}</td><td>{{x.count|floatformat}}</td><td>{{x.year}}</td></tr>
{% endfor %}
谢谢,伙计们!
QuerySet
和ValuesQuerySet
有两种解决方案。
1. 查询集
不建议用于大型Site
表和Counts
表,因为性能 - 对于每个站点,您将获得一个额外的查询来获取最新的Counts
对象(复杂性O(N*M)
(。但是,如果行数很少,那也没关系。例如:
视图
A = Site.objects.filter(site_id__in=p).annotate(latest=Max('counts_set__year'))
# Fetch latest Counts for each Site object
for site in A:
site.counts_latest = site.counts_set.order_by('-year').first()
模板
<table>
{% for x in dat %}
<tr>
<td>{{x.counts_latest.count|floatformat}}</td>
<td>{{x.counts_latest.year}}</td>
</tr>
{%endfor%}
</table>
就这样!
2. 值查询集
您应该放入所有Counts
字段的列表values
这些字段可以在模板中使用。例如:
视图
A = Site.objects.values('counts_set__count', 'counts_set__year')
.filter(site_id__in=p).annotate(latest=Max('counts_set__year'))
模板
<table>
{% for x in dat %}
<tr>
<td>{{x.counts_set__count|floatformat}}</td>
<td>{{x.counts_set__year}}</td>
</tr>
{%endfor%}
</table>
希望这有帮助!