Django---FORM组件.FORM组件的字段,FORM组件校验流程,FORM组件的全局和局部钩子,FORM和Model的组合

Django---FORM组件.FORM组件的字段,FORM组件校验流程,FORM组件的全局和局部钩子,FORM和Model的组合

一丶FORM的介绍

1.生成页面可用的HTML标签

2.对用户提交的数据进行校验

3.保留上次输入内容

二丶使用form组件实现注册功能

from django import forms  # 导入forms组件

# 按照Django form组件的要求自己写一个类
class RegForm(forms.Form):  # 继承Form
    name = forms.CharField(label="用户名")  # 在HTML就会生成一个文本框
    pwd = forms.CharField(label="密码")     
# 使用form组件实现注册方式
def register2(request):
    form_obj = RegForm()    # 实例化一个自定义form组件类的对象
    if request.method == "POST":
        # 实例化form对象的时候,把post提交过来的数据直接传进去
        form_obj = RegForm(request.POST) # 自动html页面的数据以k:v形式传递给Form对象中
        # 调用form_obj校验数据的方法
        if form_obj.is_valid():  # is_valid() 是校验方法.错误信息是字典类型.有错误就是False
            return HttpResponse("注册成功")
    return render(request, "register2.html", {"form_obj": form_obj}) # 将form对象传递给前端
<body>
    <form action="/reg2/" method="post" novalidate autocomplete="off"> <!-- -->
        {% csrf_token %}     <!--生成 CSRFTOKEN -->

        <!--方式一: 通过传递的form对象, 获得每个属性. -->
        {{ form_obj.name.label }}   # name对象的lable属性
        {{ form_obj.name }}         # name对象
        {{ form_obj.name.errors.0 }} # name对象的错误信息. errors是一个错误列表.取第一个错误即可
        <div>
            <label for="{{ form_obj.name.id_for_label }}">{{ form_obj.name.label }}</label>
            {{ form_obj.name }} {{ form_obj.name.errors.0 }}
        </div>
        <div>
            <label for="{{ form_obj.pwd.id_for_label }}">{{ form_obj.pwd.label }}</label>
            {{ form_obj.pwd }} {{ form_obj.pwd.errors.0 }}
        </div>

        <!-- 方式二 -->
        {{form_obj.as_p}} # 展示所有的字段
        <p>
            {{form_obj.as_p}}
        </p>
        <div>
            <input type="submit" class="btn btn-success" value="注册">
        </div>
    </form>
</body>

总结:

{{ form_obj.as_p }}    # 展示所有的字段

{{ form_obj.user }}   # input框
{{ form_obj.user.label }}   # label标签的中文提示
{{ form_obj.user.id_for_label }}  # input框的id
{{ form_obj.user.errors  }}    # 一个字段的错误信息
{{ form_obj.user.errors.0  }}   # 一个字段的第一个错误信息
{{ form_obj.errors  }}   # 所有字段的错误

三丶FORM组件

常用字段与插件

###  initial  默认值
class LoginForm(forms.Form):
    username = forms.CharField(
        min_length=8,
        label="用户名",
        initial="张三"  # 设置默认值
    )

### error_messages 重写错误信息
class LoginForm(forms.Form):
    username = forms.CharField(
        min_length=8,
        label="用户名",
        initial="张三",
        error_messages={
            "required": "不能为空",
            "invalid": "格式错误",
            "min_length": "用户名最短8位"
        }
    )

### password 修改input文本框的类型为密码类型
    # attrs 设置属性(可以添加bootstrap样式)
    # render_value
class LoginForm(forms.Form):
    pwd = forms.CharField(
        min_length=6,
        label="密码",
        widget=forms.widgets.PasswordInput(attrs={'class': 'c1'}, render_value=True)
    )

### radioSelect  单radio值为字符串
class LoginForm(forms.Form):
    gender = forms.fields.ChoiceField(
        choices=((1, "男"), (2, "女"), (3, "保密")),  # 在python中是 可供选择.存数据库的值为数字,显示在页面上的是 男/女
        label="性别",
        initial=3,
        widget=forms.widgets.RadioSelect()  # 设置这个input框的类型是 radio
    )    

### 单选Select
class LoginForm(forms.Form):
    hobby = forms.fields.ChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
        label="爱好",
        initial=3,
        widget=forms.widgets.Select() # 设置显示的标签 select标签
    )

### 多选Select
class LoginForm(forms.Form):
    hobby = forms.fields.MultipleChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
        label="爱好",
        initial=[1, 3],
        widget=forms.widgets.SelectMultiple() # 设置 select标签的属性 multiple多选
    )

### 单选checkbox
class LoginForm(forms.Form):
    keep = forms.fields.ChoiceField(
        label="是否记住密码",
        initial="checked",
        widget=forms.widgets.CheckboxInput()  #input的类型是 CheckBox单选框
    )

### 多选checkbox
class LoginForm(forms.Form):
    hobby = forms.fields.MultipleChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
        label="爱好",
        initial=[1, 3],
        widget=forms.widgets.CheckboxSelectMultiple() # input类型是 CheckBox 属性时multiple
    )

? 多选框的传值

def form(request):

    obj=TestForm()

    if request.method=='POST':
        obj=TestForm(request.POST)
        print(obj,type(obj))  # <class 'app01.views.TestForm'> 得到一个TestForm  对象
        print(obj.data,type(obj.data)) # <QueryDict: 'hobby2': ['1', '3'], 'hobby3': ['1', .. 拿到所有的键值对 前端页面提交的 数据.

    return render(request,'form.html',{'obj':obj})

关于choice的注意事项:

? 在使用选择标签时,需要注意choices的选项可以从数据库中获取,但是由于是静态字段 获取的值无法实时更新,那么需要自定义构造方法从而达到此目的。

#### 方式一
from django.forms import Form
from django.forms import widgets
from django.forms import fields

class MyForm(Form):

    user = fields.ChoiceField(
        # choices=((1, '上海'), (2, '北京'),),
        initial=2,
        widget=widgets.Select    # 因为启动项目后 只加载了一次. 不会再次更细
    )

    def __init__(self, *args, **kwargs):
        super(MyForm,self).__init__(*args, **kwargs)
        # self.fields['user'].choices = ((1, '上海'), (2, '北京'),)
        # 或
        self.fields['user'].choices = models.Classes.objects.all().values_list('id','caption') # 重写init方法 使用values_list对数据分组
        
#### 方式二
from django import forms
from django.forms import fields
from django.forms import models as form_model

class FInfo(forms.Form):
     # 多选   设置queryset的属性 查询数据库
    authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all()) 

     # 单选  设置queryset的属性 查询数据库
    authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all()) 

Django Form组件所有字段

Field
    required=True,               是否允许为空
    widget=None,                 HTML插件
    label=None,                  用于生成Label标签或显示内容
    initial=None,                初始值
    help_text='',                帮助信息(在标签旁边显示)
    error_messages=None,         错误信息 {'required': '不能为空', 'invalid': '格式错误'}
    validators=[],               自定义验证规则
    localize=False,              是否支持本地化
    disabled=False,              是否可以编辑
    label_suffix=None            Label内容后缀

CharField(Field)
    max_length=None,             最大长度
    min_length=None,             最小长度
    strip=True                   是否移除用户输入空白

IntegerField(Field)
    max_value=None,              最大值
    min_value=None,              最小值

FloatField(IntegerField)
    ...

DecimalField(IntegerField)
    max_value=None,              最大值
    min_value=None,              最小值
    max_digits=None,             总长度
    decimal_places=None,         小数位长度

BaseTemporalField(Field)
    input_formats=None          时间格式化   

DateField(BaseTemporalField)    格式:2015-09-01
TimeField(BaseTemporalField)    格式:11:12
DateTimeField(BaseTemporalField)格式:2015-09-01 11:12

DurationField(Field)            时间间隔:%d %H:%M:%S.%f
    ...

RegexField(CharField)
    regex,                      自定制正则表达式
    max_length=None,            最大长度
    min_length=None,            最小长度
    error_message=None,         忽略,错误信息使用 error_messages={'invalid': '...'}

EmailField(CharField)
    ...

FileField(Field)
    allow_empty_file=False     是否允许空文件

ImageField(FileField)
    ...
    注:需要PIL模块,pip3 install Pillow
    以上两个字典使用时,需要注意两点:
        - form表单中 enctype="multipart/form-data"
        - view函数中 obj = MyForm(request.POST, request.FILES)

URLField(Field)
    ...

BooleanField(Field)
    ...

NullBooleanField(BooleanField)
    ...

ChoiceField(Field)
    ...
    choices=(),                选项,如:choices = ((0,'上海'),(1,'北京'),)
    required=True,             是否必填
    widget=None,               插件,默认select插件
    label=None,                Label内容
    initial=None,              初始值
    help_text='',              帮助提示

ModelChoiceField(ChoiceField)
    ...                        django.forms.models.ModelChoiceField
    queryset,                  # 查询数据库中的数据
    empty_label="---------",   # 默认空显示内容
    to_field_name=None,        # HTML中value的值对应的字段
    limit_choices_to=None      # ModelForm中对queryset二次筛选

ModelMultipleChoiceField(ModelChoiceField)
    ...                        django.forms.models.ModelMultipleChoiceField

TypedChoiceField(ChoiceField)
    coerce = lambda val: val   对选中的值进行一次转换
    empty_value= ''            空值的默认值

MultipleChoiceField(ChoiceField)
    ...

TypedMultipleChoiceField(MultipleChoiceField)
    coerce = lambda val: val   对选中的每一个值进行一次转换
    empty_value= ''            空值的默认值

ComboField(Field)
    fields=()                  使用多个验证,如下:即验证最大长度20,又验证邮箱格式
                               fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])

MultiValueField(Field)
    PS: 抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用

SplitDateTimeField(MultiValueField)
    input_date_formats=None,   格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y']
    input_time_formats=None    格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']

FilePathField(ChoiceField)     文件选项,目录下文件显示在页面中
    path,                      文件夹路径
    match=None,                正则匹配
    recursive=False,           递归下面的文件夹
    allow_files=True,          允许文件
    allow_folders=False,       允许文件夹
    required=True,
    widget=None,
    label=None,
    initial=None,
    help_text=''

GenericIPAddressField
    protocol='both',           both,ipv4,ipv6支持的IP格式
    unpack_ipv4=False          解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用

SlugField(CharField)           数字,字母,下划线,减号(连字符)
    ...

UUIDField(CharField)           uuid类型

Django Form内置字段

校验

### validators 校验器校验
from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.validators import RegexValidator

class MyForm(Form):

    user = fields.CharField(
        validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
    )
### 自定义检验规则
    # 通过校验   不做任何操作
    # 不通过校验  抛出ValidationError异常
import re
from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.exceptions import ValidationError

# 自定义验证规则
def mobile_validate(value):
    mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
    if not mobile_re.match(value):
        raise ValidationError('手机号码格式错误')  # 必须抛出ValidationError异常

class PublishForm(Form):

    title = fields.CharField(max_length=20,
                            min_length=5,
                            error_messages={'required': '标题不能为空',
                                            'min_length': '标题最少为5个字符',
                                            'max_length': '标题最多为20个字符'},
                            widget=widgets.TextInput(attrs={'class': "form-control",
                                                          'placeholder': '标题5-20个字符'}))

    # 使用自定义验证规则
    phone = fields.CharField(validators=[mobile_validate, ], #使用自定义校验规则
                            error_messages={'required': '手机不能为空'},
                            widget=widgets.TextInput(
                                attrs={'class': "form-control",
                                       'placeholder': u'手机号码'})
                            )

?

form校验的流程

# 1. is_valid()中要执行full_clean():
   1. self._errors ={}    定义一个存放错误信息的字典
   2. self.cleaned_data = {}   #  定义一个存放有效的数据

# 2. 执行self._clean_fields()
   1. 先执行内置的校验和校验器的校验
   2. 有局部钩子,执行局部钩子

# 3. 执行 self.clean() 全局钩子

局部钩子和全局钩子

def clean_gender(self):  # 必须是clean_XXX某字段
    v = self.cleaned_data.get('gender')
    # 局部钩子
    # 不通过校验 抛出异常
    if len(v)>10:
        raise ValidationError('长度不能小于10')  # 抛出异常
    # 通过校验   必须返回当前字段的值
    return v

def clean(self):
    # 全局钩子
    # 不通过校验 抛出异常
    # 通过校验   必须返回所有字段的值 self.cleaned_data
    pwd = self.cleaned_data.get('pwd')
    re_pwd = self.cleaned_data.get('re_pwd')
    if pwd != re_pwd:
        self.add_error('re_pwd','两次密码不一致!')
        raise ValidationError('两次密码不一致')  # 抛出异常
    return self.cleaned_data  # 必须返回

Form使用bootstrap样式

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册页面</title>
    {% load static %}
    <link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-md-12 text-center">
            <h1>欢迎注册</h1>
        </div>
    </div>

    <div class="row">

        <div class="col-md-12">

            <form action="" class="form-horizontal" method="post" novalidate>
                {% csrf_token %}

                <div class="form-group">
                    <label class="col-sm-3 control-label "
                           for="{{ form_obj.username.id_for_label }}">{{ form_obj.username.label }}</label>
                    <div class="col-sm-6">
                        {{ form_obj.username }}
                    </div>
                    <label class="control-label text-danger">{{ form_obj.username.errors.0 }}</label>
                </div>

                <div class="form-group">
                    <label for="{{ form_obj.pwd.id_for_label }}"
                           class="col-sm-3 control-label">{{ form_obj.password.label }}</label>
                    <div class="col-sm-6">
                        {{ form_obj.password }}
                    </div>
                    <label class="control-label text-danger">{{ form_obj.password.errors.0 }}</label>
                </div>

                <div class="form-group">
                    <label for="{{ form_obj.re_password.id_for_label }}"
                           class="col-sm-3 control-label">{{ form_obj.re_password.label }}</label>
                    <div class="col-sm-6">
                        {{ form_obj.re_password }}
                    </div>
                    <label class="control-label text-danger">{{ form_obj.re_password.errors.0 }}</label>

                </div>

                <div class="form-group">
                    <label for="{{ form_obj.name.id_for_label }}"
                           class="col-sm-3 control-label">{{ form_obj.name.label }}</label>
                    <div class="col-sm-6">
                        {{ form_obj.name }}
                    </div>
                    <label class="control-label text-danger">{{ form_obj.name.errors.0 }}</label>

                </div>

                <div class="form-group">
                    <label for="{{ form_obj.address.id_for_label }}"
                           class="col-sm-3 control-label">{{ form_obj.address.label }}</label>
                    <div class="col-sm-6">
                        {{ form_obj.address }}
                    </div>
                    <label class="control-label text-danger">{{ form_obj.address.errors.0 }}</label>

                </div>

                <div class="form-group">
                    <label for="{{ form_obj.phone.id_for_label }}"
                           class="col-sm-3 control-label">{{ form_obj.phone.label }}</label>
                    <div class="col-sm-6">
                        {{ form_obj.phone }}
                    </div>
                    <label class="control-label text-danger">{{ form_obj.phone.errors.0 }}</label>
                </div>

                <div class="form-group">
                    <label for="{{ form_obj.useremail.id_for_label }}"
                           class="col-sm-3 control-label">{{ form_obj.useremail.label }}</label>
                    <div class="col-sm-6">
                        {{ form_obj.useremail }}
                    </div>
                    <label class="control-label text-danger">{{ form_obj.useremail.errors.0 }}</label>
                </div>

                <div class="form-group">
                    <div class="col-sm-offset-3 col-sm-10">
                        <button type="submit" class="btn btn-default">注&nbsp;册</button>
                    </div>
                </div>

            </form>

        </div>

    </div>
</div>

<script src="{% static 'js/jquery-1.11.1.min.js' %}"></script>
<script src="{% static 'js/ajax-csrf.js' %}"></script>
<script>
    $(function () {
        $('#id_username').blur(function () {
            var now_obj = $(this)
            console.log(now_obj.val())
            $.ajax({
                url: '/check_user/',
                type: 'post',
                data: {
                    'check_name': now_obj.val()
                },
                success: function (data) {
                    console.log(data.status)
                    if (data.status) {
                        $(now_obj.parent().next()).text('用户名已存在,不可使用')
                    } else {
                        $(now_obj.parent().next()).removeClass('text-danger')
                        $(now_obj.parent().next()).addClass('text-success')
                        $(now_obj.parent().next()).text('用户名可以使用')
                    }
                }
            })
        });

        $('#id_username').focus(function () {
            $(this).parent().next().removeClass('text-success')
            $(this).parent().next().addClass('text-danger')
            $(this).parent().next().text('')
        })
    })
</script>
</body>
</html>

批量添加样式

class LoginForm(forms.Form):
    username = forms.CharField(
        min_length=8,
        label="用户名",
        initial="张三",
        error_messages={
            "required": "不能为空",
            "invalid": "格式错误",
            "min_length": "用户名最短8位"
        }
    ...

    def __init__(self, *args, **kwargs): # 重写form的 init方法
        super(LoginForm, self).__init__(*args, **kwargs)
        for field in iter(self.fields):
            self.fields[field].widget.attrs.update({   # 固定写法~~
                'class': 'form-control'
            })

四丶ModelForm

form与model的结合。

class BookForm(forms.ModelForm):

    class Meta:
        model = models.Book
        fields = "__all__"
        labels = {
            "title": "书名",
            "price": "价格"
        }
        widgets = {
            "password": forms.widgets.PasswordInput(attrs={"class": "c1"}),
        }

### MATE参数
model = models.Student  # 对应的Model中的类
fields = "__all__"  # 字段,如果是__all__,就是表示列出所有的字段
exclude = None  # 排除的字段
labels = None  # 提示信息
help_texts = None  # 帮助提示信息
widgets = None  # 自定义插件
error_messages = None  # 自定义错误信息

原文地址:https://www.cnblogs.com/dengl/p/11503556.html

时间: 2024-10-08 09:04:47

Django---FORM组件.FORM组件的字段,FORM组件校验流程,FORM组件的全局和局部钩子,FORM和Model的组合的相关文章

form组件使用、常用字段、字段参数、自定义校验规则:

views: from django.shortcuts import render,HttpResponse # Create your views here.def reg(request): if request.method == "POST": user = request.POST.get("user") pwd = request.POST.get("pwd") if len(pwd) <= 6: return render(

Django框架(十六)—— forms组件、局部钩子、全局钩子

forms组件.局部钩子.全局钩子 一.什么是forms组件 forms组件就是一个类,可以检测前端传来的数据,是否合法. 例如,前端传来的邮箱数据,判断邮件格式对不对,用户名中不能以什么开头,等等 二.forms组件的使用 1.使用语法 from django.shortcuts import render, HttpResponse from django import forms # 1.先写一个类,继承Form class MyForm(forms.Form): # 定义一个属性,可以用

Django框架(十四)-- forms组件、局部钩子、全局钩子

一.什么是forms组件 forms组件就是一个类,可以检测前端传来的数据,是否合法. 例如,前端传来的邮箱数据,判断邮件格式对不对,用户名中不能以什么开头,等等 二.forms组件的使用 1.使用语法 from django.shortcuts import render, HttpResponse from django import forms # 1.先写一个类,继承Form class MyForm(forms.Form): # 定义一个属性,可以用来校验字符串类型 # 限制最大长度是

Django之路- 如何开发通用且万能的的权限框架组件

本节内容 需求讨论 权限设计 代码设计 自定义权限钩子 业务场景分析 本节课老男孩教育ALEX教你假设我们在开发一个培训机构的 客户关系管理系统,系统分客户管理.学员管理.教学管理3个大模块,每个模块大体功能如下 客户管理销售人员可以录入客户信息,对客户进行跟踪,为客户办理报名手续销售人员可以修改自己录入的客户信息客户信息不能删除销售主管可以查看销售报表 学员管理 学员可以在线报名 学员可以查看自己的报名合同.学习有效期学员可以在线提交作业 .查看自己的成绩 教学管理管理员可以创建新课程.班级讲

记Angular与Django REST框架的一次合作(2):前端组件化——Angular

注:这是这个系列的第二部分,主要集中在Angular的使用方面.之前使用过AngularJS(Angular 1.x),混在Django的模板中使用,这些页面一般完全是结果展示页.在有Django表单输入的页面中,就很难将两者很好的结合起来.自己在学习新版的Angular时,跟了2遍官方网站的“英雄指南”教程.第1次完全是照搬,熟悉了一下基本概念:第2次自己做了一些修改,写了一个图片分享系统(只有一个雏形,还不是特别完善). 推荐IDE:Visual Studio Code 代码: github

Django REST framework之序列化组件以及源码分析+全局、局部Hook

序列化两大功能 a.对queryset类型进行序列化 b.对用户请求的数据进行校验 a.对queryset类型进行序列化 举例说明: 表设计 1 from django.db import models 2 3 4 class UserGroup(models.Model): 5 title = models.CharField(max_length=32) 6 7 8 class UserInfo(models.Model): 9 user_type_choices = ( 10 (1, '普

JS组件系列——又一款MVVM组件:Vue(二:构建自己的Vue组件)

阅读目录 一.为什么组件很重要 二.Vue里面的组件基础知识 1.组件的概念 2.组件原理 3.组件使用 三.封装自己的Component 1.使用Component封装bootstrapTable 2.封装select 3.查看其他Vue框架源码 四.总结 正文 前言:转眼距离上篇 JS组件系列--又一款MVVM组件:Vue(一:30分钟搞定前端增删改查) 已有好几个月了,今天打算将它捡起来,发现好久不用,Vue相关技术点都生疏不少.经过这几个月的时间,Vue的发展也是异常迅猛,不过这好像和博

Bootstrap组件系列之福利篇几款好用的组件(推荐)

引用 :http://www.jb51.net/article/87189.htm 一.时间组件 bootstrap风格的时间组件非常多,你可以在github上面随便搜索"datepicker"关键字,可以找到很多的时间组件.博主原来也用过其中的两个,发现都会有一些大大小小的问题.经过一番筛选,找到一个效果不错.能适用各种场景的时间组件,下面就来一睹它的风采吧. 1.效果展示 初始效果 组件中文化和日期格式自定义:只显示日期 显示日期和时间(手机.平板类设备可能体验会更好) 2.源码说

DRF框架(八)——drf-jwt手动签发与校验、过滤组件、筛选组件、排序组件、分页组件

自定义drf-jwt手动签发和校验 签发token源码入口 前提:给一个局部禁用了所有 认证与权限 的视图类发送用户信息得到token,其实就是登录接口,不然进不了登录页面 获取提交的username和password 1)rest_framework_jwt.views.ObtainJSONWebToken 的 父类 JSONWebTokenAPIView 的 post 方法 接受有username.password的post请求校验数据,并且签发token 2)post方法将请求数据交给 r