具有“通过”类的ManyToMany的QuerySet的Django模板属性

时间:2018-01-30 21:13:31

标签: python django templates

我有大概这样的模型:

class Person(models.Model):
  ...
  name = models.CharField(max_length=40)
  eyes = models.CharField(max_length=12)
  ...
  relationships = models.ManyToManyField('self', through='Relationship',
    symmetrical=False, related_name='related_to')

class Relationship(models.Model):
  from_person = models.ForeignKey(Person, related_name='from_people', ...)
  to_person = models.ForeignKey(Person, related_name='to_people', ...)
  status = models.CharField(max_length=20)

我有合理的数据库条目,可以在Python shell中看到它们:

>>> p1 = Person.objects.get(...)
>>> r = Relationship.objects.filter(from_person=p1)
<QuerySet [<Relationship: p1 p2 status>], [<Relationship: p1 p99 status>]>
>>> r[0].status
Friend
>>> r[0].from_person.name
p1
>>> r[0].from_person.eyes
Brown    # p1's eye color
>>> r[0].to_person.name
p2
>>> r[0].to_person.eyes
Blue    # p2's eye color !!!

现在我想从我的模板中访问相同的信息,但我看不到我的期望:

<p>name={{ person.name }} ({{ person.eyes }})</p>
<p>len={{ person.relationships.all|length }}</p>
{% for rel in person.relationships.all %}
  <p> rel[{{ forloop.counter }}]={{ rel.status }}
        {{ rel.from_person.name }} ({{ rel.from_person.eyes }})
        {{ rel.to_person.name }}   ({{ rel.to_person.eyes }})</p>
{% endfor %}

显示:

name=p1 (Brown)
len=2
rel[0]=
rel[1]=

我期待:

name=p1 (Brown)
len=2
rel[0]=Friend p1 (Brown) p2 (Blue)
rel[1]=Enemy p1 (Brown) p99 (Red!)

我在“关系”模型中添加了访问器方法,但它没有什么区别。 我使用模板“切片”过滤器搞砸了。 我错过了一些基本的东西......

感谢您的帮助!

编辑:此模板代码执行上述示例所需的操作。感谢以下两位评论者:

{% for rel in person.from_people.all %}
  <p> rel[{{ forloop.counter }}]={{ rel.status }}
        {{ rel.from_person.name }} ({{ rel.from_person.eyes }})
        {{ rel.to_person.name   }} ({{ rel.to_person.eyes   }})</p>
{% endfor %}

2 个答案:

答案 0 :(得分:0)

查看Person模型中的这行代码:

relationships = models.ManyToManyField('self', through='Relationship', ...)

如果您处理relationships实例的属性Person,则会返回目标模型的管理器(也是Person)。

因此p1.relationships.all()会返回与p1相关的所有,而非关系实例。

如果您想访问through模型的中间数据,则必须直接查询:

Relationship.objects.filter(from_person=p1)

另请参阅Docs (Django 2.0): Extra fields on many-to-many relationships

中的示例

编辑:Dan的评论可能会显示从模板中给定Person的访问关系数据的正确方法。我认为模板语言应该能够处理后向关系。你可以尝试一下,告诉它是否有效吗?

<p>name={{ person.name }} ({{ person.eyes }})</p>
<p>len={{ person.relationships.all|length }}</p>
{% for rel in person.from_people.all %}
  {# rel is now a Relationship where 'from_person' is 'person' #}
  <p> rel[{{ forloop.counter }}]={{ rel.status }}
        {{ rel.from_person.name }} ({{ rel.from_person.eyes }})
        {{ rel.to_person.name }}   ({{ rel.to_person.eyes }})</p>
{% endfor %}

答案 1 :(得分:0)

此模板代码执行上述示例所需的操作。感谢两位评论者:

{% for rel in person.from_people.all %}
  <p> rel[{{ forloop.counter }}]={{ rel.status }}
        {{ rel.from_person.name }} ({{ rel.from_person.eyes }})
        {{ rel.to_person.name   }} ({{ rel.to_person.eyes   }})</p>
{% endfor %}