Kiet Tran
Kiet Tran

Reputation: 1538

Django template loader behavior? (got Django TemplateDoesNotExist exception)

Folder Structure

I'm currently learning Django from the Django book. I have the following directory structure:

.
└── mysite
    ├── books
    │   ├── __init__.py
    │   ├── models.py
    │   ├── templates
    │   │   ├── search_form.html
    │   │   └── search_results.html
    │   ├── tests.py
    │   └── views.py
    ├── contact
    │   ├── forms.py
    │   ├── __init__.py
    │   ├── templates
    │   │   └── contact_form.html
    │   └── views.py
    ├── manage.py
    └── mysite
        ├── __init__.py
        ├── settings.py
        ├── templates
        │   ├── base.html
        │   ├── current_datetime.html
        │   └── hours_ahead.html
        ├── urls.py
        ├── views.py
        └── wsgi.py

Where books, contact, and mysite are folders. I also have a separate templates subfolder for each of those folders to store templates.

Story

Now, inside /mysite/settings.py, I have the following lines:

TEMPLATE_DIRS = (
    os.path.join(os.path.dirname(__file__), 'templates').replace('\\', '/'),
)

Inside /contact/views.py, I have the following line (note that render here is from django.shortcuts):

return render(request, 'contact_form.html', {'form': form})

However, the line above gives me a TemplateDoesNotExist exception. This is because the template loader looks for the file contact_form.html under /mysite/templates/ instead of /contact/templates/.

Fair enough, even though I don't understand why that's the case. But, I have another case where it behaves differently.

Recall in the file structure above, I also have books/views.py. In it, I have the following lines (in different logical blocks):

return render(request, 'search_results.html',
                {'books': books, 'query': q})

and

return render(request, 'search_form.html', {'errors': errors})

If you look back above, search_results.html and search_form.html are under the /books/templates/ folder, not /mysite/templates/ folder, and yet the template loader managed to find those files. Note that it still works even when I move search_results.html and search_form.html into /mysite/templates/.

So my question is, why is there a difference in where the loader looks for templates?

Files

Anyway, here's what my /contact/views.py looks like:

from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.core.mail import send_mail
from forms import ContactForm
import os

def contact(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
            cd = form.cleaned_data
            send_mail(
                    cd['subject'],
                    cd['message'],
                    cd.get('email', '[email protected]'),
                    ['[email protected]'],
            )
            return HttpResponseRedirect('/contact/thanks/')
    else:
        form = ContactForm()
    print os.path.join(os.path.dirname(__file__), 'templates')
    return render(request, 'contact_form.html', {'form': form})

Here's my /books/views.py:

from django.shortcuts import render
from django.http import HttpResponse
from books.models import Book


def search(request):
    errors = []
    if 'q' in request.GET:
        q = request.GET['q']
        if not q:
            errors.append('Enter a search term.')
        elif len(q) > 20:
            errors.append('Please enter at most 20 characters.')
        else:
            books = Book.objects.filter(title__icontains=q)
            return render(request, 'search_results.html',
                {'books': books, 'query': q})
    return render(request, 'search_form.html', {'errors': errors})

Upvotes: 2

Views: 1265

Answers (1)

Since you apparently do have the app directories template loader installed, and since it works on your books app, I can only conclude you don't have contact in settings.INSTALLED_APPS.

Upvotes: 6

Related Questions