2012-02-03 73 views
0

我正在创建一个应用程序,人们可以在其中为城市发布帖子。我想为国家/地区创建一个视图,该视图将显示有海报的城市列表以及每个城市已经制作了多少张海报。Django查询和分组

我有一个国家表和一个国家的外键的城市表。我也有一个海报表,带有城市表的外键。

这成功地给了我一张海报清单,但是如何将它们分组为城市并通过?在该模板中,我希望能够显示该城市的城市名称,海报图片以及该城市的海报总数,为该国海报制作的每个城市。

def country_page(request, country_name): 
    country = get_object_or_404(Country, name__iexact=country_name)  
    posters = Poster.objects.filter(city__country=country)   
    variables = RequestContext(request, { 
     'location' : country, 
     'posters' : posters, 
    }) 
    return render_to_response('country_page.html', variables) 

任何帮助,将不胜感激。

回答

0

你在找什么是在sql land中的'group by'。

下面的线程有一些有趣的见解,底线是你需要原始SQL做一个真正的团体,但我怀疑你的需求,你可以做一个小的后处理做分组:

posters = Poster.objects.filter(city__country=country) 
poster_cities = {} 
for poster in posters: 
    if city not in poster_cities: 
     poster_cities[city] = [] 
    poster_cities[city].append(poster) 

现在你可以通过城市获得海报这样从模板中使用:

for city in sorted(poster_cities.keys()): 
    city_posters = poster_cities[city] 
    city_poster_count = len(poster_cities[city]) 

背景:

How to query as GROUP BY in django?

0

在原始的sql中,你应该使用“group by”等来完成它,但对于django,你应该查看模型的聚合函数。

https://docs.djangoproject.com/en/dev/topics/db/aggregation/

我遇到了类似的问题,前几天,这我是如何解决它。您首先从特定条件过滤对象,然后指定所需的字段,最后进行计数,以了解总行数。

您的解决方案可能看起来类似的东西:

posters = Poster.objects.filter(city__country=country).values('city_name','poster_image',..).annotate(total=Count('city')) 
+0

难道你不应该从城市计数吗? – Raekkeri 2012-02-03 08:40:12

+0

噢,对不起。我从我自己的项目中获取了这些代码,并且错误地更改了参数。 – Vannen 2012-02-03 08:53:18

0

这也可以在代码中实现,而不是所有的SQL,但考虑到你的应用程序的性质 - 可能有很多海报中很多城市 - 这个解决方案很容易占用太多的系统资源。但这里有一个快速的片断:

key = lambda poster: poster.city 
posters = Poster.objects.filter(city__country=country) 
posters = sorted(posters, key=key) 
di = {} 
for k, g in itertools.groupby(posters, key): 
    di[k] = list(g) 

现在di包含每个城市的钥匙,所有的海报作为值的列表。

0

这将返回城市,每个海报的该城市的数量:

cities = City.objects.filter(country=my_country).annotate(num_posters=Count('posters')) 

然后你就可以循环的模板:

<h1>{{ country }}</h1> 
{% for city in cities %} 
<p> 
    {{ city.name }} - {{ city.num_posters }} posters 
    {% for poster in city.posters.all %} 
     <img src="{{ poster.image.url }}"> 
    {% endfor %} 
</p> 
{% endfor %} 

现在,上面的代码分别取海报每个城市,这可能没有效率。为了解决这个问题,您可以使用prefetch_related(如果你能负担得起使用Django主干),或手工做自己,就像here

0

有了你已经有了你可以在模板中使用regroup的代码,类似:

{% regroup posters by city as city_list %} 

<ul> 
{% for city in city_list %} 
    <li>{{ city.grouper }} ({{city.list|length}}) 
    <ul> 
     {% for poster in city.list %} 
     <li>{{ poster.image}}</li> 
     {% endfor %} 
    </ul> 
    </li> 
{% endfor %} 
</ul> 

请注意,您需要在您的视图中按城市排列海报查询。