2016-08-01 81 views
1

在我的应用程序中,我有3个模型:问题,系列和字符。问题模型有一个系列ForeignKey和一个字符ManyToManyField。在这里他们被简化:Django模板循环迭代由不同的外键

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

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

{% 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,但我还没有得到它的工作。

EDIT:在marcusshep的请求时,角色视图是使用通用的DetailView:

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

我可以看到你的视图,你传递'character' queryset到模板吗? – marcusshep

+0

@marcusshep,用视图代码更新。 –

+0

所以,要清楚你想让你的模板只显示具有不同名称的字符正确吗? – marcusshep

回答

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 

最大的问题是,虽然会有更多的方面,将需要使用此设置。例如,我将添加Creators,Story Arcs等,他们将拥有自己的页面,并需要显示相关问题,并按照系列排序。如果有一个解决方案可以被这些模板中的任何一个使用,而不需要太多的代码重用,那将是很好的。

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

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} 
    ) 
+0

尽管最大的问题是将会有更多方面需要使用这个集合。例如,我将添加Creators,Story Arcs等,他们将拥有自己的页面,并需要显示相关问题,并按照系列排序。如果有一个解决方案可以被这些模板中的任何一个使用,而不需要太多的代码重用,那将是很好的。 –

+0

是的,只需编写一个函数并在需要时调用它。看到更新的答案。 – marcusshep

+0

这是不是只会将'问题'对象的结果传递给没有'Character'对象的模板?也许我的头还没有完成,但在我看来,你会将模板作为主要对象,然后通过“字符”过滤拉入问题对象。我对Django来说很新,所以我很诚实地问。感谢您的所有帮助! –