Django组件-forms组件

forms组件

一、校验字段功能

针对一个实例:注册用户讲解。

模型:使用django的auth_user表

模板:register.html

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

</head>
<body>

<form action="" method="post">
    {% csrf_token %}
    <div>
        <label for="user">用户名</label>
        <p><input type="text" name="user" id="user"></p>
    </div>
    <div>
        <label for="pwd">密码</label>
        <p><input type="password" name="pwd" id="pwd"></p>
    </div>
    <div>
        <label for="r_pwd">确认密码</label>
        <p><input type="password" name="r_pwd" id="r_pwd"></p>
    </div>
     <div>
        <label for="email">邮箱</label>
        <p><input type="email" name="email" id="email"></p>
    </div>
    <input type="submit">
</form>

</body>
</html>

视图函数:register

class UserForm(forms.Form):  #校验规则
    user = forms.CharField(min_length=5,
                           error_messages={'required':'该字段不能为空'},
                           label='用户名',
                           widget=widgets.TextInput(attrs={'class':'input','id':'user'})
                           )
    pwd = forms.CharField(min_length=5,
                          error_messages={'required':'该字段不能为空'},
                          label='密码',
                          widget=widgets.PasswordInput(attrs={'class':'input','id':'pwd'})

                          )
    r_pwd = forms.CharField(min_length=5,
                            error_messages={'required': '该字段不能为空'},
                            label='确认密码',
                            widget=widgets.PasswordInput(attrs={'class': 'input','id':'r_pwd'})
                            )
    email = forms.EmailField(error_messages={'invalid':'邮箱格式错误','required': '该字段不能为空'},
                             label='邮箱',
                             widget=widgets.EmailInput(attrs={'class':'input','id':'email'})
                             )
    #自定义错误,进行第二次过滤(局部钩子)
    def clean_user(self):
        val=self.cleaned_data.get('user')
        print(val)
        # user_obj = auth.authenticate(username=val)
        ret = User.objects.filter(username=val)
        print(ret)
        if not ret:    #数据库找不到这个用户
            return val
        else:
            raise ValidationError('用户已存在!')
    def clean_pwd(self):
        val=self.cleaned_data.get('pwd')
        if val.isdigit():
            raise ValidationError('密码不能是纯数字!')
        else:
            return val
    def clean_email(self):
        val=self.cleaned_data.get('email')
        if not val.endswith('163.com'):
            raise ValidationError('邮箱必须是163邮箱!')
        else:
            return val
    def clean(self):  #全局钩子,什么情况下都会执行
        pwd=self.cleaned_data.get('pwd')
        r_pwd=self.cleaned_data.get('r_pwd')

        if pwd and r_pwd:
            if pwd==r_pwd:
                return self.cleaned_data
            else:
                raise ValidationError('两次密码不一致!')
        else:
            return self.cleaned_data

逻辑代码:

def register(request):
    import json
    if request.method == 'GET':
        form = UserForm()
        return render(request, 'reg.html',locals())
    else:
        form = UserForm(request.POST)
        if form.is_valid():    #对数据进行校验
            user = form.cleaned_data.get('user')   #form.cleaned_data为一个字典,里面存储着符合条件的字段
            pwd = form.cleaned_data.get('pwd')    
            email = form.cleaned_data.get('email')
            user_obj = User.objects.create_user(username=user,password=pwd,email=email)
            auth.login(request, user_obj)
            return HttpResponse('OK')
        else:
            errors=form.errors  #form.errors为一个字典,键是错误的字段,值是相关的错误的信息
            return HttpResponse(json.dumps(errors))

二、渲染标签功能

方式一:

<form action="" method="post">   //form表单和submit按钮需要自己写
    {% csrf_token %}
    {{ form.as_p }}

    <input type="submit">
</form>

方式二:

<form action="" method="post" novalidate>
                {% csrf_token %}
                <p> 用户名 {{ form.user }}<span class="error">{{ errors.user.0 }}</span> </p>            //{{ form.user }}渲染出user的input标签
                <p>密码 {{ form.pwd }}<span class="error">{{ errors.pwd.0 }}</span></p>
                <p>确认密码 {{ form.r_pwd }}<span class="error">{{ errors.r_pwd.0 }}</span></p>
                <p>邮箱 {{ form.email }}<span class="error">{{ errors.email.0 }}</span></p>

                <input type="submit" class="btn btn-success pull-right">
            </form>

方式三:

<form action="" method="post" novalidate>
                {% csrf_token %}
                {% for field in form %}
                    <div class="form-group">
                        <label for="">{{ field.label }}</label>
                        {{ field }} <span class="error">{{ field.errors.0 }}</span>
{#                        //{{ field }}为渲染出来的input标签#}
                        {% if field.label == "确认密码" %}
                           <span class="error">{{ g_error|default:"" }}</span>
                        {% endif %}
                    </div>
                {% endfor %}
                <input type="submit" class="btn btn-success pull-right">
            </form>

三、显示错误与重置输入信息功能

方式一:form表单操作

视图:

def reg(request):
    if request.method=="POST":
        print(request.POST)
        # 数据校验
        form=UserForm(request.POST)
        if form.is_valid():
            UserInfo.objects.create(**form.cleaned_data)
            return HttpResponse("OK")
        else:
            # print(form.cleaned_data)
            # print(form.errors) # {"user":["",]}
            # print(form.errors.get("user")[0]) # {"user":["",]}
            errors=form.errors
            if form.errors.get("__all__"):
                g_error=form.errors.get("__all__")[0]
            return render(request, "reg.html",locals())
    else:
         form=UserForm()
         return render(request,"reg.html",locals())

模板:

<form action="" method="post" novalidate>
                {% csrf_token %}
                {% for field in form %}
                    <div class="form-group">
                        <label for="">{{ field.label }}</label>
                        {{ field }} <span class="error">{{ field.errors.0 }}</span>
{#                        //{{ field }}为渲染出来的input标签#}
                        {% if field.label == "确认密码" %}
                           <span class="error">{{ g_error|default:"" }}</span>
                        {% endif %}
                    </div>
                {% endfor %}
                <input type="submit" class="btn btn-success pull-right">
            </form>

方式二:Ajax操作

视图:

def register(request):
    import json
    if request.method == 'GET':
        form = UserForm()
        return render(request, 'reg.html',locals())
    else:
        form = UserForm(request.POST)
        if form.is_valid():    #对数据进行校验
            user = form.cleaned_data.get('user')   #form.cleaned_data为一个字典,里面存储着符合条件的字段
            pwd = form.cleaned_data.get('pwd')
            email = form.cleaned_data.get('email')
            user_obj = User.objects.create_user(username=user,password=pwd,email=email)
            auth.login(request, user_obj)
            return HttpResponse('OK')
        else:
            errors=form.errors  #form.errors为一个字典,键是错误的字段,值是相关的错误的信息
            return HttpResponse(json.dumps(errors))

模板:

{% for field in form %}
    <div class="group">
        <label for="" class="label">{{ field.label }}</label>
        {{ field }}<span class="error"></span>
    </div>
{% endfor %}
<div class="group">
    <input type="submit" class="button" value="注册" id="zhuce">
</div>
<script src="/static/js/jquery.js"></script>
<script>
    $('#zhuce').click(function () {
        $.ajax({
            url:'/register/',
            type:'post',
            data:{
                user:$('#user').val(),
                pwd:$('#pwd').val(),
                r_pwd:$('#r_pwd').val(),
                email:$('#email').val()
            },
            success:function (response) {
                if(response=='OK'){
                    location.href='/books/'
                }
                else{
                    $.each(JSON.parse(response),function (i,j) {
                        if(i=='user'){
                            $('#user').next().html(j[0])
                        }if (i=='pwd'){
                            $('#pwd').next().html(j[0])
                        }if (i=='r_pwd'){
                            $('#r_pwd').next().html(j[0])
                        }if (i=='email'){
                            $('#email').next().html(j[0])
                        }if(i=='__all__'){
                            $('#r_pwd').next().html(j[0])
                        }
                    });

                }
            }
        })
    });
</script>

或者更简单一些:

视图:

def register(request):
    from django.http import JsonResponse
    if request.method == 'GET':
        form = UserForm()
        return render(request, 'reg.html',locals())
    else:
        form = UserForm(request.POST)
        res = {'user':None,'err_msg':''}
        if form.is_valid():    #对数据进行校验
            user = form.cleaned_data.get('user')   #form.cleaned_data为一个字典,里面存储着符合条件的字段
            res['user'] = user
            pwd = form.cleaned_data.get('pwd')
            email = form.cleaned_data.get('email')
            user_obj = User.objects.create_user(username=user,password=pwd,email=email)
            auth.login(request, user_obj)
        else:
            errors=form.errors  #form.errors为一个字典,键是错误的字段,值是相关的错误的信息
            res['err_msg'] = errors
        return JsonResponse(res)   #JsonResponse对字典进行序列化,底层封装了HttpResponse,相关信息Ajax接收后会自动反序列化,不需要再人为的反序列化.

模板:

<script src="/static/js/jquery.js"></script>
<script>
    $('#zhuce').click(function () {
        $.ajax({
            url: '/register/',
            type: 'post',
            data: {
                user: $('#user').val(),
                pwd: $('#pwd').val(),
                r_pwd: $('#r_pwd').val(),
                email: $('#email').val()
            },
            success: function (response) {                             //ajax已经自动将序列化的字典进行了反序列化
                if (response.user) {
                    location.href = '/books/'
                }
                else {
                    $('.error').html('');
                    $.each(response.err_msg,function (i,j) {
                        $('#'+i).next().html(j[0])
                    });
                }
            }
        })
    })
<script/>

四、局部钩子与全局钩子

参见  一、校验字段功能  视图部分代码,需要注意局部钩子只有在满足第一个条件之后才会执行,如果在第一个条件不满足就不会进一步执行局部钩子代码,相反,全局钩子什么时候都会 执行。

 五、扩展

如何往django自带的auth_user表中添加新的字段,如手机号?

models.py

from django.contrib.auth.models import AbstractUserclass 
UserInfo(AbstractUser): #相当于继承了auth_user表 tel = models.CharField(max_length=32)

settings

AUTH_USER_MODEL = 'app01.UserInfo'    

#app01自定义,为UserInfo所在的app

随后可执行:python manage.py makemigrations

      python manage.py migrate

这时django自带的auth_user表将会消失,取而代之的是app01_userinfo

原文地址:https://www.cnblogs.com/fengchong/p/9908917.html