Django - 表单处理
Django - 表单处理
Section titled “Django - 表单处理”处理 HTML 表单是 Web 开发的基本组成部分。Django 提供了一个强大的表单库(django.forms),用于处理将表单渲染为 HTML、验证提交的数据,并将这些数据转换为 Python 类型。
在 Django 中创建表单类似于创建模型(Model)。你定义一个继承自 forms.Form(如果表单直接映射到模型,则继承自 forms.ModelForm)的类。类的属性代表表单字段(form fields)。
我们来创建一个简单的登录表单。在你的 myapp 文件夹中创建一个 forms.py 文件:
from django import forms
class LoginForm(forms.Form): username = forms.CharField(max_length=100, required=True) password = forms.CharField(widget=forms.PasswordInput(), required=True)这里:
LoginForm继承自forms.Form。username是一个CharField(字符字段),代表一个文本输入。password也是一个CharField,但我们使用PasswordInputwidget(小部件)来将其渲染为 HTML 中的<input type=“password”>,以隐藏输入内容。max_length提供了基本验证。required=True表示该字段不能为空。- Django 提供了许多字段类型(如
EmailField、IntegerField、BooleanField等)和 widget(如Textarea、CheckboxInput、Select等)。请参阅 Django 表单字段 和 widget 文档。
在视图(View)中使用表单
Section titled “在视图(View)中使用表单”视图(View)处理显示和处理表单的逻辑。常见的模式是在同一个视图中处理 GET(显示空表单)和 POST(处理提交的数据)请求。
我们在 myapp/views.py 中创建一个 login_view:
from django.shortcuts import render, redirectfrom .forms import LoginForm# Assuming you have some authentication logic# 假设你有一些认证逻辑# from django.contrib.auth import authenticate, login as auth_login
def login_view(request): if request.method == 'POST': form = LoginForm(request.POST) if form.is_valid(): username = form.cleaned_data['username'] password = form.cleaned_data['password'] # # *** Add authentication logic here! *** # *** 在此处添加认证逻辑! *** # Example (requires django.contrib.auth setup): # 示例(需要设置 django.contrib.auth): # user = authenticate(request, username=username, password=password) # if user is not None: # auth_login(request, user) # return redirect('home') # Redirect to a success page # return redirect('home') # 重定向到成功页面 # else: # # Handle invalid login (e.g., add form error) # # 处理无效登录(例如,添加表单错误) # form.add_error(None, 'Invalid username or password.') # # For this simple example, we'll just render a success page # 对于这个简单的示例,我们只渲染一个成功页面 return render(request, 'myapp/loggedin.html', {'username': username}) # If form is invalid, render the page with the form and errors # 如果表单无效,使用包含表单和错误的页面重新渲染 else: # GET request # GET 请求 form = LoginForm()
return render(request, 'myapp/login.html', {'form': form})解释:
- 如果
request.method是 ‘POST’,我们使用提交的数据(request.POST)实例化表单。 form.is_valid()触发验证。它检查字段要求(如required=True)并运行任何自定义验证方法。- 如果有效,数据将在
form.cleaned_data中可用,这是一个包含已验证 Python 对象的字典。 - 重要: 上述示例缺少真实的认证。在实际应用中,你会在此时使用
django.contrib.auth.authenticate和login。 - 如果表单无效,或者如果是 GET 请求,我们会实例化一个空表单(
LoginForm()),或者重新渲染已绑定数据的表单(该表单现在包含错误消息)。 - 我们将
form对象传递给模板上下文(template context)。
创建模板(Template)
Section titled “创建模板(Template)”我们需要两个模板:一个用于显示表单(login.html),一个用于成功消息(loggedin.html)。
myapp/templates/myapp/login.html 文件内容:
<!-- myapp/templates/myapp/login.html --><!DOCTYPE html><html><head> <title>Login</title> <style> .errorlist { color: red; list-style-type: none; padding-left: 0; } label { display: block; margin-top: 10px; } </style></head><body> <h2>Login</h2> <h2>登录</h2> <form method="post"> {% csrf_token %}
{{ form.non_field_errors }}
<div> {{ form.username.label_tag }} {{ form.username }} {{ form.username.errors }} </div>
<div> {{ form.password.label_tag }} {{ form.password }} {{ form.password.errors }} </div>
<br> <button type="submit">Login</button> <button type="submit">登录</button> </form></body></html>关键模板元素:
<form method=“post”>:指定 HTTP 方法。{% csrf_token %}:重要的安全标签,用于防止跨站请求伪造(Cross-Site Request Forgery,CSRF)攻击。Django 中间件(middleware)会在 POST 请求时检查此令牌(token)。{{ form.as_p }}或{{ form.as_ul }}或{{ form.as_table }}:Django 提供的快捷方式,分别将表单字段渲染并包裹在<p>、<li>或<tr><td>标签中。- 手动字段渲染(如上所示):提供了更多控制。
{{ form.fieldname.label_tag }}、{{ form.fieldname }}、{{ form.fieldname.errors }}分别渲染特定字段的标签(label)、输入 widget 和验证错误。 {{ form.non_field_errors }}显示不与特定字段关联的错误(例如,来自form.add_error(None, …)的错误)。
myapp/templates/myapp/loggedin.html 文件内容:
<!-- myapp/templates/myapp/loggedin.html --><!DOCTYPE html><html><head> <title>Logged In</title> <title>已登录</title></head><body> <p>Welcome, **{{ username }}**! (Login successful - demo only)</p> <p>欢迎, **{{ username }}**! (登录成功 - 仅为演示)</p></body></html>URL 配置
Section titled “URL 配置”在 myapp/urls.py 中将 URL 映射到视图:
from django.urls import pathfrom . import views
urlpatterns = [ path('login/', views.login_view, name='login'), # Add other app URLs here # 在此处添加其他应用(app)的 URL]确保你的主项目 urls.py 包含了此 myapp/urls.py。
运行开发服务器(python manage.py runserver)并导航到 /myapp/login/(或者你配置的任何 URL)。
你应该会看到登录表单。尝试提交:
- 字段为空时:Django 的
required=True验证应该会触发,在字段旁边显示错误。 - 提交有效数据时:你应该被重定向到
loggedin.html(或看到其内容)。 - 登录详细信息不正确时(如果你实现了认证):你会再次看到表单,并显示一个非字段错误消息。
你可以通过定义以 clean_ 开头后跟字段名的方法,或者定义一个通用的 clean() 方法,来为你的表单类添加自定义验证逻辑。
示例:确保用户名不是 ‘admin’。
from django import formsfrom django.core.exceptions import ValidationError
class LoginForm(forms.Form): username = forms.CharField(max_length=100, required=True) password = forms.CharField(widget=forms.PasswordInput(), required=True)
def clean_username(self): data = self.cleaned_data['username'] if data.lower() == 'admin': raise ValidationError("Admin username is not allowed.") # 管理员用户名不允许。 return data # Always return the cleaned data # 总是返回已清理的数据
# Example clean() method for cross-field validation # clean() 方法示例,用于跨字段验证 # def clean(self): # cleaned_data = super().clean() # # Add validation that depends on multiple fields # # 添加依赖于多个字段的验证逻辑 # return cleaned_data如果某个验证方法抛出 ValidationError,表单的 is_valid() 将返回 False,并且错误消息将与该字段关联(如果在 clean() 中抛出且未指定字段,则通过 non_field_errors 显示)。
进一步阅读:Django 表单文档