Search code examples
pythondjangodjango-generic-views

Django Generic Views :How does DetailView automatically provides the variable to the template ??


In the following code, How does the template details.html knows that album is passed to it by views.py although we have never returned or defined any context_object_name in DetailsView class in views.py. Please explain how are the various things getting connected here.

details.html

{% extends 'music/base.html' %}
{% block title %}AlbumDetails{% endblock %}

{% block body %}
    <img src="{{ album.album_logo }}" style="width: 250px;">
    <h1>{{ album.album_title }}</h1>
    <h3>{{ album.artist }}</h3>

    {% for song in album.song_set.all %}
        {{ song.song_title }}
        {% if song.is_favourite %}
            <img src="http://i.imgur.com/b9b13Rd.png" />
        {% endif %}
        <br>
    {% endfor %}
{% endblock %}

views.py

from django.views import generic
from .models import Album

class IndexView(generic.ListView):
    template_name = 'music/index.html'
    context_object_name = 'album_list'

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

class DetailsView(generic.DetailView):
    model = Album
    template_name = 'music/details.html'

urls.py

from django.conf.urls import url
from . import views

app_name = 'music'

urlpatterns = [

    # /music/
    url(r'^$', views.IndexView.as_view(), name='index'),

    # /music/album_id/
    url(r'^(?P<pk>[0-9]+)/$', views.DetailsView.as_view(), name='details'),

]

Thanks in advance !!


Solution

  • If you check the implementation of get_context_name(), you'll see this:

    def get_context_object_name(self, obj):
        """
        Get the name to use for the object.
        """
        if self.context_object_name:
            return self.context_object_name
        elif isinstance(obj, models.Model):
            return obj._meta.model_name
        else:
            return None
    

    And the implementation for get_context_data() (from SingleObjectMixin):

    def get_context_data(self, **kwargs):
        """
        Insert the single object into the context dict.
        """
        context = {}
        if self.object:
            context['object'] = self.object
            context_object_name = self.get_context_object_name(self.object)
            if context_object_name:
                context[context_object_name] = self.object
        context.update(kwargs)
        return super(SingleObjectMixin, self).get_context_data(**context)
    

    So you can see that get_context_data() adds to the dictionary an entry with the key context_object_name (from get_context_object_name()) which returns obj._meta.model_name when self.context_object_name isn't defined. In this case, the view got self.object as a consequence of the call to get() which calls get_object(). get_object() takes the model that you've defined and automatically queries it from your database using the pk you've defined in your urls.py file.

    http://ccbv.co.uk/ is a very good website for seeing all of the functions and attributes the class based views of Django has to offer in a single page.