Hi together,
I’ve started to build a Django project using a virtual environment (venv).
Currently I am working through the different ways of creating forms - from low-level (without any Form classes) to using Form and ModelForm.
But as soon as I implement a form snippet as described in Reusable form templates of the Working with forms topic in Django 4.0, I am facing the following error.
If I use no form templates, this error does not happen (described below - working setup 1).
And the error doesn’t occur, if I use the Resusable form templates approach from Django 3.2 (described below - working setup 2).
Both working setups render the same way, without any issues.
Therefore I was wondering whether this issue is being caused by the changes in Django 4.0
Error in debug window (when using Django 4.0 approach)
TemplateDoesNotExist at /codermatch/create-ad/
codermatch/formSnippet.html
Request Method: GET
Request URL: http://localhost:8000/codermatch/create-ad/
Django Version: 4.0.1
Exception Type: TemplateDoesNotExist
Exception Value: codermatch/formSnippet.html
Exception Location: C:\Users\Name\codingprojects\CoderMatching\venv\lib\site-packages\django\template\backends\django.py, line 84, in reraise
Python Executable: C:\Users\Name\codingprojects\CoderMatching\venv\Scripts\python.exe
Python Version: 3.9.7
Python Path:
['C:\\Users\\Name\\codingprojects\\CoderMatching\\codermatching',
'C:\\Program Files\\Python39\\python39.zip',
'C:\\Program Files\\Python39\\DLLs',
'C:\\Program Files\\Python39\\lib',
'C:\\Program Files\\Python39',
'C:\\Users\\Name\\codingprojects\\CoderMatching\\venv',
'C:\\Users\\Name\\codingprojects\\CoderMatching\\venv\\lib\\site-packages']
The Template-loader postmortem looks like:
Django tried loading these templates, in this order:
Using engine django:
django.template.loaders.filesystem.Loader: C:\Users\Name\codingprojects\CoderMatching\venv\lib\site-packages\django\forms\templates\codermatch\formSnippet.html (Source does not exist)
django.template.loaders.app_directories.Loader: C:\Users\Name\codingprojects\CoderMatching\venv\lib\site-packages\django\contrib\admin\templates\codermatch\formSnippet.html (Source does not exist)
django.template.loaders.app_directories.Loader: C:\Users\Name\codingprojects\CoderMatching\venv\lib\site-packages\django\contrib\auth\templates\codermatch\formSnippet.html (Source does not exist)
I don’t understand why Django trys to look up the template snippet in the venv.
Because for all the templates, which I specified in the render() methods of my views.py functions, Django looks for them in the project directories templates - hence they work as expected.
The debug windows specifies the Error during template rendering as follows:
In template C:\Users\Name\codingprojects\CoderMatching\codermatching\templates\codermatch\createAd.html, error at line 6
codermatch/formSnippet.html
1 {% extends 'base.html' %}
2
3 {% block main %}
4 <form action="{% url 'codermatch:createAd' %}" method="post">
5 {% csrf_token %}
6 {{ form }}
7 <input type="submit" name="submit-ad" id="submit-ad" value="Create Ad">
8 </form>
9 {% endblock main %}
The error occurs with the following setup:
error setup
- using the Reusable form templates of Django 3.2 (almost the same as working setup 2)
basic form (+ template_name property) in forms.py:
class createAdForm(forms.Form):
template_name = "codermatch/formSnippet.html"
projectTitle = forms.CharField(label='project title', max_length=100)
creatorName = forms.CharField(label='creator name', max_length=50)
projectDescription = forms.CharField(label='project description', max_length=1500)
contactDetails = forms.CharField(label='contact details', max_length=300)
projectStartDate = forms.DateField(label='project started (date)', widget=DateInput(attrs={'type': 'date'}), required=False)
views.py
def createAd(request):
"""
This view method enables to publish own individual ads on the page.
"""
# if POST request: process form data
if request.method == 'POST':
# create form instance + populate it with request data
form = createAdForm(request.POST)
# check if it's valid
if form.is_valid():
# process form.cleaned_data as required
newAd = Ad(projectTitle=form.cleaned_data['projectTitle'],
creatorName=form.cleaned_data['creatorName'],
projectDescription=form.cleaned_data['projectDescription'],
contactDetails=form.cleaned_data['contactDetails'],
projectStartDate=form.cleaned_data['projectStartDate'])
newAd.save()
# redirect to new URL:
return HttpResponseRedirect(reverse(viewname='codermatch:adDetail', args=(newAd.id,)))
# if it's a GET request: show the unpopulated form
elif request.method == 'GET':
form = createAdForm()
# if it's neither a POST, nor a GET request: send back to index page
else:
raise Http404('Only GET and POST requests are allowed')
return render(request=request, template_name='codermatch/createAd.html', context={'form': form})
createAd.html - based on Reusable form templates (Django 4.0):
{% extends 'base.html' %}
{% block main %}
<form action="{% url 'codermatch:createAd' %}" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" name="submit-ad" id="submit-ad" value="Create Ad">
</form>
{% endblock main %}
formSnippet.html
{{ form.as_p }}
The form works without any errors in the following cases:
working setup 1
- not using form snippets to display my form (hence no template_name property in my createAdForm)
basic form in a forms.py of app directory, like this (no template_name property):
class createAdForm(forms.Form):
projectTitle = forms.CharField(label='project title', max_length=100)
creatorName = forms.CharField(label='creator name', max_length=50)
projectDescription = forms.CharField(label='project description', max_length=1500)
contactDetails = forms.CharField(label='contact details', max_length=300)
projectStartDate = forms.DateField(label='project started (date)', widget=DateInput(attrs={'type': 'date'}), required=False)
views.py is the same as in error setup (see above)
createAd.html
{% extends 'base.html' %}
{% block main %}
<form action="{% url 'codermatch:createAd' %}" method="post">
{% csrf_token %}
{{ form.as_p }} # also working with {{ form }} only
<input type="submit" name="submit-ad" id="submit-ad" value="Create Ad">
</form>
{% endblock main %}
working setup 2
- using the Reusable form templates of Django 3.2 (instead of 4.0)
forms.py: same as in error setup (see above)
views.py: same as in error setup (see above)
createAd.html - based on Reusable form templates (Django 3.2):
{% extends 'base.html' %}
{% block main %}
<form action="{% url 'codermatch:createAd' %}" method="post">
{% csrf_token %}
{% include 'codermatch/formSnippet.html' %}
<input type="submit" name="submit-ad" id="submit-ad" value="Create Ad">
</form>
{% endblock main %}
formSnippet.html: same as in error setup (see above)
general settings
In both working setups I’ve the following settings.py:
INSTALLED_APPS = [
'codermatch', #this works because the name is defined in codermatch.apps.CodermatchConfig
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates' #alternative with same meaning: os.path.join(BASE_DIR, 'templates')
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
Solution approaches:
-
Error message misleading? Hence nonsense in formSnippet.html?
https://stackoverflow.com/a/43174094
- This shouldn’t be the issue, since the Django 3.2 approach works with the formSnippet.html, right?
-
app not correctly configured in INSTALLED-APPS
https://stackoverflow.com/a/63205788
- I don’t think so
-
Wrong TEMPLATES setup in settings.py
→ I don’t think so
Questions
- Why does Django look for the snippets in the venv, when using the Django 4.0 approach?
- Is this issue being caused by the changes in Django 4.0?