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

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

一 通过form实现校验字段功能

模型:models.py

   class UserInfo(models.Model):
        name = models.CharField(max_length=32)
        pwd = models.CharField(max_length=32)
        email = models.EmaillField()
        tel = models.CharField(max_length=32)

模板:register.html

<form action="", method="post">
        <p>用户名 <input type="text" name="username"></p>
        <p>密码<input type="password" name="password"></p>
        <p>确认密码<input type="password" name="repwd"></p>
        <p>邮箱<input type="text" name="email"></p>
        <p>手机号<input type="text" name="tel"></p>
        <input type="submit">
        {% csrf_token %}
</form>

 

二 通过form组件对模板进行渲染

form校验组件

from django import forms
class UserForm(forms.Form):
    username = forms.CharField(min_length=4)
    password = forms.CharField(min_length=4)
    repwd = forms.CharField(min_length=4)
    email = forms.EmailField()
    tel = forms.CharField

视图函数

def register(req):
    if req.method == 'POST':
    # form = UserForm({'name':'cs', 'email': '123@qq.com', 'xxx':'harry'})
    form = UserForm(req.POST)       # 注意form表单的name属性值应该与forms组件字段名称一致
    print(form.is_valid())  # 返回布尔值
    if form.is_valid():
          print(form.cleaned_data)    # {"name":'cs", "email:'123@qq.com'}
    else:
          print(form.cleaned_data)
          print(form.errors)          # {"name":["......"]}
         return  HttpResponse('ok')
                    '''
if 所有的字段校验成功,则form.cleaned_data以一个字典的形式存放所有校验通过的数据
                    '''
    return render(req, "register.html")

form组件在模板中渲染

 1 <form class="col-md-4  form-group" action="",method="post">
 2               <p>
 3                   用户名 {{ form.username }}
 4               </p>
 5               <p>
 6                   密码 {{ form.password }}
 7               </p>
 8               <p>
 9                   确认密码  {{ form.repwd }}
10               </p>
11               <p>
12                   email {{ form.email }}
13               </p>
14               <p>
15                   手机号 {{ form.tel }}
16               </p>
17 </form>
方式一
1 <form class="col-md-4  form-group" action="",method="post">
2                 {% csrf_token %}
3                 {% for filed in form %}
4                     <p>
5                         <lable>{{ filed.label }}</lable>
6                         {{ filed }}
7                     </p>
8                 {% endfor %}
9 </form>
方式二

 展示错误信息

<form  class="col-md-6" action="" method="post" novalidate>
    {% csrf_token %}
    {% for filed in form %}
          <p>
             <lable>{{ filed.label }}</lable>
              {{ filed }} <span>{{ filed.errors.0 }}</span>
           </p>
     {% endfor %}
      <input type="submit">
</form>

三 form组件的配置参数

Filed参数
            required=Ture                   是否必填
            widget=None                     HTNL插件
            label=None                      用于生成Label标签显示内容
            initial=None                    初始值
            help_text=''                    帮助信息(在标签旁边显示)
            error_messages=None             错误信息{'required':'不能为空’, 'invalid':'格式错误’}
            show_hidden_initial=False       是否在当前插件后再加一个隐藏的具有默认值的插件(可用于两次输入是否一致)
            validators=[],                  自定义验证规则
            localize=False                  是否支持本地化
            disabled=False                  是否可以编辑
            label_suffix=None               Lable内容后缀
        
        CharField(Field)
            max_length=None                最大长度
            min_length=None                最小长度
            strip=True                     是否移除用户输入空白
            
        IntergerField(Field)
            max_value = None            最大值
            min_value = None            最小值
        
        DecimalField(IntergerField)
            max_value=None                 最大值
            min_value=None                 最小值
            max_digits=None                总长度
            decimal_places=None            小数位长度
            
        BaseTemporalField(Field)        
            input_forats=None            时间格式化
        
        DateField(BaseTemporalField)      格式:2015-09-01
        TimeField(BaseTemporalField)      格式:11:12
        DateTimeField(BaseTemporalField)  格式:2015-09-01 11:12
        
        RegexField(charField)
            regex,                        自定义正则表达式
            max_length=None,              最大长度
            min_length=None,              最小长度
            error_message=None            {"invalid":"..."}
            
        FileField(Field)
            allow_empty_file=False        是否允许空文件
        
        ChoiceField(Field)
            choices=(),        选项,如:choices = ((0,'上海’),(1,,'北京')
            required=True      是否必填
            widget=None        插件,默认select插件
            label=None         Label内容
            initial=None       初始值
            help_text='',      帮助提示
        
        TypeChoiceField(ChoiceField)
            coerce = lambda val: val    对选中的值进行一次转换
            empty_value = ''            空的默认值
            
        ComboFiel(Field)
            fields=()           使用多个验证,如下:即验证最大程度20,又验证邮箱格式
                                fields.ComboField(fields=[fields.CharField(max_length=20),fields.EmailField(),]
                                
        GenericIPAddressField
            protocol='both',             both,ipv4,ipv6支持的IP格式
            unpack_ipv4=False            解析ipv4地址,如果是::ffff:192.0.0.2.1 可以解析为192.0.0.2.1
            
        SlugField(CharField)             数字,字母,下划线,减号(连接符)

在form中使用组件

from  django.core.exceptions import NON_FIELD_ERRORS,ValidationError
class UserForm(forms.Form):
        username = forms.CharField(min_length=2, label='用户名', 
             error_messages={"required": "该字段不能为空"},
             widget= widgets.TextInput(attrs={'class':"form-control"})) password = forms.CharField(min_length=4,
                     label='密码',
                     widget=widgets.PasswordInput(attrs={'class':"form-control"})) repwd = forms.CharField(min_length=4,
                   label='重复密码',
                   widget= widgets.TextInput(attrs={'class':"form-control"})) email = forms.EmailField(label='邮箱',
                    error_messages={"required": "该字段不能为空", "invalid":"格式输入错误"},     widget= widgets.TextInput(attrs={'class': "form-control"})) tel = forms.CharField(label="电话号码",
                     error_messages={"required": "该字段不能为空"}, widget=widgets.TextInput(attrs={'class': "form-control"})) def clean_username(self): val = self.cleaned_data.get("username") # 获取输入的名字 ret = UserInfo.objects.filter(name=val) # 从数据库中查询是否有该用户存在if not ret: return val else: raise ValidationError("该用户已注册") def clean_tel(self): var = self.cleaned_data.get("tel") if len(var) == 11: return var else: raise ValidationError("手机号码必须为11位!") def clean(self): pwd = self.cleaned_data.get("password") r_pwd = self.cleaned_data.get("repwd") if pwd and r_pwd: if pwd == r_pwd: return self.cleaned_data else: raise ValidationError('两次密码不一致') else: return self.cleaned_data

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

方式一:

 1 from django.forms import Form
 2 from django.forms import widgets
 3 from django.forms import fields
 4 from django.core.validators import RegexValidator
 5  
 6 class MyForm(Form):
 7  
 8     user = fields.ChoiceField(
 9         # choices=((1, '上海'), (2, '北京'),),
10         initial=2,
11         widget=widgets.Select
12     )
13  
14     def __init__(self, *args, **kwargs):
15         super(MyForm,self).__init__(*args, **kwargs)
16         # self.fields['user'].widget.choices = ((1, '上海'), (2, '北京'),)
17         #
18         self.fields['user'].widget.choices = models.Classes.objects.all().value_list('id','caption')

方式二:

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

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

 

四 自定义验证规则

方式一 使用字段钩子或者全局钩子

from  django.core.exceptions import NON_FIELD_ERRORS,ValidationError
class UserForm(forms.Form):
        username = forms.CharField(min_length=2, 
                     label='用户名',
                     error_messages={"required": "该字段不能为空"},
                     widget=widgets.TextInput(attrs={'class':"form-control"})) password = forms.CharField(min_length=4,
                     label='密码',
                     widget=widgets.PasswordInput(attrs={'class':"form-control"})) repwd = forms.CharField(min_length=4,
                     label='重复密码',
                     widget= widgets.TextInput(attrs={'class':"form-control"})) email = forms.EmailField(label='邮箱',
                    error_messages={"required": "该字段不能为空", "invalid":"格式输入错误"}, widget=widgets.TextInput(attrs={'class': "form-control"})) tel = forms.CharField(label="电话号码",
                 error_messages={"required": "该字段不能为空"}, widget=widgets.TextInput(attrs={'class': "form-control"}))
def clean_username(self): val = self.cleaned_data.get("username") # 获取输入的名字 ret = UserInfo.objects.filter(name=val) # 从数据库中查询是否有该用户存在if not ret: return val else: raise ValidationError("该用户已注册") def clean_tel(self): var = self.cleaned_data.get("tel") if len(var) == 11: return var else: raise ValidationError("手机号码必须为11位!") def clean(self): pwd = self.cleaned_data.get("password") r_pwd = self.cleaned_data.get("repwd") if pwd and r_pwd: if pwd == r_pwd: return self.cleaned_data else: raise ValidationError('两次密码不一致') else: return self.cleaned_data

 方式二 使用validators参数进行正则表达式匹配

1 from django.forms import Form
2 from django.forms import widgets
3 from django.forms import fields
4 from django.core.validators import RegexValidator
5  
6 class MyForm(Form):
7     user = fields.CharField(
8         validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
9     )

通过正则表达式验证IP地址以及端口号

ipaddr_validate="^((?:(2[0-4]\d)|(25[0-5])|([01]?\d\d?))\.){3}(?:(2[0-4]\d)|(255[0-5])|([01]?\d\d?))$"
port_validate='^([0-9]|[1-9]\d|[1-9]\d{2}|[1-9]\d{3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$'
from django.forms import Form,fields
from django.forms import widgets,forms
import re
ipaddr_validate="^((?:(2[0-4]\d)|(25[0-5])|([01]?\d\d?))\.){3}(?:(2[0-4]\d)|(255[0-5])|([01]?\d\d?))$"
port_validate='^([0-9]|[1-9]\d|[1-9]\d{2}|[1-9]\d{3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$'
class dbinfo_create(Form):
    data_mode_type=fields.CharField(required=True,error_messages={'required':'数据库模型不能为空.'})
    database_type=fields.CharField(required=True,error_messages={'required':'数据库类型不能为空'})
    host=fields.RegexField(ipaddr_validate,required=True,error_messages={'required':'IP不能为空','invalid':'不合法的IP地址'})
    port=fields.RegexField(port_validate,required=True,error_messages={'required':'端口不能为空.','invalid':'端口无效'})
    # instance_nikename=fields.CharField(max_length=20,error_messages={'required':'端口不能为空.',"max_length":"标题不能超过20个字"})
    db_business=fields.CharField(required=True,error_messages={'required':'请说明所属业务线'})
    DBA=fields.CharField(required=True,error_messages={'required':'请说明DBA'})
    responsible_person=fields.CharField(required=True, error_messages={'required':'请选择相关责任人!'})

五 通过Ajax提交并验证表单

<form id="form">
    <div class="form-group">
        <p style="font-size: 26px; color: #337ab7">注册新用户</p>
        <p><span id="summary-error"></span></p>
        {% csrf_token %}
        <p>
            <span>用户名:</span>{{ form_obj.username }}
            <span class="pull-right"></span>
        </p>

        <p>
            <span>密码:</span>{{ form_obj.password }}
            <span class="pull-right"></span>
        </p>

        <p>
            <span>确认密码:</span>{{ form_obj.re_pwd }}
            <span class="pull-right"></span>
        </p>
        <div class="row">
            <div class="col-md-10">
                <p>
                    Emil:{{ form_obj.email }}
                    <span class="pull-right"></span>
                </p>
            </div>

            <p class="col-md-2">
                <button class="pull-right btn-primary btn" style="margin-top: 18px" id="get_email_code">获取验证码</button>
            </p>
        </div>


        <p>
            <span>验证码</span>{{ form_obj.check_code }}
            <span class="pull-right"></span>
        </p>

        <label for="avatar">
            <span>上传头像</span>
            <img id="avatar_img" width="80" height="80" src="/media/avatar/default.jpg" style="margin-left: 10px">
        </label>
        <input type="file" id="avatar" style="display: none">
        <div>
            <input type="button" id='submit_info' class="btn-primary btn pull-right" value="提交">
        </div>
    </div>
</form>
HTML
   function bindSubmit() {
        $('#submit_info').click(function () {

            $("#form p").removeClass('has-error');
            $(".errors").html('');
            var subData = new FormData();
            var request_data = $('#form').serializeArray();
            $.each(request_data, function (index, data) {
                subData.append(data.name, data.value);
            });
            subData.append("avatar", $('#avatar')[0].files[0]);
            subData.append('csrfmiddlewaretoken', $("[name='csrfmiddlewaretoken']").val());

            $.ajax({
                url: "/register/",
                type: "post",
                processData: false,
                contentType: false,
                data: subData,
                dataType: 'json',
                success: function (data) {
                    console.log(data.error_msg);
                    if (!data.state) {
                        if (data.summary_error) {
                            $('#summary-error').html(data.summary_error)
                        }
                        $.each(data.error_msg, function (field, msg) {
                            if (field == "__all__") {
                                $('#summary-error').html(msg[0]).parent().addClass("has-error")
                            }
                            $('#id_' + field).next().html(msg[0]).addClass('errors').parent().addClass('has-error')
                        })
                    } else {
                        console.log(123);
                        location.href = '/index/'

                    }
                }

            })
        })
    }
JS
class RegisterForm(forms.Form):
    '''
    注册form表单校验
    '''
    username = forms.CharField(
        max_length=32,
        error_messages={'required': '用户名不能为空'},
        widget=widgets.TextInput(attrs={'class': "form-control"}))
    password = forms.CharField(
        max_length=32,
        error_messages={'required': '密码不能为空'},
        widget=widgets.PasswordInput(attrs={'class': "form-control"}))
    re_pwd = forms.CharField(
        max_length=32,
        error_messages={'required': '密码不能为空'},
        widget=widgets.PasswordInput(attrs={'class': "form-control"}))

    email = forms.EmailField(
        error_messages={'required': '邮箱不能为空'},
        widget=widgets.EmailInput(attrs={'class': "form-control"}))
    check_code = forms.CharField(
        widget=widgets.TextInput(attrs={'class': "form-control"}))

    def clean_username(self):
        '''
        校验用户是否存在
        :return:
        '''
        username = self.cleaned_data.get('username')
        user_obj = models.UserInfo.objects.filter(username=username)
        if not user_obj:
            return username
        else:
            raise ValidationError('该用户已存在')

    def clean(self):
        '''
        校验两次输入的密码是否一致
        :return:
        '''
        password = self.cleaned_data.get('password')
        repwd = self.cleaned_data.get('re_pwd')
        if password == repwd:
            return self.cleaned_data
        else:
            raise ValidationError("两次密码输入不一致")

    def clean_email(self):
        '''
        校验注册邮箱是否已经注册
        :return:
        '''
        email = self.cleaned_data.get('email')
        user_obh = models.UserInfo.objects.filter(email=email)

        if not user_obh:
            return email
        else:
            raise ValidationError("该邮箱已被注册")
form.py
def register(request):
    '''
    通过ajax实现用户注册
    :param request:
    :return:
    '''
    response = {'state': False, 'error_msg':"", 'summary_error': ""}

    if request.is_ajax():
        form_obj = blog_forms.RegisterForm(request.POST)
        if form_obj.is_valid():
            username = form_obj.cleaned_data.get('username')
            password = form_obj.cleaned_data.get('password')
            Email = form_obj.cleaned_data.get('email')
            valid_code = form_obj.cleaned_data.get('check_code')
            avatar_obj = request.FILES.get('avatar')
            check_valid = request.session['valid_code']
            if valid_code == check_valid:
                extra = {}
                if avatar_obj:
                    extra["avatar"] = avatar_obj
                blog_obj = models.Blog.objects.create(
                    title="%s的博客" % username,
                    site_name="%s的个人站点" % username,
                    theme="default.css")

                models.UserInfo.objects.create_user(username=username, password=password, blog=blog_obj, email=Email, **extra)
                response['state'] = True
                return JsonResponse(response)
            else:
                response['summary_error'] = '验证码错误'
                return JsonResponse(response)
        else:

            response['error_msg'] = form_obj.errors
            return JsonResponse(response)
    elif request.method == 'GET':
        form_obj = blog_forms.RegisterForm()
        return render(request, 'register.html', {'form_obj': form_obj})
View.py

 

posted on 2018-07-22 17:28  cs_1993  阅读(208)  评论(0编辑  收藏  举报