【问题标题】:m2m through : accessing intermediate table from templatesm2m through:从模板访问中间表
【发布时间】:2012-07-13 17:14:03
【问题描述】:

当多对多关系通过直通表有额外数据时,如何获取模板中的数据?从一个视图来看,如果我提供参数,我可以得到数据:

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.all 也不起作用。

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

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

【问题讨论】:

标签: django django-models django-orm


【解决方案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)

【讨论】:

  • %model%_set 语法(或相关名称,如果您已指定)用于通过后向关系访问模型。
  • 您可以编辑自己的答案,直接在此处而不是在 cmets 中添加这些额外信息。
  • @AndreyKaygorodov 但是如何获得与 m2m 实例关联的“投票”?
  • 我认为在你的情况下,你应该在模板中使用 CategoryEntry 模型。
【解决方案2】:

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

category.entry.all()

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

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

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

【讨论】:

  • 添加 'for entry in category.category_entry.all: pprint('2: ' + entry)' 会导致错误 'Category object has no attribute category_entry'。请记住,我们的目标是在模板中加入一些东西,这样它就可以显示存储在每条 m2m 记录中的唯一额外数据。您能否更新您的答案,了解为什么它在这里不起作用?
  • 修正了我的答案,对此感到抱歉
  • 你能修改答案来处理模板吗?该视图正在过滤和排序条目。我想在模板中显示“投票”。
  • 但是如何获得与 m2m 实例关联的“投票”?
【解决方案3】:

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

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')

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-04-28
    • 1970-01-01
    • 2011-01-18
    • 1970-01-01
    • 1970-01-01
    • 2015-05-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多