04: Form 验证用户数据 & 生成html

目录:Django其他篇

01:Django基础篇

02:Django进阶篇

03:Django数据库操作--->Model

04: Form 验证用户数据 & 生成html

05:ModelForm 数据验证 & 生成html & 数据库操作

06: Django Admin

07: Django 学习补充

目录:

1.1 Form作用 与 基本使用     返回顶部

  1、form 作用

      1功能1  验证

      2功能2  生成html标签

      3、功能3: HTML Form提交保留上次提交数据

      4、功能4: 初始化页面显示内容

  2、form使用原则

      1新url方式操作(一定要用form方式生成html,避免提交刷新页面,丢失当前页面中填的值)

      2发Ajax请求时可以不用form生成html标签,仅用form做验证,因为ajax请求本身不刷新页面,不必担心填

           的值会丢失,当然使用form生成html也是可以的

  3、form基本使用:对 login.html提交密码做简单长度验证

from django.shortcuts import render,HttpResponse,redirect
from app01.forms import UserForm

def login(request):
    if request.method == 'GET':
        obj = UserForm()
        return render(request,'login.html',{'obj':obj})

    elif request.method == 'POST':
        obj = UserForm(request.POST)
        r1 = obj.is_valid()
        if r1:
            print(obj.cleaned_data)
        else:
            print(obj.errors)
        return render(request,'login.html',{'obj':obj})
views.py中定义处理函数
from django import forms
from django.forms import fields

class UserForm(forms.Form):
    #1: 这里的name必须要和input框中name的值
    name = fields.CharField(
        error_messages={'required':'用户名不能为空'},
    )

    #2: 这里的password必须是input框中name的值
    password = fields.CharField(
        min_length=6,
        max_length=10,
        error_messages={'required':'密码不能为空',
                        'min_length':'密码长度不能小于6',
                        'max_length':'密码长度不能大于12',
                        }
    )
app01/forms.py中定义字段验证规则
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>

    <form method="POST" action="/login/">
        <p>用户名:<input name="name" type="text">{{ obj.errors.name.0 }}</p>
        <p>密 码:<input name="password" type="text">{{ obj.errors.password.0 }}</p>
        <p><input type="submit" value="提交"></p>
    </form>

</body>
</html>
login.html

  4、生成HTML更简单的三种方法,但是耦合性太强,不好定制(不建议使用)

      1. { obj.as_p }
      2. { obj.as_ul }
      3. { obj.as_table }

1.2 from内置字段fields(数据验证)、内置插件widgets(生成html)     返回顶部

########################  1、常用的form内置字段    #########################

#1. Field
    required=True,                   # 是否允许为空
    widget=None,                     # HTML插件
    label=None,                      # 用于生成Label标签或显示内容
    initial=None,                    # 初始值
    help_text='',                    # 帮助信息(在标签旁边显示)
    error_messages=None,             # 错误信息 {'required': '不能为空', 'invalid': '格式错误'}
    show_hidden_initial=False,       # 是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一致)
    validators=[],                   # 自定义验证规则
    localize=False,                  # 是否支持本地化(比如需要本地时间而不是utc时间)
    disabled=False,                  # 是否可以编辑
    label_suffix=None                # Label内容后缀

#2. CharField(Field)
    max_length=None,                 # 最大长度
    min_length=None,                 # 最小长度
    strip=True                       # 是否移除用户输入空白
    
#3. EmailField(CharField)            # 必须为邮件格式

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

#5. FileField(Field)                 # 上传文件
    allow_empty_file=False           # 是否允许空文件
    
#6. 时间格式化(必须输入下面要求的格式)
    DateField(BaseTemporalField)                      # 格式:2015-09-01
    TimeField(BaseTemporalField)                      # 格式:11:12
    DateTimeField(BaseTemporalField)                  # 格式:2015-09-01 11:12


    
########################  2、不常用的form内置字段    #########################
    
#7. IntegerField(Field)
    max_value=None,                  # 最大值
    min_value=None,                  # 最小值
    
#8. RegexField(CharField)           # 自定义正则表达式
    regex,                          # 自定制正则表达式
    max_length=None,                # 最大长度
    min_length=None,                # 最小长度
    error_message=None,             # 忽略,错误信息使用 error_messages={'invalid': '...'}
    
#9. max_value=None,                  # 最大值
    min_value=None,                  # 最小值
    max_digits=None,                 # 总长度
    decimal_places=None,             # 小数位长度
        
#10. ImageField(FileField)上传图片
    注:需要PIL模块,pip3 install Pillow
    以上两个字典使用时,需要注意两点:
        - form表单中 enctype="multipart/form-data"
        - view函数中 obj = MyForm(request.POST, request.FILES)
        
#11. BooleanField(Field)             # 必须是布尔值

#12. ComboField(Field)               # 使用多个验证(比如:即验证最大长度20,又验证邮箱格式)
    fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])
        
#13. FilePathField(ChoiceField)      # 文件选项,目录下文件显示在页面中
        path,                       # 文件夹路径
        
#14. GenericIPAddressField
    protocol='both',                # both,ipv4,ipv6支持的IP格式
    unpack_ipv4=False               # 解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, 
    PS:protocol必须为both才能启用
    
#15. URLField(Field)                 # 必须是url格式
    
#16. ModelMultipleChoiceField(ModelChoiceField)
form内置字段(做数据验证)
#########################  1、常用的widgets内置插件    #########################

# TextInput(Input)
# PasswordInput(TextInput)
# EmailInput(TextInput)
# Textarea(Widget)
# FileInput

# Select
# SelectMultiple
# RadioSelect
# CheckboxInput
# CheckboxSelectMultiple


########################  2、不常用的widgets内置插件    #########################

# DateInput(DateTimeBaseInput)
# DateTimeInput(DateTimeBaseInput)
# TimeInput(DateTimeBaseInput)

# NumberInput(TextInput)
# URLInput(TextInput)

# ClearableFileInput
# MultipleHiddenInput
# SplitDateTimeWidget
# SplitHiddenDateTimeWidget
# SelectDateWidget
# HiddenInput(TextInput)
# NullBooleanSelect
内置插件widgets(生成html)

1.3 Form 验证用户数据 & 生成html 使用演示     返回顶部

  1、Form验证数据、生成html

from django.shortcuts import HttpResponse,render
from app01 import models
from app01.forms import FM

def login(request):
    if request.method == 'GET':
        obj = FM()    # 初始化操作,将字典中的值显示到页面,作为初始化值
        return render(request,'login.html',{'obj':obj})

    elif request.method == 'POST':
        # 获取用户所有数据
        # 每条请求数据的验证
        # 成功:获取所有正确信息
        # 失败:显示错误信息
        obj = FM(request.POST,request.FILES)   #将POST中提交的所有数据传给处理类(类中做校验)
        data = obj.is_valid()                  #类中对输入信息校验结果,符合返回True,否则返回False
        if data:
            # obj.cleaned_data 中获取了用户POST中所有正确信息,格式是字典

            print(obj.cleaned_data)

            # 将获取的正确信息字典传入进去就可以直接创建到数据库中
            # models.UserInfo.objects.create(**obj.cleaned_data)
        else:
            print(obj.errors)
        return render(request,'login.html',{'obj':obj})


# 法get请求时给页面初始化值
'''
# 从数据库获取数据,传入给initial的值必须是一个字典,且key必须是页面中的字段
dic= {
    'user':'tom',
    'pwd':'123',
    'email':'tom@qq.com',
    'city':2,
    'mcity':[1,2]
}
# obj = FM(initial=dic)    # 初始化操作,将字典中的值显示到页面,作为初始化值
# 为了使用户以get请求也能看到页面内容,在这里也要传入obj
'''
views.py获取前端数据、返回错误信息
from django import forms            #我们定义的类必须继承forms.Form
from django.forms import widgets    #widgets是插件,可以生成input框
from django.forms import fields     #字段

class FM(forms.Form):
    # 字段本身自己只做验证
    user = fields.CharField(
        error_messages={'required':'用户名不能为空'},
        label="用户名",        #在input框前面添加一个提示信息,比如“用户名”
        initial='root',        #在input框中可以设置一个默认值
        )
    pwd = fields.CharField(max_length=12,
                          min_length=6,
                          error_messages={'required':'密码名不能为空',
                                          'min_length':'密码长度不能小于6',
                                          'max_length':'密码长度不能大于12'
                          },
                          widget=widgets.PasswordInput(attrs={'class':'c1'}), #变成密码input框
                          )
    email = fields.EmailField(error_messages={'required':'邮箱不能为空','invalid':'邮箱格式错误',},
                              help_text='必须输入邮箱格式'
                              )

    f = fields.FileField()
    city = fields.ChoiceField(
        choices=[(0,'上海'),(1,'广州'),(2,'北京')]
    )
    mcity = fields.MultipleChoiceField(
        choices=[(0,'上海'),(1,'广州'),(2,'北京')]
    )
forms.py写form类定义验证规则
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <form action="/login/" method="POST">
        <p>{{ obj.user.label }}: {{ obj.user }} {{ obj.errors.user.0 }}</p>
        <p>{{ obj.pwd.label }}{{ obj.pwd }} {{ obj.errors.pwd.0 }}</p>
        <p>{{ obj.email }} {{ obj.errors.email.0 }} {{ obj.email.help_text }}</p>

        <p>{{ obj.f }} {{ obj.errors.f.0 }}</p>
        <p>{{ obj.p }} {{ obj.errors.p.0 }}</p>
        <p>{{ obj.city }} {{ obj.errors.city.0 }}</p>
        <p>{{ obj.mcity }} {{ obj.errors.mcity.0 }}</p>

        <input type="submit" value="提交">
    </form>

    <!-- 1、obj.errors获取到的就是这样的一端html字符串  -->
    <!--
    1、 obj.user.label        标签显示内容(如:用户名)
        obj.user.label_tag
    2、 obj.user              自动生成一个input标签,这种表自动保留上一次提交的数据功能
    3、 obj.errors.user.0     获取字段错误信息(提取到user字段)
        obj.errors            所有字段错误信息的html字符串
        obj.user.errors       错误信息(返回html标签)
                              <ul class="errorlist"><li>用户名不能为空</li></ul>
    4、 obj.email.help_text   获取提示帮助信息(必须输入邮箱格式)
    -->

    <!--  2、obj.errors获取到的就是这样的一端html字符串  -->
    <!--
    <ul class="errorlist">
        <li>user<ul class="errorlist"><li>用户名不能为空</li></ul></li>
        <li>pwd<ul class="errorlist"><li>密码名不能为空</li></ul></li>
    </ul>
    -->
</body>
</html>
login.html生成html

  2、生成HTML常用语法

      1、 obj.user.label                     标签显示内容(如:用户名)
            obj.user.label_tag

      2、 obj.user                            自动生成一个input标签,这种表自动保留上一次提交的数据功能

      3、 obj.errors.user.0              获取字段错误信息(提取到user字段)
            obj.errors                          所有字段错误信息的html字符串
            obj.user.errors                 错误信息(返回html标签)<ul class="errorlist"><li>用户名不能为空</li></ul>

      4、 obj.email.help_text          获取提示帮助信息(必须输入邮箱格式)

   3、操作form对象、数据验证

      1. obj = FM(request.POST)                  #将POST中提交的所有数据传给处理类(类中做校验)
      2. obj.is_valid()                                  #类中对输入信息校验结果,符合返回True,否则返回False
      3. obj.cleaned_data=obj.clean()           #用户POST中所有正确信息,格式就是字典
                                                               #{'mcity': ['0'], 'user': 'root', 'city': '0', }

      4. obj.errors                                         # 所有错误信息的html字符串(ul li格式)
          obj.errors.get('user')                         # user字段错误信息的html字符串(ul li格式)
          obj.errors.get('user')[0]                    #[0]user字段错误信息的错误信息的字符串

1.4 使用choice字段实现radio,select,checkbox功能     返回顶部

# 方法1:
user = fields.CharField(
    initial=2,
    widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),))
)

# 方法2:
user = fields.ChoiceField(
    choices=((1, '上海'), (2, '北京'),),
    initial=2,
    widget=widgets.RadioSelect
)
1、单radio,值为字符串的两种写法
# 方法1:
user = fields.CharField(
    initial=2,
    widget=widgets.Select(choices=((1,'上海'),(2,'北京'),))
)

# 方法2:
user = fields.ChoiceField(
    choices=((1, '上海'), (2, '北京'),),
    initial=2,
    widget=widgets.Select
)
2、单select,值为字符串的两种写法
user = fields.MultipleChoiceField(
    choices=((1,'上海'),(2,'北京'),),
    initial=[1,],
    widget=widgets.SelectMultiple
)
3、多选select,值为列表
user = fields.CharField(
    widget=widgets.CheckboxInput()
)
4、单checkbox
user = fields.MultipleChoiceField(
    initial=[2, ],
    choices=((1, '上海'), (2, '北京'),),
    widget=widgets.CheckboxSelectMultiple
)
5、多选checkbox,值为列表

1.5 form动态从数据库获取数据添加到select下拉菜单中     返回顶部

   1、原理介绍

      #1 由于user_type是类中的静态字段,程序一启动,就将值放到fields字段中了

      #2 所以后面数据库修改后user_type的值还是从fields字段中获取的,必须重启程序才能更新数据到页面

      #3 为了实现不必重启程序,我们必须要重写UserInfoForm类的构造方法(每次实例化类都会执行这个构造方法)

      #4 每次刷新页面就会调用UserInfoForm类的构造方法,在构造方法中定义每次刷新网页时再从数据库取一次值,将值赋值给fields对应字段

   2、实现动态从数据库获取数据添加到select下拉菜单中三种方法

from django.shortcuts import render
from app01 import models

def index(request):
    from app01.forms import UserInfoForm
    obj = UserInfoForm()
    
    # 这样就可以实现不必重启服务,数据库更新后前台刷新即可看到新数据
    # obj.fields['user_type'].choices = models.UserType.objects.values_list('id','name')
    return render(request,'index.html',{'obj':obj})
views.py 中定义处理函数
from django.db import models
from django.db import models

class UserType(models.Model):
    name = models.CharField(max_length=32)
    def __str__(self):
        return self.name
models.py中创建usertype表
from django import forms
from django.forms import fields         #fields字段专门用于验证
from django.forms import widgets        #widgets专门用于生成html标签
from app01 import models

class UserInfoForm(forms.Form):

    # 方法1 和 方法2 需要重写构造方法
    user_type1 = fields.ChoiceField(choices=[],widget=widgets.Select)
    user_type2 = fields.CharField(widget=widgets.Select(choices=[]))

    def __init__(self,*args,**kwargs):
        super(UserInfoForm,self).__init__(*args,**kwargs)
        self.fields['user_type1'].choices = models.UserType.objects.values_list('id','name')
        self.fields['user_type2'].widget.choices= models.UserType.objects.values_list('id','name')


    # 方法3:
    from django.forms.models import ModelChoiceField, ModelMultipleChoiceField
    # 1 这种方法不必重写构造方法,页面数据库数据就会更新到页面
    # 2 但要使用这种方法在创建表的类时必须定义 def __str__(self)
    user_type3 = ModelChoiceField(
        empty_label='请选择用户类型',      #选择框中的提示信息
        queryset=models.UserType.objects.all(),
        to_field_name='name',              #指定那个字段作为value
    )
forms.py生成下拉菜单:三种方法
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <p>{{ obj.user_type1 }}</p>
    <p>{{ obj.user_type2 }}</p>
    <p>{{ obj.user_type3 }}</p>
    <input type="submit" value="提交">
</body>
</html>
index.html生成html

1.6 form验证规则中的内置钩子     返回顶部

  1. from验证经历的顺序(搜索:Form and field validation

      1、拿到字段:用户发送一堆数据,根据form循环,拿到第一个字段

      2、正则匹配:先进行fields默认正则表达式判断,然后进行自定的正则表达式判断(如果有)

      3、字段钩子函数:然后执行字段的钩子函数,接着进行第二个字段,然后是第二个字段钩子函数...

      4、clean钩子函数:字段钩子函数执行完了再执行clean钩子函数进行整体验证

      5、_post_clean:     最后执行_post_clean钩子做其他验证

  2、 form验证的错误信息存放位置

      1、字段钩子错误信息放到对应的字段中 (obj.error中对应的字段字典)

      2、整体错误信息会放到 {"__all__":[],}中等价于{'NON_FIELD_ERRORS':[],} (如:执行clean)

  3、forms.py文件中使用这三种钩子

from django import forms
from django.forms import fields           #fields字段专门用于验证
from app01 import models
from django.core.exceptions import ValidationError

class RegisterForm(forms.Form):
    user = fields.CharField()
    email = fields.EmailField()
    pwd = fields.EmailField()

    #1 clean_字段名 是字段钩子(每个字段都有对应的这个钩子):如判断:“用户名已存在”
    def clean_user(self):
        # self.cleand_data['user']是用户提交的数据'
        c = models.User.objects.filter(name=self.cleand_data['user']).count()
        if not c:
            return self.cleand_data['user']     #必须要有返回值
        else:
            raise ValidationError('用户名已存在',code='xxx')

    #2 clean钩子对整体验证:如判断“用户名或密码错误”
    def clean(self):
        c = models.User.objects.filter(
            name=self.cleand_data['user'],
            pwd=self.cleand_data['pwd']).count()
        if c:
            return self.cleand_data     #正确的值必须return回去
        else:
            raise ValidationError('用户名或密码错误')

    #3 在这里可以做 其他验证
    def _post_clean(self):
        pass
forms.py文件中使用这三种钩子

1.7 form中自定义验证规则两种方法     返回顶部

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开头')],
    )
法1:使用RegexValidator模块进行自定义验证
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('手机号码格式错误')
 
class PublishForm(Form):
    # 使用自定义验证规则
    phone = fields.CharField(validators=[mobile_validate, ],
                            error_messages={'required': '手机不能为空'},
                            widget=widgets.TextInput(attrs={'class': "form-control",
                                                          'placeholder': u'手机号码'}))
法2:使用validators字段自己写函数进行验证

 

posted @ 2017-12-07 19:07  不做大哥好多年  阅读(422)  评论(0编辑  收藏  举报