迭代结果,按m2m排序

时间:2011-10-21 23:02:46

标签: django django-models

我的数据模型很简单:

class Neighborhood(models.Model):
    name = models.CharField(max_length = 50)
    slug = models.SlugField()

class Location(models.Model):
    company = models.ForeignKey(Company)
    alt_name = models.CharField()
    neighborhoods = models.ManyToManyField(Neighborhood)

我想在我的网站上提供一个页面,列出他们所在地区的所有位置。如果它是单数,我认为{% regroup %}应用了邻域名称{% ifchanged %}将是我需要的所有内容,但在我的情况下,如果它是m2m,我不知道这是怎么回事。一个位置可能有多个邻域,所以我希望它们在每个匹配的邻域下面冗余显示。

我也知道FOO_set,但这是每个对象;我想加载整个数据集。

最终结果(在模板中)应该是这样的:

Alameda
    Crazy Thai
Castro
    Kellys Burgers
    Pizza Orgasmica
Filmore
    Kellys Burgers
    Some Jazz Bar
Mission
    Crazy Thai
    Elixir
...

模板语法(理想情况下?)看起来像:

{% for neighborhood in neighborhood_list %}
    {% ifchanged %}{{ neighborhood.name }}{% endifchanged %}
    {% for location in neighborhood.restaurants.all %}
        {{ location.name }}
    {% endfor %}
{% endfor %}

2 个答案:

答案 0 :(得分:1)

创建另一个定义m2m关系的模型:

class ThroughModel(models.Model):
    location = models.ForeignKey('Location')
    neighborhood = models.ForeignKey('Neighborhood')
并将其用作m2m字段的through模型:
class Location(models.Model):
    ...
    neighborhoods = models.ManyToManyField(Neighborhood, through='ThroughModel')
然后你可以把你所有的社区分类:
ThroughModel.objects.select_related().order_by('neighborhood__name')
这是未经测试的。

或者,如果您无法更改数据库,只需执行原始SQL连接。

答案 1 :(得分:1)

我只是以昂贵的方式做到这一点并将结果缓存在我的头上。您的模板示例可以正常工作,直到性能成为每个X缓存超时生成一个页面的问题。

如果结果集足够小,你也可以在python中完成它:

# untested code - don't have your models
from collections import defaultdict

results = defaultdict(list)
for location_m2m in Location.neighborhoods.through.objects.all() \ # line wrap
        .select_related('neighborhood', 'location', 'location__company__name'):

    if location_m2m.location not in results[location_m2m.neighborhood]:
        results[location_m2m.neighborhood].append(location_m2m.location)

# sort now unique locations per neighborhood
map(lambda x: x.sort(key=lambda x: x.location.company.name), results.values())

# sort neighborhoods by name
sorted_results = sorted(results.items(), key=lambda x:x[0].name)