Django-HTMX集成报错:'WSGIRequest'对象无'get'属性
Django + HTMX 提交联系表单触发 AttributeError 问题
错误详情
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
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(表单处理视图)
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(主页视图)
def home(request): form = Contact_Us_Form() return render(request, 'pages/home.html', {'form': form})
Urls.py
urlpatterns = [ path("", include('dashboard.urls')), # 主页通过dashboard应用的urls.py渲染 path('contactus', Contact_Us_Form, name="contact"), ]
home.html(主页表单代码)
<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 Google Privacy Policy and Terms Of Service apply.</p> </div> <div class="d-flex justify-content-end"> <button type="submit" class="btn btn-secondary w-20">Submit</button> </div> </form>
排查过程
- 在views.py中添加GET场景分支处理
- 尝试添加/移除表单的method="POST"和action="contacts"属性,无效
- 尝试将
form = Contact_Us_Form(request.POST)改为form = Contact_Us_Form(data = request.POST),无效 - 检查网络请求载荷与头信息,确认请求方法为POST且包含预期字段
- 尝试添加/移除CSRF引用,确认非CSRF问题
解决方案
1. 修复URL路由的核心错误
问题出在Urls.py中,你把表单类Contact_Us_Form直接绑定到了路由上,而不是对应的视图函数contact_us_response。Django路由需要接收视图函数(或类视图),当你传入表单类时,Django会把请求对象request当作表单的初始化参数传入,导致表单内部的self.data变成了WSGIRequest对象,而不是预期的POST数据字典,最终调用data.get()时触发AttributeError。
修改Urls.py:
# 先确保导入了视图函数 from .views import contact_us_response urlpatterns = [ path("", include('dashboard.urls')), path('contactus', contact_us_response, name="contact"), # 替换为视图函数 ]
2. 修正表单提交后的跳转逻辑
当前视图中redirect("partials/success.html")是错误的,redirect()接收的是URL名称或者完整URL,不是模板路径。你需要先为成功页面添加路由,或者返回一个HTMX能替换的成功片段。
示例:创建success.html片段,然后返回渲染后的内容:
if form.is_valid(): # 这里可以添加表单数据处理逻辑,比如发送邮件等 return render(request, "partials/success.html")
3. 完善模板中的CSRF防护
HTMX需要CSRF令牌才能正常提交POST请求,确保模板中包含CSRF令牌:
在home.html的表单内添加:
{% csrf_token %}
修改后的表单:
<form id="contact-us-form" hx-post="{% url 'contact' %}" hx-target="#contact-us-form"> {% csrf_token %} {{ form }} <button type="submit" class="btn btn-secondary w-20">Submit</button> </form>
4. 优化表单验证失败的响应
当表单验证失败时,应该返回带错误信息的表单片段,而不是简单的文本,这样HTMX可以替换原表单显示错误:
if form.is_valid(): return render(request, "partials/success.html") else: return render(request, "partials/contact.html", {"form": form})
内容的提问来源于stack exchange,提问作者Heartthrob_Rob
相关产品推荐
相关产品推荐

