python - Django template for loop iteration by distinct foreign key -


in app, have 3 models: issue, series, , character. issue model has series foreignkey, , character manytomanyfield. here simplified:

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

i have character template displays information character. want display issues character in, sorted series.

{% 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>     {% series in character.issue_set.all %}     <div>         <a href="{% url 'app:series' series.id %}">{{ series.name }}</a>         <ul>         {% 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 %} 

obviously, way formats every issue in set, outputs series title, , each issue in set.

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

here's see:

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

i've researched quite bit on templating, , i'm not seeing way listing based on distinct values. i've tried creating new set in character or issue model use replace issue_set.all, have yet working.

edit: upon request of marcusshep, character view using generic detailview:

class characterview(generic.detailview):     model = character     template_name = 'app/character.html' 

i use function based view rather class based generic view. reason being required behavior going beyond generic.

in function can build queryset desire instead of having fight 1 provided 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}) 

alternatively, can use have , override detailview's get_queryset() method.

class characterview(generic.detailview):     model = character     template_name = 'app/character.html'      def get_queryset():         # return correct queryset 

the biggest problem though there more aspects need use set. instance, i'll adding creators, story arcs, etc. have own pages , need display related issues, sorted series well. nice have solution can used of these templates without code re-use.

this common problem in areas of programming. simple way solve isolate logic in 1 function , call function whenever need it.

def my_issues_query():     # find objects need  def my_view(request, *args, **kwargs):     issues = my_issues_query() 

you can take advantage of pythons decorator functions. (which favorite approach.)

def has_issues(view_function):     def get_issues(request, *args, **kwargs):         # find issues need here         # you'll need write logic once.         issues = issues.objects.filter(...)         return issues     return get_issues  @has_issues def my_view(request, *args, **kwargs):     # functions namespace contains     # variable `issues`.     # allows use of query ie.     return render(         request,          "my_templates/template.html",          {"issues":issue}     ) 

Comments