〖Python〗-- Django的Form组件

【Django的Form组件】

Django的Form主要具有一下几大功能:

  • 生成HTML标签
  • 验证用户数据(显示错误信息)
  • HTML Form提交保留上次提交数据
  • 初始化页面显示内容

Form类的使用:

1、定义规则:

1
2
3
4
from django.forms import Form
from django.forms import fields
class xxx(Form):
    xx = fields.CharField(max_lenghth=,min_lenghth=,required=True,error_message=)

2、使用:

1
2
3
4
5
6
7
8
9
10
11
12
obj = xxx(request.POST)
# 是否校验成功
v = obj.is_valid()
    # html标签name属性 = Form类字段名
 
obj.is_valid()验证通过返回True,失败则返回False
 
# 所有错误信息
obj.errors
 
# 正确信息
obj.cleaned_data

登录和注册案例:

from django.shortcuts import render,HttpResponse,redirect

from django.forms import Form
from django.forms import fields
class LoginForm(Form):
    # 正则验证: 不能为空,6-18
    username = fields.CharField(
        max_length=18,
        min_length=6,
        required=True,
        error_messages={
            'required': '用户名不能为空',
            'min_length': '太短了',
            'max_length': '太长了',
        }
    )
    # 正则验证: 不能为空,16+
    password = fields.CharField(min_length=16,required=True)
    # email = fields.EmailField()
    # email = fields.GenericIPAddressField()
    # email = fields.IntegerField()


def login(request):
    if request.method == "GET":
        return render(request,'login.html')
    else:
       obj = LoginForm(request.POST)
       if obj.is_valid():
           # 用户输入格式正确
           print(obj.cleaned_data) # 字典类型
           return redirect('http://www.baidu.com')
       else:
           # 用户输入格式错误
           return render(request,'login.html',{'obj':obj})
views.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<form method="POST" action="/login/">
    {% csrf_token %}
    用户名:<input type="text" name="username">{{ obj.errors.username.0 }}<br>
    密码 &nbsp;&nbsp;:<input type="password" name="password">{{ obj.errors.password.0 }}<br>
    <input type="submit" value="提交">

</form>

</body>
</html>
login.html

基于Form和Ajax提交实现用户登录案例:两种验证方式

from django.shortcuts import render,redirect,HttpResponse
from django.forms import Form
from django.forms import fields
from django.forms import widgets

class LoginForm(Form):
    user = fields.CharField(required=True)
    pwd = fields.CharField(min_length=18)


def login(request):
    if request.method == 'GET':
        return render(request,'login.html')
    else:
        obj = LoginForm(request.POST)
        if obj.is_valid():
            print(obj.cleaned_data)
            return redirect('http://www.baidu.com')
        return render(request,'login.html',{'obj': obj})

def ajax_login(request):
    import json
    ret = {'status': True,'msg': None}
    obj = LoginForm(request.POST)
    if obj.is_valid():
        print(obj.cleaned_data)
    else:
        # print(obj.errors) # obj.errors对象
        ret['status'] = False
        ret['msg'] = obj.errors
    v = json.dumps(ret)
    return HttpResponse(v)

#
# class TestForm(Form):
#     t1 = fields.CharField(
#         required=True,
#         max_length=8,
#         min_length=2,
#         error_messages={
#             'required': '不能为空',
#             'max_length': '太长',
#             'min_length': '太短',
#         }
#     )
#     t2 = fields.IntegerField(
#         min_value=10,
#         max_value=1000,
#         error_messages={
#             'required': 't2不能为空',
#             'invalid': 't2格式错误,必须是数字',
#             'min_value': '必须大于10',
#             'max_value': '必须小于1000',
#         },
#     )
#     t3 = fields.EmailField(
#         error_messages={
#             'required': 't3不能为空',
#             'invalid': 't3格式错误,必须是邮箱格式',
#         }
#     )





class TestForm(Form):
    t1 = fields.CharField(required=True,max_length=8,min_length=2,
        error_messages={
            'required': '不能为空',
            'max_length': '太长',
            'min_length': '太短',
        }
    )
    t2 = fields.EmailField()

def test(request):
    if request.method == "GET":
        obj = TestForm()
        return render(request,'test.html',{'obj': obj})
    else:
        obj = TestForm(request.POST)
        if obj.is_valid():
            print(obj.cleaned_data)
        else:
            print(obj.errors)
        return render(request,'test.html',{'obj':obj})



class RegiterForm(Form):
    user = fields.CharField(min_length=8)
    email = fields.EmailField()
    password = fields.CharField()
    phone = fields.RegexField('139\d+')


def register(request):
    if request.method == 'GET':
        obj = RegiterForm()
        return render(request,'register.html',{'obj':obj})
    else:
        obj = RegiterForm(request.POST)
        if obj.is_valid():
            print(obj.cleaned_data)
        else:
            print(obj.errors)
        return render(request,'register.html',{'obj':obj})
views.py
"""s4day77 URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/1.10/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.conf.urls import url, include
    2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^login/', views.login),
    url(r'^ajax_login/', views.ajax_login),
    url(r'^test/', views.test),
    url(r'^register/', views.register),
]
urls.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <h1>用户登录</h1>
    <form id="f1" action="/login/" method="POST">
        {% csrf_token %}
        <p>
            <input type="text" name="user" />{{ obj.errors.user.0 }}
        </p>
        <p>
            <input type="password" name="pwd" />{{ obj.errors.pwd.0 }}
        </p>
        <input type="submit" value="提交" />
        <a onclick="submitForm();">提交</a>
    </form>
    <script src="/static/jquery-1.12.4.js"></script>
    <script>
        function submitForm(){
            $('.c1').remove();
            $.ajax({
                url: '/ajax_login/',
                type: 'POST',
                data: $('#f1').serialize(),// user=alex&pwd=456&csrftoen=dfdf\
                dataType:"JSON",
                success:function(arg){
                    console.log(arg);
                    if(arg.status){

                    }else{
                        $.each(arg.msg,function(index,value){
                            console.log(index,value);
                            var tag = document.createElement('span');
                            tag.innerHTML = value[0];
                            tag.className = 'c1';
                            $('#f1').find('input[name="'+ index +'"]').after(tag);
                        })
                    }
                }
            })
        }
    </script>
</body>
</html>
login.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <form action="/test/" method="POST" novalidate>
        {% csrf_token %}
        <p>
            {{ obj.t1 }}{{ obj.errors.t1.0 }}
        </p>
        <p>
            {{ obj.t2 }}{{ obj.errors.t2.0 }}
        </p>
        <input type="submit" value="提交" />
    </form>
</body>
</html>
test.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>

    <form action="/register/" method="POST" novalidate>
        {% csrf_token %}
        <p>
            {{ obj.user }} {{ obj.errors.user.0 }}
        </p>
        <p>
            {{ obj.email }} {{ obj.errors.email.0 }}
        </p>
        <p>
            {{ obj.password }} {{ obj.errors.password.0 }}
        </p>
        <p>
            {{ obj.phone }} {{ obj.errors.phone.0 }}
        </p>
        <input type="submit" value="提交"  />
    </form>
</body>
</html>
register.html

总结:

1
2
- Ajax,仅用验证功能
- Form,验证功能,生成HTML标签

班级、学生案例:

models.py
from django.shortcuts import render,redirect
from app01 import models
from django.forms import Form
from django.forms import fields
from django.forms import widgets



class ClassForm(Form):
    title = fields.RegexField('全栈\d+')

def class_list(request):
    cls_list = models.Classes.objects.all()
    return render(request,'class_list.html',{'cls_list':cls_list})

def add_class(request):
    if request.method == "GET":
        obj = ClassForm()
        return render(request,'add_class.html',{'obj': obj})
    else:
        obj = ClassForm(request.POST)
        if obj.is_valid():
            # obj.cleaned_data # 字典
            # 数据库创建一条数据
            # print(obj.cleaned_data)
            # models.Classes.objects.create(title=obj.cleaned_data['tt'])

            models.Classes.objects.create(**obj.cleaned_data)
            return redirect('/class_list/')
        return render(request,'add_class.html',{'obj': obj})

def edit_class(request,nid):
    if request.method == "GET":
        row = models.Classes.objects.filter(id=nid).first()
        # 让页面显示初始值
        # obj = ClassForm(data={'title': 'asdfasdfasdfas'})
        obj = ClassForm(initial={'title': row.title})
        return render(request,'edit_class.html',{'nid': nid,'obj':obj})
    else:
        obj = ClassForm(request.POST)
        if obj.is_valid():
            models.Classes.objects.filter(id=nid).update(**obj.cleaned_data)
            return redirect('/class_list/')
        return render(request,'edit_class.html',{'nid': nid,'obj':obj})



class StudentForm(Form):
    name = fields.CharField(
        min_length=2,
        max_length=6,
        widget=widgets.TextInput(attrs={'class': 'form-control'})
    )
    email = fields.EmailField(widget=widgets.TextInput(attrs={'class': 'form-control'}))
    age = fields.IntegerField(min_value=18,max_value=25,widget=widgets.TextInput(attrs={'class': 'form-control'}))
    cls_id = fields.IntegerField(
        # widget=widgets.Select(choices=[(1,'上海'),(2,'北京')])
        widget=widgets.Select(choices=models.Classes.objects.values_list('id','title'),attrs={'class': 'form-control'})
    )


def student_list(request):

    stu_list = models.Student.objects.all()
    return render(request,'student_list.html',{'stu_list':stu_list})

def add_student(request):
    if request.method == "GET":
        obj = StudentForm()
        return render(request,'add_student.html',{'obj':obj})
    else:
        obj = StudentForm(request.POST)
        if obj.is_valid():
            models.Student.objects.create(**obj.cleaned_data)
            return redirect('/student_list/')
        return render(request,'add_student.html',{'obj':obj})



def edit_student(request,nid):
    if request.method == "GET":
        row = models.Student.objects.filter(id=nid).values('name','email','age','cls_id').first()
        obj = StudentForm(initial=row)
        return render(request,'edit_student.html',{'nid':nid,'obj': obj})
    else:
        obj = StudentForm(request.POST)
        if obj.is_valid():
            models.Student.objects.filter(id=nid).update(**obj.cleaned_data)
            return redirect('/student_list/')
        return render(request,'edit_student.html',{'nid':nid,'obj': obj})
views.py
"""s4day77example URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/1.10/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.conf.urls import url, include
    2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^class_list/', views.class_list),
    url(r'^add_class/', views.add_class),
    url(r'^edit_class/(\d+)/', views.edit_class),

    url(r'^student_list/', views.student_list),
    url(r'^add_student/', views.add_student),
    url(r'^edit_student/(\d+)/', views.edit_student),
]
urls.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <h1>班级列表</h1>
    <div>
        <a href="/add_class/">添加</a>
    </div>
    <ul>
        {% for row in cls_list %}
            <li>{{ row.title }} <a href="/edit_class/{{ row.id }}/">编辑</a>  </li>
        {% endfor %}
    </ul>
</body>
</html>
class_list.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <h1>添加班级</h1>
    <form method="POST" action="/add_class/" novalidate>
        {% csrf_token %}
        {{ obj.title }} {{ obj.errors.title.0 }}
        <input type="submit" value="提交" />
    </form>
</body>
</html>
add_class.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <h1>编辑班级</h1>
    <form method="POST" action="/edit_class/{{ nid }}/">
        {% csrf_token %}
        <p>
            {{ obj.title }} {{ obj.errors.title.0 }}
        </p>
        <input type='submit' value="提交" />
    </form>
</body>
</html>
edit_class.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <h1>学生列表</h1>
    <a href="/add_student/">添加</a>
    <ul>
        {% for row in stu_list %}
            <li>{{ row.name }}-{{ row.email }}-{{ row.age }}-{{ row.cls_id }}-{{ row.cls.title }}   <a href="/edit_student/{{ row.id }}/">编辑</a></li>
        {% endfor %}
    </ul>
</body>
</html>
student_list.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <h1>添加学生</h1>
    <form action="/add_student/" method="POST">
        {% csrf_token %}
        <p>
            {{ obj.name }}
        </p>
        <p>
            {{ obj.email }}
        </p>
        <p>
            {{ obj.age }}
        </p>
        <p>
            {{ obj.cls_id }}
        </p>
        <input type="submit" value="提交" />
    </form>
</body>
</html>
add_student.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
    <link rel="stylesheet" href="/static/bootstrap-3.3.5-dist/css/bootstrap.css"/>
</head>
<body>


    <div style="width: 500px;margin: 0 auto;">
        <form class="form-horizontal" method="POST" action="/edit_student/{{ nid }}/">
            {% csrf_token %}
            <div class="form-group">
                <label class="col-sm-2 control-label">姓名:</label>

                <div class="col-sm-10">
                    {{ obj.name }}
                </div>
            </div>
            <div class="form-group">
                <label class="col-sm-2 control-label">邮箱:</label>

                <div class="col-sm-10">
                    {{ obj.email }}
                </div>
            </div>
             <div class="form-group">
                <label class="col-sm-2 control-label">年龄:</label>

                <div class="col-sm-10">
                    {{ obj.age }}
                </div>
            </div>
             <div class="form-group">
                <label class="col-sm-2 control-label">班级:</label>

                <div class="col-sm-10">
                    {{ obj.cls_id }}
                </div>
            </div>
            <div class="form-group">
                <div class="col-sm-offset-2 col-sm-10">
                    <input type="submit" class="btn btn-default" value="提交" />
                </div>
            </div>
        </form>
    </div>
</body>
</html>
edit_student.html

 老师案例:

views.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h1>老师列表</h1>
<a href="/add_teacher/">添加</a>
<table>
    <tr>
        <th>ID</th>
        <th>老师姓名</th>
        <th>班级</th>
    </tr>
    {% for row in tea_list %}
    <tr>
        <td>{{ row.id }}</td>
        <td>{{ row.name }}</td>
        <td>
            {% for row in row.c2t.all %}
                {{ row.title }}
            {% endfor %}
        </td>
        <td>
            <a href="/edit_teacher/{{ row.id }}">编辑</a>
        </td>
    </tr>
    {% endfor %}
</table>

</body>
</html>
teacher_list.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<form method="POST" action="/add_teacher/">
    {% csrf_token %}
    {{ obj.name }}{{ obj.errors.name.0 }}
    {{ obj.xx }}{{ obj.errors.xx.0 }}
    <input type="submit" value="提交">
</form>

</body>
</html>
add_teacher.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h1>编辑老师</h1>
<form method="POST" action="/edit_teacher/{{ nid }}/">
    {% csrf_token %}
    {{ obj.name }}{{ obj.errors.name.0 }}
    {{ obj.xx }} {{ obj.errors.xx.0 }}
    <input type="submit" value="提交">
</form>


</body>
</html>
edit_teacher.html
urls.py

Form组件的上传功能

from django.shortcuts import render,redirect,HttpResponse
from django.forms import Form
from django.forms import fields
from django.forms import widgets
from app01 import models
import os


class F2Form(Form):
    user = fields.CharField()
    fafafa = fields.FileField()

def f1(request):
    if request.method=="GET":
        return render(request,'f1.html')
    else:
        print(request.FILES)
        file_obj = request.FILES.get("fafafa")
        f = open(os.path.join('static',file_obj.name),'wb')
        for chunk in file_obj.chunks():
            f.write(chunk)
        f.close()
        return render(request,'f1.html')

def f2(request):
    if request.method == "GET":
        obj = F2Form()
        return render(request,'f2.html',{'obj':obj})
    else:
        obj = F2Form(data=request.POST,files=request.FILES)
        if obj.is_valid():
            print(obj.cleaned_data.get("fafafa").name)
            print(obj.cleaned_data.get("fafafa").size)
        return render(request,'f2.html',{'obj':obj})
views.py
f1.html
f2.html

Form类的字段和插件

创建Form类时,主要涉及到 【字段】 和 【插件】,字段用于对用户请求数据的验证,插件用于自动生成HTML;

1、Django内置字段如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
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,              是否支持本地化
    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)            时间间隔:%%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类型
    ...

注:UUID是根据MAC以及当前时间等创建的不重复的随机字符串

>>> import uuid

    # make a UUID based on the host ID and current time
    >>> uuid.uuid1()    # doctest: +SKIP
    UUID('a8098c1a-f86e-11da-bd1a-00112444be1e')

    # make a UUID using an MD5 hash of a namespace UUID and a name
    >>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org')
    UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e')

    # make a random UUID
    >>> uuid.uuid4()    # doctest: +SKIP
    UUID('16fd2706-8baf-433b-82eb-8c7fada847da')

    # make a UUID using a SHA-1 hash of a namespace UUID and a name
    >>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org')
    UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d')

    # make a UUID from a string of hex digits (braces and hyphens ignored)
    >>> x = uuid.UUID('{00010203-0405-0607-0809-0a0b0c0d0e0f}')

    # convert a UUID to a string of hex digits in standard form
    >>> str(x)
    '00010203-0405-0607-0809-0a0b0c0d0e0f'

    # get the raw 16 bytes of the UUID
    >>> x.bytes
    b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f'

    # make a UUID from a 16-byte string
    >>> uuid.UUID(bytes=x.bytes)
    UUID('00010203-0405-0607-0809-0a0b0c0d0e0f')
View Code

2、Django内置插件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
TextInput(Input)
NumberInput(TextInput)
EmailInput(TextInput)
URLInput(TextInput)
PasswordInput(TextInput)
HiddenInput(TextInput)
Textarea(Widget)
DateInput(DateTimeBaseInput)
DateTimeInput(DateTimeBaseInput)
TimeInput(DateTimeBaseInput)
CheckboxInput
Select
NullBooleanSelect
SelectMultiple
RadioSelect
CheckboxSelectMultiple
FileInput
ClearableFileInput
MultipleHiddenInput
SplitDateTimeWidget
SplitHiddenDateTimeWidget
SelectDateWidget

常用选择插件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# 单radio,值为字符串
# user = fields.CharField(
#     initial=2,
#     widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),))
# )
  
# 单radio,值为字符串
# user = fields.ChoiceField(
#     choices=((1, '上海'), (2, '北京'),),
#     initial=2,
#     widget=widgets.RadioSelect
# )
  
# 单select,值为字符串
# user = fields.CharField(
#     initial=2,
#     widget=widgets.Select(choices=((1,'上海'),(2,'北京'),))
# )
  
# 单select,值为字符串
# user = fields.ChoiceField(
#     choices=((1, '上海'), (2, '北京'),),
#     initial=2,
#     widget=widgets.Select
# )
  
# 多选select,值为列表
# user = fields.MultipleChoiceField(
#     choices=((1,'上海'),(2,'北京'),),
#     initial=[1,],
#     widget=widgets.SelectMultiple
# )
  
  
# 单checkbox
# user = fields.CharField(
#     widget=widgets.CheckboxInput()
# )
  
  
# 多选checkbox,值为列表
# user = fields.MultipleChoiceField(
#     initial=[2, ],
#     choices=((1, '上海'), (2, '北京'),),
#     widget=widgets.CheckboxSelectMultiple
# )

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

 方式一:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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.ChoiceField(
        # choices=((1, '上海'), (2, '北京'),),
        initial=2,
        widget=widgets.Select
    )
  
    def __init__(self*args, **kwargs):
        super(MyForm,self).__init__(*args, **kwargs)
        # self.fields['user'].widget.choices = ((1, '上海'), (2, '北京'),)
        # 或
        self.fields['user'].widget.choices = models.Classes.objects.all().value_list('id','caption')

方式二:

使用django提供的ModelChoiceField和ModelMultipleChoiceField字段来实现

1
2
3
4
5
6
7
8
9
10
from django import forms
from django.forms import fields
from django.forms import widgets
from django.forms import models as form_model
from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator
  
class FInfo(forms.Form):
    authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all())
    # authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all())zidi

自定义验证规则

方式一:

1
2
3
4
5
6
7
8
9
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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):
  
  
    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'手机号码'}))
  
    email = fields.EmailField(required=False,
                            error_messages={'required': u'邮箱不能为空','invalid': u'邮箱格式错误'},
                            widget=widgets.TextInput(attrs={'class'"form-control"'placeholder': u'邮箱'}))

方法三:自定义方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from django import forms
    from django.forms import fields
    from django.forms import widgets
    from django.core.exceptions import ValidationError
    from django.core.validators import RegexValidator
  
    class FInfo(forms.Form):
        username = fields.CharField(max_length=5,
                                    validators=[RegexValidator(r'^[0-9]+$''Enter a valid extension.''invalid')], )
        email = fields.EmailField()
  
        def clean_username(self):
            """
            Form中字段中定义的格式匹配完之后,执行此方法进行验证
            :return:
            """
            value = self.cleaned_data['username']
            if "666" in value:
                raise ValidationError('666已经被玩烂了...''invalid')
            return value

方式四:同时生成多个标签进行验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
from django.forms import Form
from django.forms import widgets
from django.forms import fields
  
from django.core.validators import RegexValidator
  
  
############## 自定义字段 ##############
class PhoneField(fields.MultiValueField):
    def __init__(self*args, **kwargs):
        # Define one message for all fields.
        error_messages = {
            'incomplete''Enter a country calling code and a phone number.',
        }
        # Or define a different message for each field.
        = (
            fields.CharField(
                error_messages={'incomplete''Enter a country calling code.'},
                validators=[
                    RegexValidator(r'^[0-9]+$''Enter a valid country calling code.'),
                ],
            ),
            fields.CharField(
                error_messages={'incomplete''Enter a phone number.'},
                validators=[RegexValidator(r'^[0-9]+$''Enter a valid phone number.')],
            ),
            fields.CharField(
                validators=[RegexValidator(r'^[0-9]+$''Enter a valid extension.')],
                required=False,
            ),
        )
        super(PhoneField, self).__init__(error_messages=error_messages, fields=f, require_all_fields=False*args,
                                         **kwargs)
  
    def compress(self, data_list):
        """
        当用户验证都通过后,该值返回给用户
        :param data_list:
        :return:
        """
        return data_list
  
############## 自定义插件 ##############
class SplitPhoneWidget(widgets.MultiWidget):
    def __init__(self):
        ws = (
            widgets.TextInput(),
            widgets.TextInput(),
            widgets.TextInput(),
        )
        super(SplitPhoneWidget, self).__init__(ws)
  
    def decompress(self, value):
        """
        处理初始值,当初始值initial不是列表时,调用该方法
        :param value:
        :return:
        """
        if value:
            return value.split(',')
        return [NoneNoneNone]

初始化数据

在Web应用程序中开发编写功能时,时常用到获取数据库中的数据并将值初始化在HTML中的标签上。

1、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()
  
    city = fields.ChoiceField(
        choices=((1, '上海'), (2, '北京'),),
        widget=widgets.Select
    )
View Code

2、Views

from django.shortcuts import render, redirect
from .forms import MyForm
  
  
def index(request):
    if request.method == "GET":
        values = {'user': 'root', 'city': 2}
        obj = MyForm(values)
  
        return render(request, 'index.html', {'form': obj})
    elif request.method == "POST":
        return redirect('http://www.google.com')
    else:
        return redirect('http://www.google.com')
View Code

3、HTML

<form method="POST" enctype="multipart/form-data">
    {% csrf_token %}
    <p>{{ form.user }} {{ form.user.errors }}</p>
    <p>{{ form.city }} {{ form.city.errors }}</p>
  
    <input type="submit"/>
</form>
View Code

关于对字段认证[clean,clean_字段]的补充(关于错误信息)

class RegesterForm(Form):
    username = fields.CharField(
        widget=widgets.TextInput(
            attrs={"class": "form-control",
                   "placeholder": "用户名",
                   }),
        error_messages={
            "required": "内容不能为空",
            "invalid": "格式错误,请重新输入!", })
 
    nickname = fields.CharField(
        widget=widgets.TextInput(
            attrs={"class": "form-control",
                   "placeholder": "即昵称",
                   }),
        error_messages={
            "required": "内容不能为空",
            "invalid": "格式错误,请重新输入!", })
 
    email = fields.EmailField(
        widget=widgets.TextInput(
          attrs={
              "class": "form-control",
              "placeholder": "请输入您查用邮箱",
          }),
        error_messages = {
            "required": "内容不能为空",
            "invalid": "格式错误,请重新输入!",}
    )
 
    password = fields.CharField(
        widget=widgets.PasswordInput(
            attrs={"class": "form-control",
                   "placeholder": "密码,必须包含数字,字母!",
                   }),
        error_messages={
            "required": "内容不能为空",
            "invalid": "格式错误,请重新输入!", })
 
    passwords = fields.CharField(
        widget=widgets.PasswordInput(
            attrs={"class": "form-control",
                   "placeholder": "请输入确认密码",
                   }),
        error_messages={
            "required": "内容不能为空",
            "invalid": "格式错误,请重新输入!", })
 
    avatar = fields.FileField(
        widget=widgets.FileInput(
            attrs={'id':"imgSelect",}),
    )
    code = fields.CharField(
        widget=widgets.TextInput(
            attrs={
                "class": "form-control",
                "placeholder": "验证码",
            },)
    )
    def __init__(self,request,*args,**kwargs):
        super(RegesterForm,self).__init__(*args,**kwargs)
        self.request = request
 
    def clean_code(self):
        input_code = self.cleaned_data["code"]
        session_code = self.request.session.get("code")
        if input_code.upper() == session_code.upper():
            return input_code
        raise ValidationError("验证码错误,请重新输入!")
    #自定义字段验证方法,获取错误信息的方式不变,还是   对象.errors.字段名.0
 
    def clean(self):
        p1 = self.cleaned_data.get("password")
        p2 = self.cleaned_data.get("passwords")
        if p1 == p2:
            return self.cleaned_data
        else:
            self.add_error("passwords",ValidationError("输入的密码不一致!")) 
View Code
对于Form组件的错误信息:
    注意再注意:
    默认错误信息方式: raise ValidationError("输入的密码不一致!")
    自定义对已拿到所有字段数据进行验证的时候,这种方式在获取错误信息时就发生改变,查看源码发现如果有错误的话,他会执行self.add_error(None, e)
    通过方法给字段None添加错误信息,查看add_error的源码以及执行过程,发现None = NON_FIELD_ERRORS。也就是说会默认给__all__字段或
    NON_FIELD_ERRORS写上错误信息。原因:内部定义的NON_FIELD_ERRORS="__all__",
    获取方式:
        前端获取 是通过obj.non_field_errors
        后台获取是通过 obj.errors["__all__"]  or   obj.errors[NON_FIELD_ERRORS]
 
    我们知道,当报错的时候,内部会自动去添加错误信息,若是我们能否手动指定某个字段呢?答案是肯定的。
    这样我们自己添加异常的错误信息,就能直接通过{{obj.errors.passwords.0}}获取到与其他的无疑。
    语法:
        self.add_error('字段名称', 错误异常对象)
总结

以上代码是我写用户注册时的form组件,由于牵扯到对输入字段的认证问题!如果选择在视图函数中,那代码的重复率可就老了去了!!!所以就使用了Form组件中的字段认证的方法!!!

前面已经介绍过Form组件中两种验证方式的函数,一个对字段的 clean_字段;另一个是等所有字段验证之后,对所有验证过的clean_data进行更高的验证:clean;今天我要说的是关于验证过程中,产生和收集错误信息的问题。详见上面代码!!!

 

posted @ 2017-10-09 23:33  盛欣  阅读(594)  评论(0编辑  收藏  举报