当前位置:首页 > 技术 > 正文内容

Django表单渲染与处理详解

访客 技术 2026年6月8日 1

登录页面示例:GET与POST请求

以一个登录页面为例,我们可以看到两种常见的HTTP请求方式在表单处理中的应用。

GET方式:用于页面加载

当用户首次访问登录页面时,通常使用GET请求来获取页面内容。在这种情况下,表单的渲染不一定需要form组件,但表单字段的name属性应与后续POST请求中用于解析数据的键名保持一致。

POST方式:用于数据提交

当用户填写完表单并点击提交按钮时,使用POST请求将用户输入的数据发送到服务器。服务器端接收这些数据,进行验证和处理。

视图函数(views.py)


from django.shortcuts import render, HttpResponse, redirect
from app01.models import UserInfo # 假设UserInfo模型已定义

def handle_login(request):
    if request.method == "POST":
        user_name = request.POST.get('username')
        pass_word = request.POST.get('password')
        
        # 模拟用户验证
        user_query = UserInfo.objects.filter(username=user_name, password=pass_word)
        if user_query:
            # 登录成功,设置session并重定向
            request.session['logged_in_user'] = user_name
            return HttpResponse('欢迎登录系统!')
        else:
            return HttpResponse('用户名或密码错误!')

    # GET请求,渲染登录页面
    return render(request, 'login.html', locals())
    

登录页面模板(login.html)


<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>用户登录</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
    <script src="/static/jquery-3.2.1.min.js"></script>
    <script src="/static/bootstrap/js/bootstrap.js"></script>
    <style>
        form { margin-top: 100px; }
        .btn { display: block; margin-left: auto; margin-right: auto; }
    </style>
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-md-4 col-md-offset-4">
            <form action="/login/" method="post" class="center-block">
                {% csrf_token %}
                <div class="form-group">
                    <label for="username_input">用户名:</label>
                    <input type="text" class="form-control" id="username_input" name="username" required>
                </div>

                <div class="form-group">
                    <label for="password_input">密码:</label>
                    <input type="password" class="form-control" id="password_input" name="password" required>
                </div>

                <div class="form-group">
                    <input type="submit" class="btn btn-primary" value="登录">
                </div>
            </form>
        </div>
    </div>
</div>
</body>
</html>
    

使用Django Forms进行表单渲染与验证

Django的Forms库提供了更强大、更规范的方式来创建、渲染和验证表单。

自定义表单类

我们可以定义一个继承自django.forms.Form的类,来声明表单字段及其属性。

视图函数(views.py)


from django.shortcuts import render, HttpResponse
from django import forms
from django.forms import widgets
from app01.models import UserInfo, Sex, Account # 假设模型已定义

class RegistrationForm(forms.Form):
    user_name = forms.CharField(
        max_length=12,
        min_length=6,
        label='用户名',
        widget=widgets.TextInput(attrs={'class': "form-control", 'id': 'user_name_field'})
    )
    pass_word = forms.CharField(
        min_length=6,
        max_length=12,
        label='密码',
        widget=widgets.PasswordInput(attrs={'class': 'form-control', 'id': 'password_field'})
    )
    gender_choice = forms.ChoiceField(
        choices=Sex.objects.all().values_list('id', 'sex'), # 从数据库动态获取选项
        label="性别",
        initial=lambda: Sex.objects.get(sex="保密").id if Sex.objects.filter(sex="保密").exists() else 1, # 设置默认值
        widget=forms.widgets.RadioSelect
    )

def register(request):
    error_message = ""
    form_instance = RegistrationForm()

    if request.method == "POST":
        form_instance = RegistrationForm(request.POST)
        if form_instance.is_valid():
            # cleaned_data 包含了经过验证的、清洗过的数据
            input_username = form_instance.cleaned_data.get("user_name")
            input_password = form_instance.cleaned_data.get("pass_word")
            selected_gender_id = form_instance.cleaned_data.get('gender_choice')
            
            # 创建新用户记录
            Account.objects.create(name=input_username, pwd=input_password, Tosex_id=selected_gender_id)
            return HttpResponse('注册成功!')
        else:
            # 表单验证失败,可以在这里处理错误信息
            error_message = "表单验证失败,请检查输入。"

    return render(request, "registration.html", {"form_obj": form_instance, "error_msg": error_message})
    

注册页面模板(registration.html)


<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
    <title>用户注册</title>
    <style>
        .error-text { color: red; }
        #form-container {
            height: 300px;
            position: absolute;
            margin-top: -150px;
            top: 50%;
        }
    </style>
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-md-6 col-md-offset-3" id="form-container">
            <form action="" method="post" novalidate>
                {% csrf_token %}

                <!-- 用户名字段渲染 -->
                <div class="form-group">
                    <label for="{{ form_obj.user_name.id_for_label }}" class="control-label">{{ form_obj.user_name.label }}</label>
                    <div>
                        {{ form_obj.user_name }}
                        {% if form_obj.user_name.errors %}
                            <span class="error-text">{{ form_obj.user_name.errors.0 }}</span>
                        {% endif %}
                    </div>
                </div>

                <!-- 密码字段渲染 -->
                <div class="form-group">
                    <label for="{{ form_obj.pass_word.id_for_label }}" class="control-label">{{ form_obj.pass_word.label }}</label>
                    <div>
                        {{ form_obj.pass_word }}
                        {% if form_obj.pass_word.errors %}
                            <span class="error-text">{{ form_obj.pass_word.errors.0 }}</span>
                        {% endif %}
                    </div>
                </div>

                <!-- 性别选择字段渲染 -->
                <div class="form-group">
                    <label class="control-label">{{ form_obj.gender_choice.label }}</label>
                    <div>
                        {{ form_obj.gender_choice }}
                        {% if form_obj.gender_choice.errors %}
                            <span class="error-text">{{ form_obj.gender_choice.errors.0 }}</span>
                        {% endif %}
                    </div>
                </div>
                
                <!-- 提交按钮与全局错误信息 -->
                <div class="form-group">
                    <input type="submit" class="btn btn-primary" value="注册">
                    {% if error_msg %}
                        <span class="error-text">{{ error_msg }}</span>
                    {% endif %}
                </div>
            </form>
        </div>
    </div>
</div>

<script src="/static/jquery-3.2.1.min.js"></script>
<script src="/static/bootstrap/js/bootstrap.js"></script>
</body>
</html>
    

使用ModelForm简化模型表单

当表单字段与数据库模型一一对应时,可以使用ModelForm来自动生成表单,大大减少代码量。

ModelForm定义

通过在内部类Meta中指定modelfields,可以快速创建一个基于模型的表单。

视图函数(views.py)


from django.shortcuts import render, HttpResponse, redirect
from django.forms import ModelForm
from django.forms import widgets as form_widgets
from app01.models import Book, UserInfo # 假设Book和UserInfo模型已定义

class BookForm(ModelForm):
    class Meta:
        model = Book
        fields = '__all__' # 或者指定 ['title', 'price', 'publisher', 'authors']
        widgets = {
            'title': form_widgets.TextInput(attrs={'class': 'form-control'}),
            'price': form_widgets.NumberInput(attrs={'class': 'form-control'}), # 使用NumberInput更合适
            'publisher': form_widgets.Select(attrs={'class': 'form-control'}),
            'authors': form_widgets.SelectMultiple(attrs={'class': 'form-control'})
        }
        # 可以自定义字段标签
        labels = {
            'title': '书名',
            'price': '价格',
            'publisher': '出版社',
            'authors': '作者'
        }

class LoginForm(ModelForm):
    class Meta:
        model = UserInfo
        fields = ['username', 'password'] # 只包含需要的字段
        widgets = {
            'username': form_widgets.TextInput(attrs={'class': 'form-control', 'placeholder': '请输入用户名'}),
            'password': form_widgets.PasswordInput(attrs={'class': 'form-control', 'placeholder': '请输入密码'})
        }
        labels = {
            'username': '用户名',
            'password': '密码'
        }

# 假设 book_list, add, delete, edit 是处理图书相关操作的视图函数
# ... (省略book_list, add, delete, edit函数的详细实现) ...

def login_view(request):
    if request.method == "POST":
        user_input_form = LoginForm(request.POST)
        if user_input_form.is_valid():
            user_name = user_input_form.cleaned_data.get('username')
            pass_word = user_input_form.cleaned_data.get('password')
            
            # 验证用户
            user_exists = UserInfo.objects.filter(username=user_name, password=pass_word).first()
            if user_exists:
                request.session['current_user'] = user_name
                return redirect('/book_list/') # 重定向到图书列表页
            else:
                # 登录失败,可以在form_login中添加错误信息
                pass 
    else:
        user_input_form = LoginForm() # GET请求,创建空表单

    return render(request, 'login_form_page.html', {'login_form_obj': user_input_form})

def add_book_view(request):
    if request.method == 'POST':
        book_creation_form = BookForm(request.POST)
        if book_creation_form.is_valid():
            book_creation_form.save() # 直接保存到数据库
            return redirect('/book_list/')
    else:
        book_creation_form = BookForm()
    return render(request, 'add_book_page.html', {'book_form_instance': book_creation_form})

# ... 其他视图函数 ...
    

登录页面模板(login_form_page.html)


<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>ModelForm 登录</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
    <style>
        form { margin-top: 100px; }
    </style>
</head>
<body>
<script src="/static/jquery-3.2.1.min.js"></script>
<script src="/static/bootstrap/js/bootstrap.js"></script>

<div class="container">
    <div class="row">
        <div class="col-md-4 col-md-offset-4">
            <form action="" method="post">
                {% csrf_token %}
                <div class="form-group">
                    <label for="{{ login_form_obj.username.id_for_label }}">{{ login_form_obj.username.label }}</label>
                    {{ login_form_obj.username }}
                    {% if login_form_obj.username.errors %}<span class="error-text">{{ login_form_obj.username.errors.0 }}</span>{% endif %}
                </div>

                <div class="form-group">
                    <label for="{{ login_form_obj.password.id_for_label }}">{{ login_form_obj.password.label }}</label>
                    {{ login_form_obj.password }}
                     {% if login_form_obj.password.errors %}<span class="error-text">{{ login_form_obj.password.errors.0 }}</span>{% endif %}
                </div>

                <input type="submit" class="btn btn-primary btn-block" value="登录">
            </form>
        </div>
    </div>
</div>
</body>
</html>
    

添加图书页面模板(add_book_page.html)


<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>添加图书</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
    <style>
        form { margin-top: 50px; }
    </style>
</head>
<body>

<script src="/static/jquery-3.2.1.min.js"></script>
<script src="/static/bootstrap/js/bootstrap.js"></script>

<div class="container">
    <div class="row">
        <div class="col-md-6 col-md-offset-3">
            <h2 class="text-center">添加新图书</h2>
            <form action="" method="post" enctype="multipart/form-data"> <!-- 如果有文件上传,需要 enctype -->
                {% csrf_token %}
                
                {% for field in book_form_instance %}
                    <div class="form-group">
                        <label for="{{ field.id_for_label }}">{{ field.label }}</label>
                        {{ field }}
                        {% if field.errors %}
                            <span class="error-text">{{ field.errors.0 }}</span>
                        {% endif %}
                        {% if field.help_text %}
                            <small class="form-text text-muted">{{ field.help_text }}</small>
                        {% endif %}
                    </div>
                {% endfor %}
                
                <input type="submit" class="btn btn-success btn-block" value="保存图书">
            </form>
        </div>
    </div>
</div>
</body>
</html>
    

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。