以多对多关系显示中间表中的数据

时间:2019-04-30 11:48:53

标签: django django-models django-templates

我有3个模型遵循Django文档(https://docs.djangoproject.com/en/2.2/topics/db/models/#extra-fields-on-many-to-many-relationships)中描述的原理:

class Topic(models.Model):
    key = models.CharField(max_length=255, primary_key=True)
    persons = models.ManyToManyField('Person', through='Interest')

class Person(models.Model):
    first_name = models.CharField(max_length=255)
    last_name = models.CharField(max_length=255)
    interests = models.ManyToManyField('Topic', through='Interest')

class Interest(models.Model):
    person = models.ForeignKey(Person, on_delete=models.CASCADE)
    topic = models.ForeignKey(Topic, on_delete=models.CASCADE)
    source = models.ForeignKey(TopicSource, on_delete=models.CASCADE)

views.py非常简单:

class TopicsView(generic.ListView):
    template_name = 'app/topics.html'
    context_object_name = 'topics_list'

    def get_queryset(self):
        return Topic.objects.all()

模板实际上让我头疼:

    <table>
        <tbody class="list">
            {% for item in topics_list %}
            <tr>
                <td>{{ item.key }}</td>
                <td>{{ item.person_set.all.count }}</td>
                <td>
                    <ul>
                        {% for person in item.person_set.all %}
                        <li>{{ person.last_name }}, {{ person.first_name }} [{% person.interests_set.get(cluster=item) %}]</li>{% endfor %}
                    </ul>
                </td>
            </tr>
            {% endfor %}
        </tbody>
    </table>

使用{% person.interests_set.get(topic=item) %},我试图访问中间表中的数据。

如何在人名旁边显示source中的interest

This solution在shell中提供了有关如何执行此操作的提示,但我不知道如何在模板中实现。

2 个答案:

答案 0 :(得分:2)

Django模板不支持您尝试开箱即用的功能。您必须创建自定义tag才能实现您要尝试的功能。

无论如何,您都可以这样做:

class TopicsView(generic.ListView):
    template_name = 'app/topics.html'
    context_object_name = 'topics_list'
    queryset = Topic.objects.prefetch_related(
        Prefetch(
            'interest_set',
            Interest.objects.select_related('person')
    )

然后调整模板以遍历兴趣。

<table>
    <tbody class="list">
        {% for item in topics_list %}
        <tr>
            <td>{{ item.key }}</td>
            <td>{{ item.interest_set.all.count }}</td>
            <td>
                <ul>
                    {% for interest in item.interest_set.all %}
                    <li>{{ interest.person.last_name }}, {{ interest.person.first_name }} [ {{ interest.source }} ]</li>{% endfor %}
                </ul>
            </td>
        </tr>
        {% endfor %}
    </tbody>
</table>

答案 1 :(得分:0)

作为@schillingt提出的解决方案(公认的解决方案)的替代方案,我提出了以下解决方案:

views.py

class InterestsView(generic.ListView):
    template_name = 'app/interests.html'
    context_object_name = 'interests_list'

    def get_queryset(self):
        return Interest.objects.order_by('topic', 'person').all()

模板:

{% regroup interests_list by topic as l1%}
    <table>
        <tbody>
            {% for topic in l1 %}
            <tr>
                <td>{{ topic.grouper }}</td>
                <td>{{ topic.list|length }}</td>
                <td>
                    <ul>
                        {% for item in topic.list%}
                        <li>{{ item.person.last_name }}, {{ item.person.first_name }} [{{ item.source }}]</li>
                        {% endfor %}
                    </ul>
                </td>
            </tr>
            {% endfor %}
        </tbody>
    </table>

但是,@ schillingt的解决方案更好,因为它的性能要好很多(系数2),