I’m building a homepage that includes a contact-us form. This contact-us form element should be reusable across multiple pages, so I’ve used HTMX to try incorporate. However am receiving the following error, which I can’t make sense of because I’m submitting POST data.
Request Method: POST
Request URL: http://localhost:8000/contactus
Django Version: 4.2.13
Python Version: 3.9.6
Installed Applications:
['django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'debug_toolbar',
'accounts',
'dashboard']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'debug_toolbar.middleware.DebugToolbarMiddleware']
Traceback (most recent call last):
File "/Users/robrobrob/Desktop/Projects/Trolleys/venv/lib/python3.9/site-packages/django/core/handlers/exception.py", line 55, in inner
response = get_response(request)
File "/Users/robrobrob/Desktop/Projects/Trolleys/venv/lib/python3.9/site-packages/django/core/handlers/base.py", line 220, in _get_response
response = response.render()
File "/Users/robrobrob/Desktop/Projects/Trolleys/venv/lib/python3.9/site-packages/django/forms/utils.py", line 67, in render
context = context or self.get_context()
File "/Users/robrobrob/Desktop/Projects/Trolleys/venv/lib/python3.9/site-packages/django/forms/forms.py", line 322, in get_context
top_errors = self.non_field_errors().copy()
File "/Users/robrobrob/Desktop/Projects/Trolleys/venv/lib/python3.9/site-packages/django/forms/forms.py", line 358, in non_field_errors
return self.errors.get(
File "/Users/robrobrob/Desktop/Projects/Trolleys/venv/lib/python3.9/site-packages/django/forms/forms.py", line 196, in errors
self.full_clean()
File "/Users/robrobrob/Desktop/Projects/Trolleys/venv/lib/python3.9/site-packages/django/forms/forms.py", line 433, in full_clean
self._clean_fields()
File "/Users/robrobrob/Desktop/Projects/Trolleys/venv/lib/python3.9/site-packages/django/forms/forms.py", line 440, in _clean_fields
value = bf.initial if field.disabled else bf.data
File "/Users/robrobrob/Desktop/Projects/Trolleys/venv/lib/python3.9/site-packages/django/forms/boundfield.py", line 135, in data
return self.form._widget_data_value(self.field.widget, self.html_name)
File "/Users/robrobrob/Desktop/Projects/Trolleys/venv/lib/python3.9/site-packages/django/forms/forms.py", line 220, in _widget_data_value
return widget.value_from_datadict(self.data, self.files, html_name)
File "/Users/robrobrob/Desktop/Projects/Trolleys/venv/lib/python3.9/site-packages/django/forms/widgets.py", line 297, in value_from_datadict
return data.get(name)
Exception Type: AttributeError at /contactus
Exception Value: 'WSGIRequest' object has no attribute 'get'
** Forms.py **
This file contains the form logic
class Contact_Us_Form(forms.Form):
name = forms.CharField(
label="Name",
max_length=60,
widget=forms.TextInput(attrs={'class': 'form-control'})
)
sender = forms.EmailField(
widget=forms.TextInput(attrs={'class': 'form-control'}),
label="Email"
)
message_content = forms.CharField(
widget=forms.Textarea(attrs={'class': 'form-control'}),
label="Your message"
)
** Views.py **
for the form element
def contact_us_response(request):
if request.method == "POST":
form = Contact_Us_Form(data=request.POST)
if form.is_valid():
return redirect("partials/success.html")
else:
return HttpResponse("Something's broke")
elif request.method == "GET":
form = Contact_Us_Form()
return render(request, "partials/contact.html", {"form": form})
else:
form = Contact_Us_Form()
return HttpResponse("Method not allowed", status=405)
** Views.py **
for the homepage
def home(request):
form = Contact_Us_Form()
return render(request, 'pages/home.html', {'form': form})
** Urls.py **
urlpatterns = [
path("", include('dashboard.urls')), # the homepage is rendered via separate urls.py on the 'dashboard' app's urls.py
path('contactus', Contact_Us_Form, name="contact"),
]
** home.html relevant section from homepage **
<form id="contact-us-form" hx-post="{% url 'contact' %}" hx-target="#contact-us-form">
{{ form }}
<button type="submit" class="btn btn-secondary w-20" >Submit</button>
</form>
** contact.html **
<form>
<div class="mb-3">
<label for="name" class="form-label d-inline">Name <p class="text-secondary d-inline">*</p></label>
{{ form.name }}
</div>
<div class="mb-3">
<label for="email" class="form-label">Email <p class="text-secondary d-inline">*</p></label>
{{ form.sender }}
</div>
<div class="mb-3">
<label for="message" class="form-label">How can we help you? <p class="text-secondary d-inline">*</p></label>
{{ form.message_content }}
<p class="small text-secondary">We'll hold your details in accordance with our Privacy Policy.
This site is protected by reCAPTCHA and the <a href="https://policies.google.com/privacy">Google Privacy Policy</a> and <a href="https://policies.google.com/terms">Terms Of Service</a> apply.</p>
</div>
<div class="d-flex justify-content-end">
<button type="submit" class="btn btn-secondary w-20">Submit</button>
</div>
</form>
My troubleshooting process
Don’t understand why POST data is throwing a GET error. Also don’t really understand how WSGI is coming into this picture. It looks like similar errors have been raised on SO before without resolution.
- Added if/else handling for GET scenarios in the views.py
- Added (and removed)
method="POST"andaction="contacts"to override this behaviour. No success - Tried changing
form = Contact_Us_Form(request.POST)intoform = Contact_Us_Form(data = request.POST). No success - Reviewed
networkinspect tab for payload and headers.Request Method = POSTand payload includes expected fields (name, sender, message content) - Added and removed
CSRFreferences throughout the document. This is not the source of the error
>Solution :
You should link the path to the view so contact_us_response, not the form (`):Contact_Us_Form
urlpatterns = [
path(
'', include('dashboard.urls')
), # the homepage is rendered via separate urls.py on the 'dashboard' app's urls.py
path('contactus', contact_us_response, name='contact'),
]