用于循环迭代的Django模板由不同的外键

时间:2016-08-01 15:00:23

标签: python django for-loop django-templates

在我的应用中,我有3个型号:问题,系列和角色。 Issue模型有一个Series ForeignKey和一个Character ManyToManyField。这里简化了:

class Character(models.Model):
    name = models.CharField('Character name', max_length=200)
    desc = models.TextField('Description', max_length=500)

class Series(models.Model):
    name = models.CharField('Series name', max_length=200)
    desc = models.TextField('Description', max_length=500)

class Issue(models.Model):
    series = models.ForeignKey(Series, on_delete=models.CASCADE, blank=True)
    name = models.CharField('Issue name', max_length=200)
    number = models.PositiveSmallIntegerField('Issue number')
    date = models.DateField('Cover date')
    desc = models.TextField('Description', max_length=500)
    characters = models.ManyToManyField(Character, blank=True)
    cover = models.FilePathField('Cover file path', path="media/images/covers")

我有一个Character模板,显示有关角色的信息。我还要显示字符所在的问题,按系列排序。

{% extends "app/base.html" %}

{% block page-title %}{{ character.name }}{% endblock page-title %}

{% block content %}

<div class="description">
    <p>{{ character.desc }}</p>
</div>

<div class="issues">
    <h3>Issues</h3>
    {% for series in character.issue_set.all %}
    <div>
        <a href="{% url 'app:series' series.id %}">{{ series.name }}</a>
        <ul>
        {% for issue in character.issue_set.all %}
            {% if issue.series.name == series.name %}
            <li>
                <a href="{% url 'app:issue' issue.id %}"><img src="/{{ issue.cover }}" alt = "{{ series.name }}" ></a>
                <a href="{% url 'app:issue' issue.id %}"><p>Issue #{{ issue.number }}</p></a>
            </li>
            {% endif %}
        {% endfor %}
        </ul>
    </div>
    {% endfor %}
</div>

{% endblock content %}

显然,目前格式化的方式是,对于集合中的每个问题,它都会输出系列标题,然后输出集合中的每个问题。

<div class="issues">
    <h3>Issues</h3>
    <div>
        <a href="/series/1">Series 1</a>
        <ul>
            <li>
                <a href="/issue/1"><img src="/media/images/covers/01.jpg" alt="Series 1"></a>
                <a href="/issue/1"><p>Issue #1</p></a>
            </li>
            <li>
                <a href="/issue/2"><img src="/media/images/covers/02.jpg" alt="Series 1"></a>
                <a href="/issue/2"><p>Issue #2</p></a>
            </li>
        </ul>
    </div>
    <div>
        <a href="/series/1">Series 1</a>
        <ul>
            <li>
                <a href="/issue/1"><img src="/media/images/covers/01.jpg" alt="Series 1"></a>
                <a href="/issue/1"><p>Issue #1</p></a>
            </li>
            <li>
                <a href="/issue/2"><img src="/media/images/covers/02.jpg" alt="Series 1"></a>
                <a href="/issue/2"><p>Issue #2</p></a>
            </li>
        </ul>
    </div>
</div>

以下是我想看到的内容:

<div class="issues">
    <h3>Issues</h3>
    <div>
        <a href="/series/1">Series 1</a>
        <ul>
            <li>
                <a href="/issue/1"><img src="/media/images/covers/01.jpg" alt="Series 1"></a>
                <a href="/issue/1"><p>Issue #1</p></a>
            </li>
            <li>
                <a href="/issue/2"><img src="/media/images/covers/02.jpg" alt="Series 1"></a>
                <a href="/issue/2"><p>Issue #2</p></a>
            </li>
        </ul>
    </div>
</div>

我对模板进行了大量研究,而且我没有找到基于不同值的列表的方法。我也尝试在我的角色或问题模型中创建一个新的集合,我可以用来替换issue_set.all,但我还没有让它工作。

编辑:根据marcusshep的请求,角色视图使用通用的DetailView:

class CharacterView(generic.DetailView):
    model = Character
    template_name = 'app/character.html'

1 个答案:

答案 0 :(得分:1)

我会使用基于函数的视图而不是基于类的通用视图。原因是你所要求的行为超出了通用的范围。

在您的函数中,您可以构建所需的查询集,而不必使用generic.DetailView提供的查询集。

def my_view(request, *args, **kwargs):
    character = Character.objects.get(id=request.GET.get("id", None))
    issues = character.issue_set.all().order_by("series__name")
    return render(request, 'app/character.html', {"issues": issues})

或者,您可以使用已有的内容并覆盖DetailView's get_queryset() method

class CharacterView(generic.DetailView):
    model = Character
    template_name = 'app/character.html'

    def get_queryset():
        # return correct queryset
  

但最大的问题是需要使用此套件的更多方面。例如,我将添加创作者,故事弧等,他们将拥有自己的页面,并且需要显示相关问题,也按系列排序。如果没有太多的代码重用,那么可以使用任何这些模板都可以使用的解决方案。

这是所有编程领域中非常常见的问题。解决这个问题的一个非常简单的方法是在一个函数中隔离逻辑,并在需要时调用该函数。

def my_issues_query():
    # find the objects you need

def my_view(request, *args, **kwargs):
    issues = my_issues_query()

您还可以利用pythons装饰器功能。 (这是我最喜欢的方法。)

def has_issues(view_function):
    def get_issues(request, *args, **kwargs):
        # find all the issues you need here
        # you'll only need to write this logic once.
        issues = Issues.objects.filter(...)
        return issues
    return get_issues

@has_issues
def my_view(request, *args, **kwargs):
    # this functions namespace now contains
    # the variable `issues`.
    # which allows for the use of the query ie.
    return render(
        request, 
        "my_templates/template.html", 
        {"issues":issue}
    )