django中的forms组件(权限信息校验,增删改查)

1.用处

  1、用户请求数据验证

  2、自动生成错误信息    

  3、打包用户提交的正确信息

  4、如果其中有一个错误了,其他的正确,则保留上次输入的内容

  5、自动创建input标签并可以设置样式

  6.基于forms实现增删改查

2.使用方法

 对于注册信息进行校验

在应用下创建一个forms.py文件(起什么名无所谓,后面在视图函数中直接导入进来使用)

from django import forms
from django.forms import widgets
from django.core.exceptions import NON_FIELD_ERRORS, ValidationError

class UserInfo(forms.Form):
    username = forms.CharField(
        required=True,   # 标明是必填字段,不能为空
        min_length=4, max_length=12,
        label="姓名",     # 给定字段名称,直接把username换成了姓名
        error_messages={"required": "用户名不能为空!!"},
        widget=widgets.TextInput(attrs={"placeholder": "用户名", "class": "form-control"}) # 自动生成input框
    )

    password = forms.CharField(
        widget=widgets.PasswordInput(attrs={"placeholder":"密码","class":"form-control"}),
        label="密码",
    )

    sec_pwd = forms.CharField(
        required=True,
        label="二次密码",
        widget=widgets.PasswordInput(attrs={"placeholder":"二次密码","class":"form-control"})
    )

    age = forms.IntegerField(
        label="年龄",
        widget = widgets.NumberInput(attrs={"placeholder":"年龄","class":"form-control"}),
        error_messages={"required": "输入不对!!"},
    )

    email = forms.EmailField(
        widget=widgets.EmailInput(attrs={"placeholder":"邮箱","class":"form-control"}),
        label="邮箱",
        error_messages={"invalid": "格式错误"}
    )


    # 定制化二次错误信息

    # 局部钩子
    # 注意这里必须是以clean_  开头,可以查看源码,下面得到的val都是字符串类型
    def clean_username(self):
        val = self.cleaned_data.get("username")
        if not val.isdigit():
            return val
        else:
            raise ValidationError("用户名非纯数字")

    def clean_password(self):
        val = self.cleaned_data.get("password")
        if len(val) > 3:
            return val
        else:
            raise ValidationError("密码太短")

    def clean_age(self):
        val = self.cleaned_data.get("age")
        if int(val) > 18:
            return val
        else:
            raise ValidationError("岁数太小")


    # 全局钩子
    # 对于两次输入的密码进行校验是否一致
    def clean(self):
        password = self.cleaned_data.get("password")
        sec_pwd = self.cleaned_data.get("sec_pwd")
        if password == sec_pwd:
            return self.cleaned_data
        else:
            raise ValidationError("两次密码不一致")

  这个类到底干了什么事呢??你在解释器中打印就会发现,第一件事就是将自己显示成HTML。form对象做的第二件事就是来校验信息

  调用任何绑定form的is_valid()方法,就可以知道它的数据是否合法

  Django的form系统自动寻找匹配的函数方法,该方法名称以 clean_ 开头,并以字段名称结束。 如果有这样的方法,它将在校验时被调用。这属于一次额外校验

  如果存在异常,我们抛出一个 forms.ValidationError 型异常,这个异常的描述会被作为错误列表中的一项显示给用户

views.py

from django.shortcuts import render,HttpResponse
# Create your views here.
from app01.form import UserInfo


def index(request):
    # 定制化提示信息,
    if request.method=="POST":
        form = UserInfo(request.POST)
        # 如果全部输入信息有效
        if form.is_valid():
            return HttpResponse("添加成功")
        else:
            # 打印输入的信息
            print("---",form.cleaned_data)      # 得到一个字典
            print("???",form.errors)             # ErrorDict : {"校验错误的字段":["错误信息",]}
            print("!!!",form.errors.get("email"))   # ErrorList ["错误信息",]


            g_error = form.errors.get("__all__")
            print("+++",g_error)     # <ul class="errorlist nonfield"><li>两次密码不一致</li></ul>
            if g_error:
                g_error = g_error[0]   # 直接获取你自己的错误提示,即两次密码不一致
            
            return render(request, "index.html", locals())

    else:
        form = UserInfo()
        return render(request, "index.html", locals())

 这里form.py和创建的视图函数衔接关键点就在于 form = UserInfo(request.POST)

模板渲染:

方式一:

以p标签的样式展现出来,当然也能以能table标签展示

index.html

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .error {
            color: red;
        }
    </style>
    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.css">
</head>
<body>
<h3>注册用户</h3>
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            {# 这个novalidate很重要啊,没有这个后面自己定制的错误提示无法渲染出来 #}
            {# 自己编写表单验证插件的时候,使用它可以避免和默认的表单验证冲突 #}
            <form action="" method="post" novalidate>
                {% csrf_token %}
                {{ form.as_p }}
                <input type="submit">
           </form>
        </div>
    </div>
</div>

</body>
</html>

# 要注意这里form表单中添加的属性novalidate,它能够避免和默认的表单验证发生冲突

方式二:

书写相对麻烦

<form action="" method="post" novalidate>
      {% csrf_token %}
                <div>
                    <p>姓名</p>
                    {{ form.username }}
                </div>
                <div>
                    <p>密码</p>
                    {{ form.password }}
                </div>
                <div>
                    <p>二次密码</p>
                    {{ form.sec_pwd }}
                </div>
                <div>
                    <p>年龄</p>
                    {{ form.age }}
                </div>
                <div>
                    <p>年龄</p>
                    {{ form.email }}
                </div>
                <input type="submit">
    
 </form>

方式三(常用):

<form action="" method="post" novalidate>
        {% csrf_token %}
                {% for foo in form %}
                    <div class="form-group">
                        {# 渲染出lable标签,标签后面是输入框 #}
                        <lable>{{ foo.label }}</lable>{{ foo }}
                        {# 专门定制报错信息 #}
                        <span class="error pull-right">{{ foo.errors.0 }}</span>
                        {# 对于二次输入报错信息进行设置 #}
                        {% if foo.label == "二次密码" %}
                            <span class="error pull-right">{{ g_error|default_if_none:"" }}</span>
                        {% endif %}
                    </div>
                {% endfor %}
                <input type="submit" class="btn btn-default btn-sm">
            </form>

 3.基于forms组件的ModelForm实现的增删改查

models.py

from django.db import models

class Depart(models.Model):
    caption = models.CharField(max_length=32)

    def __str__(self):
        return self.caption
class Role(models.Model):
    title = models.CharField(max_length=32)

    def __str__(self):
        return self.title

class User(models.Model):

    name = models.CharField(verbose_name='姓名',max_length=32)
    depart = models.ForeignKey(verbose_name='部门',to='Depart',on_delete=models.CASCADE)

    gender_choices = (
        (1,''),
        (2,''),
    )
    gender = models.IntegerField(verbose_name='性别',choices=gender_choices,default=1)

    roles = models.ManyToManyField(verbose_name='角色',to='Role')

urls.py

from django.contrib import admin
from django.urls import path,re_path
from app01 import views
urlpatterns = [
    path('admin/', admin.site.urls),
    re_path('user/list/$', views.user_list),
    re_path('user/add/$', views.user_add),
    re_path('user/edit/(?P<uid>d+)/$', views.user_edit),
    re_path('user/del/(?P<uid>d+)/$', views.user_del),
]

views.py

from django.shortcuts import render,redirect
from app01 import models

def user_list(request):
    user_queryset = models.User.objects.all()
    return render(request,'user_list.html',{'user_queryset':user_queryset})


from django import forms
class UserForm(forms.ModelForm):
    class Meta:
        model = models.User
        fields = '__all__'
        # fields = ['name','depart']
        widgets = {
            'name':forms.TextInput(attrs={'class':'form-control'}),
            'depart':forms.Select(attrs={'class':'form-control'}),
            'gender':forms.Select(attrs={'class':'form-control'}),
            'roles':forms.SelectMultiple(attrs={'class':'form-control'}),
        }
        error_messages = {
            'name':{
                'required':'用户名不能为空'
            }
        }

def user_add(request):
    if request.method == "GET":
        form = UserForm()
    else:
        form = UserForm(request.POST)
        if form.is_valid():
            print('通过验证')
            form.save()
            return redirect('/user/list/')
    return render(request,'user_add.html',{'form':form})


def user_edit(request,uid):
    obj = models.User.objects.filter(id=uid).first()
    if request.method =='GET':
        form = UserForm(instance=obj)
        return render(request,'user_edit.html',{'form':form})
    else:
        form = UserForm(data=request.POST,instance=obj)
        if form.is_valid():
            form.save()
            return redirect('/user/list/')
        else:
            return render(request, 'user_edit.html', {'form': form})


def user_del(request,uid):
    models.User.objects.filter(id=uid).delete()
    return redirect('/user/list/')

 user_list.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container">
        <a href="/user/add/" class="btn btn-primary">添加</a>
        <table class="table table-bordered">
            <thead>
                <tr>
                    <th>名称</th>
                    <th>性别</th>
                    <th>部门</th>
                    <th>角色</th>
                    <th>操作</th>
                </tr>
            </thead>
            <tbody>
                {% for row in user_queryset %}
                    <tr>
                        <td>{{ row.name }}</td>
                        <td>{{ row.get_gender_display }}</td>
                        <td>{{ row.depart.caption }}</td>
                        <td>
                            {% for node in row.roles.all %}
                                <span>{{ node.title }}</span>
                            {% endfor %}
                        </td>
                        <td>
                            <a href="/user/edit/{{ row.id }}/">编辑</a>
                            <a href="/user/del/{{ row.id }}/">删除</a>
                        </td>
                    </tr>
                {% endfor %}
            </tbody>
        </table>
    </div>
</body>
</html>

 user_edit.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
     <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <h1>编辑用户</h1>
    <form method="post" novalidate>
        {% csrf_token %}
        {% for field in form %}
            <div>{{ field.label }}{{ field }} {{ field.errors.0 }}</div>
        {% endfor %}
        <input type="submit" value="提交">
    </form>
</body>
</html>

user_add.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
     <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container">
        <h1>添加用户</h1>
        <form method="post" class="form-horizontal" novalidate>
            {% csrf_token %}
            {% for field in form %}
                <div class="form-group">
                    <label class="col-sm-2 control-label">{{ field.label }} </label>
                    <div class="col-sm-10">
                      {{ field }} {{ field.errors.0 }}
                    </div>
                  </div>
            {% endfor %}
            <input type="submit" value="提交">
        </form>
    </div>
</body>
</html>

 效果:

这里其他效果:

原文地址:https://www.cnblogs.com/LearningOnline/p/9278447.html