m2m through:从模板访问中间表

时间:2012-07-13 19:56:59

标签: django django-models django-orm

当ManyToMany关系通过直通表获得额外数据时,如何获取模板中的数据?从视图中我可以获取数据,如果我提供参数:

class Category(models.Model):
    title           = models.CharField(max_length=1024,null=True,blank=True)
    entry           = models.ManyToManyField(Entry,null=True,blank=True,
                                             related_name='category_entry',
                                             through='CategoryEntry',
                                             )

class CategoryEntry(models.Model):
    category    = models.ForeignKey(Category)
    entry       = models.ForeignKey(Entry)
    votes       = models.IntegerField(null=False, default=0)

def category_detail(request, pk):
    category = models.Category.objects.select_related().get(pk=pk)
    entries  = category.entry.order_by('-temp_sort_order').filter(temp_sort_order__gte=0)
    for entry in entries:
        assert isinstance(entry, models.Entry)
        ce = models.CategoryEntry.objects.get(entry=entry, category=category)
        pprint('Show votes as a test: ' + ce.votes) #OK
        pprint('entry title: ' + entry.title) #OK
        pprint('entry votes: ' + str(entry.category_entry.votes)) #BAD
        pprint('entry votes: ' + str(entry.entry.votes))  #BAD
    ....

但模板无法为方法提供参数。

https://docs.djangoproject.com/en/dev/topics/db/models/#extra-fields-on-many-to-many-relationships上的文档对模板没有提及。使用for entry in category.category_entry_set.all使用'Category'对象没有属性'category_entry_set'。 category.category_entry.all也不起作用。

最终我想在模板中显示额外的数据:

{% for entry in entries %}
    <ul>
        <li>Title: {{ entry.title }} Votes: {{ entry.category_entry.votes }} {{ entry.entry.votes }}</li>
    </ul>
{% endfor %}

3 个答案:

答案 0 :(得分:1)

更新我的答案,我错误地将相关经理放在错误的模型上,在你的情况下,就像安德烈所说,从类别中获取条目的正确方法是:

category.entry.all()

现在,解决您的迭代和订购问题。在python中它看起来像这样:

for ce in category.categoryentry_set.order_by('-votes'):
    print ce.entry, ce.votes

这将为您提供按投票排序的每个类别的条目。要将此模板转换为模板,您只需将查询集category.categoryentry_set.order_by('-votes')保存到变量中并对其进行迭代即可。

答案 1 :(得分:1)

如果模板中有类别实例:

category.entry.all -> list of entries

如果模板中有一个条目实例:

entry.category_entry.all -> list of categories

您应该以复数形式呼叫M2M字段, 那么你将有一个更易读的代码

category.entries.all

%model%_set语法(或相关名称,如果已指定)用于通过向后关系访问模型。

https://docs.djangoproject.com/en/1.4/topics/db/queries/#following-relationships-backward

但是如何获得与m2m实例关联的“投票”? - 布莱斯

我建议您采用以下方式:

class Category(models.Model):
    title           = models.CharField(max_length=1024,null=True,blank=True)
    entries           = models.ManyToManyField(Entry,null=True,blank=True,
                                             related_name='categories',
                                             through='CategoryEntry',
                                             )

class CategoryEntry(models.Model):
    category    = models.ForeignKey(Category, related_name='category_entries')
    entry       = models.ForeignKey(Entry)
    votes       = models.IntegerField(null=False, default=0)

def category_detail(request, pk):
    category = models.Category.objects.select_related().get(pk=pk)
    category_entries  = category.category_entries.filter(entry__temp_sort_order__gte=0).order_by('-entry__temp_sort_order')
    for category_entry in category_entries:
        # category_entry is an instance of the model CategoryEntry
        pprint('category entry votes: ' + str(category_entry.votes))
        pprint('entry title: ' + category_entry.entry.title)
   ....

HOW TO
entry = Entry.objects.get(pk=1)
entry.categories.all() # list of categories (here we work through related name of the field entries)

category = Category.objects.get(pk=1)
category.entries.all() # list of entries (here we work through m2m field entries)

category.category_entries.all() # list of CategoryEntry objects (through related name category_entries of the field category in model CategoryEntry)

答案 2 :(得分:0)

这是一个丑陋丑陋的黑客行事。过滤和排序后,处理列表并附加额外的模型字段。模板现在可以轻松访问:

entries  = category.entry.order_by('-temp_sort_order').filter(temp_sort_order__gte=0)
for entry in entries:
    assert isinstance(entry, models.Entry)
    ce = models.CategoryEntry.objects.get(entry=entry, category=category)
    entry.xxx_votes = mark_safe(ce.votes)  # use {{ entry.xxx_votes to access }}
    entry.xxx_ce    = ce  # Use {{ entry.ce.votes to access }}
return render_to_response('category.html')

希望有人可以提供更好的答案,或建议改进django本身。此解决方案不允许我对category.entry.order_by('-category_entry.votes')

进行排序