Django Form表单

来源:互联网 发布:网络包工头在哪找活 编辑:程序博客网 时间:2024/06/05 06:09

Django Form表单的好处

  • 对用户提交的数据验证
  • 自动生成错误信息
  • 打包用户提交的正确信息
  • 能够在input框里保留上次输入的错误信息
  • 定制页面的html标签

构建一个Form表单

创建form类

from django.forms import Form,fields,widgetsfrom django.core.validators import RegexValidatorfrom django.core.exceptions import ValidationErrorfrom blog import modelsclass RegisterForm(Form):    email = fields.CharField(        required=True,        error_messages={"required":"邮箱不能为空"},        widget=widgets.EmailInput(attrs={"placeholder":"需要通过邮箱激活账户","class":"form-control",}),        validators=[RegexValidator("[\w!#$%&'*+/=?^_`{|}~-]+(?:\.[\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[\w](?:[\w-]*[\w])?","请输入正确的邮箱格式")]    )    telephone = fields.CharField(        required=True,        error_messages={"required": "手机号不能为空"},        widget=widgets.EmailInput(attrs={"placeholder": "需要通过手机号激活账户", "class": "form-control"}),        validators=[RegexValidator(            "^1(3|4|5|7|8)\d{9}$","手机号码有误")]    )    username = fields.CharField(        required=True,        min_length=4,        error_messages={            "required":"用户名不能为空",            "min_length":"用户名不能少于4个字符",        },        widget=widgets.TextInput(attrs={"placeholder":"登录用户名,不少于4个字符","class":"form-control"})    )    nick_name = fields.CharField(        required=True,        min_length=2,        error_messages={            "required": "昵称不能为空",            "min_length": "昵称不能少于2个字符",        },        widget=widgets.TextInput(attrs={"placeholder": "昵称,不少于2个字符", "class": "form-control"})    )    password = fields.CharField(        required=True,        min_length=8,        error_messages={            "required": "密码不能为空",            "min_length": "密码不能少于8个字符",        },        widget=widgets.PasswordInput(attrs={"placeholder": "至少8位,且必须包含字母,数字,特殊字符", "class": "form-control"}),        validators=[RegexValidator("^(?![a-zA-Z0-9]+$)(?![^a-zA-Z/D]+$)(?![^0-9/D]+$).{10,20}$","密码必须包含字母,数字,特殊符号")]    )    repeat_password = fields.CharField(        required=True,        error_messages={            "required": "密码不能为空",        },        widget=widgets.PasswordInput(            attrs={"placeholder": "请再次输入密码", "class": "form-control"}),    )    def clean_username(self):#局部钩子        username = models.UserInfo.objects.filter(username=self.cleaned_data.get("username"))        if not username:            return self.cleaned_data.get("username")        else:            raise ValidationError("用户名已存在")    def clean_email(self):#局部钩子        email = models.UserInfo.objects.filter(email = self.cleaned_data.get("email"))        if not email:            return self.cleaned_data.get("email")        else:            raise ValidationError("邮箱已注册")    def clean(self):#全局钩子        password = self.cleaned_data.get("password")        repeat_password = self.cleaned_data.get("repeat_password")        if password == repeat_password:            return self.cleaned_data        else:            raise ValidationError("两次输入的密码不一致")

视图

def register(request):    if request.method == "GET":        form = RegisterForm()        return render(request, 'register.html', {"form": form})    elif request.is_ajax():        form = RegisterForm(request.POST)        registerResponse = {"user": None, "error_list": None}        # print(type(form))        if form.is_valid():            email = form.cleaned_data.get("email")            telephone = form.cleaned_data.get("telephone")            username = form.cleaned_data.get("username")            nick_name = form.cleaned_data.get("nick_name")            password = form.cleaned_data.get("password")            avatar_img = request.FILES.get("avatar_img")            models.UserInfo.objects.create_user(email=email, telephone=telephone, username=username,                                                nick_name=nick_name, password=password, avatar=avatar_img)            registerResponse["user"] =form.cleaned_data.get("username")            print(registerResponse["user"])        else:            registerResponse["error_list"] = form.errors        return HttpResponse(json.dumps(registerResponse))

模板

<!DOCTYPE html>  //实现一个简单的注册功能,结合form,ajax<html lang="en"><head>    <meta charset="UTF-8">    <title>Title</title>    <link rel="stylesheet" href="/static/css/bootstrap.min.css">    <link rel="stylesheet" href="/static/sweet/sweetalert2.min.css">    <link rel="stylesheet" href="/static/css/register.css">    <script src="/static/js/jquery-3.2.1.min.js"></script>    <script src="/static/js/bootstrap.min.js"></script>    <script src="/static/js/jquery.cookie.js"></script>    <script src="/static/sweet/sweetalert2.min.js"></script>    <style type="text/css">        .my-navbar a {            background: transparent !important;            color: #fff !important        }        .my-navbar a:hover {            color: #45bcf9 !important;            background: transparent;            outline: 0        }        #input{            color: red;        }        .avatar{            position: relative;            width: 60px;            height: 60px;        }        #avatar_file,#avatar_img{            position:absolute;            top:0;            left: 20px;            width: 60px;            height: 60px;        }        #avatar_file{            opacity: 0;        }    </style></head><body style="background-color: #f8f8f8"><nav class="navbar navbar-inverse navbar-fixed-top my-navbar">    <div class="container">        <div class="navbar-header">            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"                    data-target="#bs-example-navbar-collapse-1" aria-expanded="false">                <span class="sr-only">Toggle navigation</span>                <span class="icon-bar"></span>                <span class="icon-bar"></span>                <span class="icon-bar"></span>            </button>            <a class="navbar-brand" href="#" style="font-size: 30px">博&nbsp;客&nbsp;苑</a>        </div>        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">            <ul class="nav navbar-nav navbar-right">                <li><a href=""><span class="glyphicon glyphicon-home " style="font-size: 15px"></span>&nbsp;首&nbsp;页</a>                </li>                <li><a href="/sign_in/"><span class="glyphicon glyphicon-user" style="font-size: 15px"></span>&nbsp;登&nbsp;录</a>                </li>                <li><a href="/register/"><span class="glyphicon glyphicon-user" style="font-size: 15px"><span                        class=" glyphico glyphicon-plus-sign" style="font-size: 2px;"></span></span>&nbsp;注&nbsp;册</a>                </li>            </ul>        </div>    </div></nav><div class="container" style="margin-top: 100px">    <div class="row col-md-11 ">        <div class="col-md-offset-1">        <h3>注册新用户</h3>        <hr>    </div>        <div class="col-md-7">            <form class="form-horizontal" id="s1" method="post" novalidate>                {% csrf_token %}                <div class="form-group">                    <label for="inputEmail"                           class="col-sm-3 control-label  col-md-offset-1">邮&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;箱:</label>                    <div class="col-md-8">                        {{ form.email }}//form表单自动生成input框                    </div>                </div>                <div class="form-group">                    <label for="inputPhone" class="col-sm-3 control-label col-md-offset-1">手机号码:</label>                    <div class="col-md-8">                        {{ form.telephone }}                    </div>                </div>                <div class="form-group">                    <label for="inputUser" class="col-sm-3 control-label col-md-offset-1">用户名称:</label>                    <div class="col-md-8">                            {{ form.username }}                    </div>                </div>                <div class="form-group">                    <label for="inputNickname"                           class="col-sm-3 control-label col-md-offset-1">昵&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;称:</label>                    <div class="col-md-8">                        {{ form.nick_name }}                    </div>                </div>                <div class="form-group">                    <label for="inputPassword"                           class="col-sm-3 control-label col-md-offset-1">密&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;码:</label>                    <div class="col-md-8">                        {{ form.password }}                    </div>                </div>                <div class="form-group">                    <label for="inputRepeatPassword" class="col-sm-3 control-label col-md-offset-1">确认密码:</label>                    <div class="col-md-8">                           {{ form.repeat_password }}                    </div>                </div>                <div class="form-group">                    <label for="inputRepeatPassword" class="col-sm-3 control-label col-md-offset-1">头像:</label>                    <div class="col-md-8 avatar">                        <a href=""><img src="/static/img/default.png" alt="" id="avatar_img"></a>                        <input type="file" class="form-control" id="avatar_file">                    </div>                </div>                <div class="form-group">                    <div class="col-md-2" style="margin-left:330px">                        <input type="button" value="注&nbsp;&nbsp;册" class="form-control btn-primary" id="register">                    </div>                </div>                <div style="margin-left:230px">                    <span>点击"注册"按钮,表示您已同意和遵守<a href="">用户协议</a></span>                </div>            </form>        </div>        <div class="col-sm-1">            <table style="height:280px;border-color:#cccccc;border-left-style:solid;border-width:1px">                <tr>                    <td valign="top"></td>                </tr>            </table>        </div>        <div class="col-md-4">            <img src="/static/img/registersideimg.png" alt="" style="width: 300px;height: 280px;border-radius: 8px">        </div>    </div></div><script>    //头像预览$("#avatar_file").change(function () {    //this.files    var ele_file = $(this)[0].files[0];//获取当前文件    var read = new FileReader();//实例化read对象    read.readAsDataURL (ele_file);//获取当前文件的url    read.onload = function () {        $("#avatar_img").attr("src",this.result);//this.result 就是read.readAsDataURL获取到的url路径    }});//注册校验$("#register").on("click",function () {    var formData = new FormData();//实例化formData对象    formData.append("email",$("#id_email").val());//获取email值    formData.append("telephone",$("#id_telephone").val());//获取telephone值    formData.append("username",$("#id_username").val());//获取username值    formData.append("nick_name",$("#id_nick_name").val());//获取nick_name值    formData.append("password",$("#id_password").val());//获取password值    formData.append("repeat_password",$("#id_repeat_password").val());//获取repeat_password值    formData.append("avatar_img",$("#avatar_file")[0].files[0]);//获取文件二进制    $(".pull-right").html("");    $(".pull-right").parent().removeClass("has-error");    $.ajax({        url:"/register/",        type:"POST",        data:formData,        headers: {"X-CSRFToken": $.cookie('csrftoken')},        contentType:false,//必须加的字段,不加的话二进制文件传不过去        processData:false,        success:function (data) {            var dat = JSON.parse(data);            console.log(dat);            if (dat.user){                location.href = "/sign_in/"            }            else{                //jquery循环取出error_list里面的键值对                $.each(dat.error_list,function (i,j) {                    console.log(i,j);                    $span = $("<span>");//造span标签                    $span.addClass("pull-right").css("color","red");//让span标签显示在右边                    $span.html(j[0]);//给span赋值                    $("#id_"+i) .after($span).parent().addClass("has-error");                    if (i == "__all__"){                        $("input[name=repeat_password]").after($span);                    }                })            }        }    })})</script></body></html>

form补充

1 django内置字段

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-01TimeField(BaseTemporalField)    格式:11:12DateTimeField(BaseTemporalField)格式:2015-09-01 11:12DurationField(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.ModelMultipleChoiceFieldTypedChoiceField(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类型    ...

2 django 内置插件

TextInput(Input)NumberInput(TextInput)EmailInput(TextInput)URLInput(TextInput)PasswordInput(TextInput)HiddenInput(TextInput)Textarea(Widget)DateInput(DateTimeBaseInput)DateTimeInput(DateTimeBaseInput)TimeInput(DateTimeBaseInput)CheckboxInputSelectNullBooleanSelectSelectMultipleRadioSelectCheckboxSelectMultipleFileInputClearableFileInputMultipleHiddenInputSplitDateTimeWidgetSplitHiddenDateTimeWidgetSelectDateWidget

3 表单渲染

对于<label>/<input> 对,还有几个输出选项:{{ form.as_table }} 以表格的形式将它们渲染在<tr> 标签中{{ form.as_p }} 将它们渲染在<p> 标签中{{ form.as_ul }} 将它们渲染在<li> 标签中可以用这种方式生成,但推荐使用,不灵活,不易控