Skip to main content
 首页 » 编程设计

python之Django:按计数排序的聚合的输出聚合

2025年05月04日31mengfanrong

我正在尝试在我的 Django 模板中输出以下数据。

国家将按故事数降序排列。 城市将按故事数(在该国家/地区下)降序排列

Country A(# of stories) 
  City A (# of stories) 
  City B (# of stories) 
 
Country B(# of stories) 
  City A (# of stories) 
  City B (# of stories) 

我的模型如下:

# Create your models here. 
class Country(models.Model): 
    name = models.CharField(max_length=50) 
 
class City(models.Model): 
    name = models.CharField(max_length=50) 
    country = models.ForeignKey(Country) 
 
class Story(models.Model): 
    city = models.ForeignKey(City) 
    country = models.ForeignKey(Country) 
    name = models.CharField(max_length=255) 

最简单的方法是什么?

请您参考如下方法:

这个解决方案对我有用。不过,您需要对其进行调整以将其传递给模板。

from django.db.models import Count 
all_countries = Country.objects.annotate(Count('story')).order_by('-story__count') 
 
for country in all_countries: 
    print "Country %s (%s)" % (country.name, country.story__count) 
    all_cities = City.objects.filter(country = country).annotate(Count('story')).order_by('-story__count') 
    for city in all_cities: 
        print "\tCity %s (%s)" % (city.name, city.story__count) 

更新

这是将此信息发送到模板的一种方法。这涉及使用自定义过滤器。

@register.filter 
def get_cities_and_counts(country): 
    all_cities = City.objects.filter(country = country).annotate(Count('story')).order_by('-story__count') 
    return all_cities 

查看:

def story_counts(request, *args, **kwargs): 
    all_countries = Country.objects.annotate(Count('story')).order_by('-story__count') 
    context = dict(all_countries = all_countries) 
    return render_to_response(..., context) 

在你的模板中:

{% for country in all_countries %} 
    <h3>{{ country.name }} ({{ country.story__count }})</h3> 
    {% for city in country|get_cities_and_counts %} 
        <p>{{ city.name }} ({{ city.story__count }})</p> 
    {% endfor %} 
{% endfor %} 

更新 2

在模型中使用自定义方法的变体。

class Country(models.Model): 
    name = models.CharField(max_length=50) 
 
    def _get_cities_and_story_counts(self): 
        retrun City.objects.filter(country = self).annotate(Count('story')).order_by('-story__count') 
    city_story_counts = property(_get_cities_and_story_counts) 

这可以让您避免定义过滤器。模板代码更改为:

{% for country in all_countries %} 
    <h3>{{ country.name }} ({{ country.story__count }})</h3> 
    {% for city in country.city_story_counts %} 
        <p>{{ city.name }} ({{ city.story__count }})</p> 
    {% endfor %} 
{% endfor %}