Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple models generic DetailView to template

I have 2 models and I got the IndexView working properly using the get_context_data method. However my DetailView using the same technique is not working. How do I simply get 2 models into the DetailView?

views.py

from .models import CharacterSeries, CharacterUniverse


class IndexView(generic.ListView):
    template_name = 'character/index.html'
    context_object_name = 'character_series_list'

    def get_queryset(self):
        return CharacterSeries.objects.order_by('name')

    def get_context_data(self, **kwargs):
        context = super(IndexView, self).get_context_data(**kwargs)
        context['character_universe_list'] = CharacterUniverse.objects.order_by('name')
        return context


class DetailView(generic.DetailView):
    model = CharacterSeries
    template_name = 'character/detail.html'

    def get_context_data(self, **kwargs):
        context = super(DetailView, self).get_context_data(**kwargs)
        context['character_universe_list'] = CharacterUniverse.objects.all()
        return context

I am missing something; I need to get CharacterUniverse into the DetailView. I have tried using this page's information to no avail.

Thanks all.

UPDATE:

detail.html

<ul>
{% for series in characterseries.character_set.all %}
    <li>{{ series.name }}</li>
{% endfor %}
</ul>

<ul>
{% for universe in characteruniverse.character_set.all %}
    <li>{{ universe.name }}</li>
{% endfor %}
</ul>

index.html

{% load staticfiles %}

<link rel ="stylesheet" type="text/css" href="{% static 'character/style.css' %}" />

<h1>Character Series</h1>

<ul>
  {% for character_series in character_series_list %}  {# for MODEL in .. #}
    <li><a href="{% url 'character:detail' character_series.pk %}">{{ character_series.name }}</a></li>
  {% endfor %}
</ul>

<h1>Character Universe</h1>

<ul>
  {% for character_universe in character_universe_list %}  {# for MODEL in .. #}
    <li><a href="{% url 'character:detail' character_universe.pk %}">{{ character_universe.name }}</a></li>
  {% endfor %}
</ul>

An example from the official documentation: This is not possible in my case?

from django.views.generic import DetailView
from books.models import Publisher, Book

class PublisherDetail(DetailView):

    model = Publisher

    def get_context_data(self, **kwargs):
        # Call the base implementation first to get a context
        context = super(PublisherDetail, self).get_context_data(**kwargs)
        # Add in a QuerySet of all the books
        context['book_list'] = Book.objects.all()
        return context

Perhaps this is the final solution? This is not working though.. Naming wrong?


ALL THE UPDATES

views.py

from django.shortcuts import get_object_or_404, render
from django.views import generic
from django.views.generic import DetailView
from .models import CharacterSeries, CharacterUniverse


class IndexView(generic.ListView):
    template_name = 'character/index.html'
    context_object_name = 'character_series_list'

    def get_queryset(self):
        return CharacterSeries.objects.order_by('name')

    def get_context_data(self, **kwargs):
        context = super(IndexView, self).get_context_data(**kwargs)
        context['character_universe_list'] = CharacterUniverse.objects.order_by('name')
        return context


class SeriesDetail(DetailView):
    model = CharacterSeries
    template_name = 'character/series_detail.html'

class UniverseDetail(DetailView):
    model = CharacterUniverse
    template_name = 'character/universe_detail.html'

urls.py

from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^$', views.IndexView.as_view(), name='index'),
    url(r'^(?P<pk>[0-9]+)/$', views.SeriesDetail.as_view(), name='series_detail'),
    url(r'^(?P<pk>[0-9]+)/$', views.UniverseDetail.as_view(), name='universe_detail'),
]

index.html

{% load staticfiles %}

<link rel ="stylesheet" type="text/css" href="{% static 'character/style.css' %}" />

<h1>Character Series</h1>

<ul>
  {% for character_series in character_series_list %}
    <li><a href="{% url 'character:series_detail' character_series.pk %}">{{ character_series.name }}</a></li>
  {% endfor %}
</ul>

<h1>Character Universe</h1>

<ul>
  {% for character_universe in character_universe_list %}
    <li><a href="{% url 'character:universe_detail' character_universe.pk %}">{{ character_universe.name }}</a></li>
  {% endfor %}
</ul>

series_detail.html

<ul>
{% for series in characterseries.character_set.all %}
    <li>{{ series.name }}</li>
{% endfor %}
</ul>

universe_detail.html

<ul>
{% for universe in characteruniverse.character_set.all %}
    <li>{{ universe.name }}</li>
{% endfor %}
</ul>
like image 231
Snerd Avatar asked Jun 30 '15 18:06

Snerd


People also ask

What is the difference between a list view and detail view in Django?

The ListView approach seems more semantic, because what I want is a list of posts, but it's also slightly more complex. It requires that I overwrite two methods. The DetailView approach only requires me to overwrite one method.


1 Answers

Explanation of why you can't use one view for both models

A DetailView is meant to display details about an object from one model. It's fine to include extra context, but the view isn't designed to handle two possible models.

The example from the docs is showing the details for one publisher, and displaying all the books at the same time.

Your DetailView lets you show the details for one CharacterSeries, and display all of the CharacterUniverse at the same time.

However, you cannot use that same view to display details for one CharacterUniverse. You need a different view to display details for one CharacterUniverse

Solution

Therefore, you need two different detail views, one for each model.

You need a distinct url for each view. Otherwise, the request will always match the first regex (in this case series_detail. The following would work.

url(r'^series/(?P<pk>[0-9]+)/$', views.SeriesDetail.as_view(), name='series_detail'),
url(r'^universe/(?P<pk>[0-9]+)/$', views.UniverseDetail.as_view(), name='universe_detail'),
like image 193
Alasdair Avatar answered Sep 20 '22 10:09

Alasdair