Please help me with CBV template_name behaviour.

64 views
Skip to first unread message

JoeCodeswell

unread,
Jun 18, 2016, 2:17:55 PM6/18/16
to Django users
Dear django-users,

In an effort ot learn Django, i am writing a blog post, "Simple Django Tutorial", to remind myself & possibly others of some Django Basics.

I ALMOST finished when i noticed some strange (to me) behaviour of the `template_name` in a CBV.

Here are the relevant CBVs:

class SimpleSearchListContactView(ListView):

    model
= Contact
    template_name
= 'contacts/contact_list.html'    
   
def get_queryset(self):
        qs
= super(SimpleSearchListContactView, self).get_queryset()
       
       
return qs.filter(first_name__contains=self.kwargs['fname'])
       
# "first_name" is the first_name field in our Contacts model
       
# "contains" is one of Django's "Field lookups"
       
# "'fname'" is passed in from our url <fname> Regex Named Group  
   
   
class ParametricSearchListContactView(ListView):
    model
= Contact
    template_name
= 'contacts/contact_list.html'

   
def get_queryset(self):
        qs
= super(ParametricSearchListContactView, self).get_queryset()
        field_lookups_dict
= {
           
'%s__%s'%(self.kwargs['field_name'], self.kwargs['match_cmd']):self.kwargs['value'],
           
# for a def of each match_cmd see Field lookups - https://docs.djangoproject.com/en/1.9/ref/models/querysets/#field-lookups
       
}
       
print ("ParametricSearchListContactView")
       
print (ParametricSearchCRUDListContactView.template_name)
       
print (ParametricSearchListContactView.template_name)
       
print (ListView.template_name)
       
return qs.filter(**field_lookups_dict)
   
   
class SimpleSearchCRUDListContactView(ListView):

    model
= Contact
    template_name
= 'contacts/crudlist.htm'    
   
   
def get_queryset(self):
        qs
= super(SimpleSearchCRUDListContactView, self).get_queryset()
       
       
return qs.filter(first_name__contains=self.kwargs['fname'])
       
# "first_name" is the first_name field in our Contacts model
       
# "contains" is one of Django's "Field lookups"
       
# "'fname'" is passed in from our url <fname> Regex Named Group  
   
   
class ParametricSearchCRUDListContactView(ListView):
    model
= Contact
    template_name
= 'contacts/crudlist.htm'
   

   
def get_queryset(self):
        qs
= super(ParametricSearchCRUDListContactView, self).get_queryset()
        field_lookups_dict
= {
           
'%s__%s'%(self.kwargs['field_name'], self.kwargs['match_cmd']):self.kwargs['value'],
           
# for a def of each match_cmd see Field lookups - https://docs.djangoproject.com/en/1.9/ref/models/querysets/#field-lookups
       
}
       
print ("ParametricSearchCRUDListContactView")
       
print (ParametricSearchCRUDListContactView.template_name)
       
print (ParametricSearchListContactView.template_name)
       
print (ListView.template_name)

       
return qs.filter(**field_lookups_dict)
   

   


The 2nd pair of classes are the same as the first pair EXCEPT:
 
    template_name = ‘contacts/crudlist.html’ NOT ‘contacts/contact_list.html’
    Class names are new in 2 places in each class:
        “SimpleSearchCRUDListContactView”
        “ParametricSearchCRUDListContactView”


Here are the relevant URLs:

    url(r'^ssearch/(?P<fname>[\w-]+)/$', contacts.views.SimpleSearchListContactView.as_view(), name='simplesearchlistcontactview', ),
    url
(r'^psearch/(?P<field_name>[\w-]+)/(?P<match_cmd>[\w-]+)/(?P<value>[\w-]+)/$', contacts.views.ParametricSearchListContactView.as_view(), name='parametricsearchlistcontactview', ),
   
    url
(r'^ssearchc/(?P<fname>[\w-]+)/$', contacts.views.SimpleSearchCRUDListContactView.as_view(), name='ssearchc', ),
    url
(r'^psearchc/(?P<field_name>[\w-]+)/(?P<match_cmd>[\w-]+)/(?P<value>[\w-]+)/$', contacts.views.ParametricSearchCRUDListContactView.as_view(), name='psearchc', ),



I EXPECT the Views with CRUD in their names (CRUD Views) to behave THE SAME AS the others EXCEPT items are listed with read, update & delete links, because that is how `contacts/crudlist.htm` displays them.

THE PROBLEM IS that the CRUD Views display the items using the Plain Template (contacts/contact_list.html) NOT the CRUD Template ('contacts/crudlist.htm')

I.E. Navigating to `http://127.0.0.1:8000/contacts/psearchc/last_name/contains/d/`
YIELDS

Plain Contacts

NOT AS EXPECTED

CRUD Contacts

Create Also, for the same navigation URL, in the Server Status Window the prints yield

[18/Jun/2016 11:16:26] "GET /contacts/psearchc/last_name/contains/d/ HTTP/1.1" 200 218
ParametricSearchCRUDListContactView
contacts
/crudlist.htm
contacts
/contact_list.html
None

I hope someone can tell me what's going on here.

Thanks in advance.

Love and peace,

Joe

James Schneider

unread,
Jun 19, 2016, 1:52:46 AM6/19/16
to django...@googlegroups.com

> I EXPECT the Views with CRUD in their names (CRUD Views) to behave THE SAME AS the others EXCEPT items are listed with read, update & delete links, because that is how `contacts/crudlist.htm` displays them.
>
> THE PROBLEM IS that the CRUD Views display the items using the Plain Template (contacts/contact_list.html) NOT the CRUD Template ('contacts/crudlist.htm')
>

The Django debug toolbar can likely illuminate the problem here, or at least provide a direction. You would need to verify the template(s) that have been rendered as part of your view call, and that they're actually doing what you think they're doing.

It's a bit hard to follow your code, as you include extraneous classes that don't appear to be relevant to the problem (no inheritance, no indication they've been triggered, etc.). With that being said, your output from the view appears to be correct and shows a different (and correct) template_name for each view. I might be missing something though, and admittedly I'm responding on my phone.

My assumption at this point would be that the templates are rendered correctly by Django (correctly meaning 'as configured'), and that the issue actually lies within your template inheritance structure (if any). Again, the debug toolbar will walk you through that.

-James

JoeCodeswell

unread,
Jun 20, 2016, 12:18:44 PM6/20/16
to Django users
Dear James,

Thanks for your reply.
  1. I'll investigate using the "Django debug toolbar".
  2. re: "extraneous classes":  I was trying to make a point of how to construct the second-2 classes from the first-2. The second-2 classes (CRUD classes) are a text copy of the first-2 with the difference being that the second-2 have their names changed, in the appropriate 2 places & (I THOUGHT) they point to A DIFFERENT Crud Template ('contacts/crudlist.htm'). The Crud Template IS NOT USED FOR RENDERING. INSTEAD the Template mentioned in the first-2 classes is used.
  3. re: "template inheritance structure". Any Django Docs on this subject?

I'll investigate the Debug Toolbar & see what it tells me.


Again, THANKS, BIG TIME, James.


Love and peace,

Joe

JoeCodeswell

unread,
Jun 21, 2016, 1:01:31 PM6/21/16
to Django users
Dear James & All,

I installed the Django Debug Toolbar and here is what it says when i navigate to 'http://127.0.0.1:8000/contacts/psearchc/last_name/contains/d/'

Template path

  1. C:\Users\joeco\djtut\mysite\templates

Template

contacts/contact_list.html
C:\\Users\\joeco\\djtut\\mysite\\templates\\contacts\\contact_list.html
Context:
{'False': False, 'None': None, 'True': True}
{'DEFAULT_MESSAGE_LEVELS': {'DEBUG': 10,
                           
'ERROR': 40,
                           
'INFO': 20,
                           
'SUCCESS': 25,
                           
'WARNING': 30},
 
'csrf_token': <SimpleLazyObject: '8EMBPVWQwGxM4RqYdoUYNbLZcdGX3Wyo'>,
 
'debug': True,
 
'messages': <django.contrib.messages.storage.fallback.FallbackStorage object at 0x000001E614D9C8D0>,
 
'perms': <django.contrib.auth.context_processors.PermWrapper object at 0x000001E614D91940>,
 
'request': '<<request>>',
 
'sql_queries': <function debug.<locals>.<lambda> at 0x000001E614DA7A60>,
 
'user': <SimpleLazyObject: <User: joeco>>}
{}
{'contact_list': '<<queryset of contacts.Contact>>',
 
'is_paginated': False,
 
'object_list': '<<queryset of contacts.Contact>>',
 
'page_obj': None,
 
'paginator': None,
 
'view': <contacts.views.ParametricSearchCRUDListContactView object at 0x000001E614D9C278>}

Context processors

django.template.context_processors.csrf
{'csrf_token': <SimpleLazyObject: '8EMBPVWQwGxM4RqYdoUYNbLZcdGX3Wyo'>}

django.template.context_processors.debug
{'sql_queries': <function debug.<locals>.<lambda> at 0x000001E614DA7A60>, 'debug': True}

django.template.context_processors.request
{'request': <WSGIRequest: GET '/contacts/psearchc/last_name/contains/d/'>}

django.contrib.auth.context_processors.auth
{'perms': <django.contrib.auth.context_processors.PermWrapper object at 0x000001E614D91940>, 'user': <SimpleLazyObject: <User: joeco>>}

django.contrib.messages.context_processors.messages
{'DEFAULT_MESSAGE_LEVELS': {'INFO': 20, 'WARNING': 30, 'DEBUG': 10, 'ERROR': 40, 'SUCCESS': 25}, 'messages': <django.contrib.messages.storage.fallback.FallbackStorage object at 0x000001E614D9C8D0>}

Again, i am EXPECTING the view to use the
CRUD Template == 'contacts/crudlist.htm';
NOT the Plain TEMPLATE == 'contacts/contact_list.html'

OK EVERYONE, I APOLOGIZE. I HAD A SPELLING MISTAKE.
'contacts/crudlist.htm'
SHOULD HAVE BEEN
'contacts/crudlist.html'

All WORKS NOW.
THANKS for the help.
At least i found out about the Django Debug Toolbar.

Sorry again. Thanks AGAIN.

JoeCodeswell

unread,
Jun 21, 2016, 1:05:08 PM6/21/16
to Django users
Dear James &  Django-Users,

As an afterthought, I wonder why my misspelling didn't cause an error instead of a "wrong" Template being used?

Any insights?

Thanks again,

Love and peace,

Joe

James Schneider

unread,
Jun 22, 2016, 7:18:21 PM6/22/16
to django...@googlegroups.com
On Tue, Jun 21, 2016 at 10:05 AM, JoeCodeswell <joecod...@gmail.com> wrote:
Dear James &  Django-Users,

As an afterthought, I wonder why my misspelling didn't cause an error instead of a "wrong" Template being used?

Any insights?


Not particularly. That should have caused an error. The only way it wouldn't have is if you have (or one of your installed apps has) a file named crudlist.htm inside of a folder named contacts. I'd be interested to see what the debug toolbar had to say while the typo was in place. 

As far as your question about template inheritance earlier, here is the link to the docs:


-James

JoeCodeswell

unread,
Jun 23, 2016, 1:48:42 PM6/23/16
to Django users
Dear James,

Thanks for all the GREAT info. I'll be sure to look at #template-inheritance.



I'd be interested to see what the debug toolbar had to say while the typo was in place.

The contents of the debug toolbar that i published, in this thread, IN THIS POST, just before my afterthought post, WAS "while the typo was in place". I used the contents to discover the typo.

Thanks again, James for the info and the interest.

Love and peace,

Joe

James Schneider

unread,
Jun 27, 2016, 3:05:03 AM6/27/16
to django...@googlegroups.com
As an afterthought, I wonder why my misspelling didn't cause an error instead of a "wrong" Template being used?

Any insights?


Not particularly. That should have caused an error. The only way it wouldn't have is if you have (or one of your installed apps has) a file named crudlist.htm inside of a folder named contacts. I'd be interested to see what the debug toolbar had to say while the typo was in place. 

As far as your question about template inheritance earlier, here is the link to the docs:


-James

I was unhappy with my own answer, so I did some digging. It looks like the typo worked accidentally "as designed".

A CBV (in this case inheriting from ListView) for model Foo, will return a default 'template_name' of 'foo_list.html'. What isn't necessarily obvious is that the value of 'template_name' is handled by the get_template_names() method:


The pluralized name of the method indicates that a list of template names are returned. If we look at the the code for MultipleObjectTemplateResponseMixin (which ListView inherits from at some point), we see what happens:


You'll see that a list is built that includes the value of 'template_name' (from TemplateResponseMixin) as well as the "generic" template name that is built using the app_label and model name (myapp/foo_list.html), so something like ['crudview.html', 'contact/contact_list.html'] in your case. 

Since the typo existed and you were using CBV's, Django simply moved on to the next available name in the list of templates, which happened to be added automatically as part of the CBV process, and happened to match the name of the template you were using as the baseline for your tests.

Hope that clears it up.

-James
Reply all
Reply to author
Forward
0 new messages