Reputation: 1538
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
Reputation: 118508
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