Form组件、auth认证组件、自定义图片验证码登录、自定义分页
12.7 Form组件
Django form组件实现的功能:生成页面可用的HTML标签、对用户提交的数据进行校验、保留上次输入内容
12.71 使用form组件实现注册功能
# 按照Django form组件的要求写一个类from django import forms
from django.forms import fields
from django.core.validators import RegexValidator
from django.core.exceptions import ValidationError
# 自定义验证规则
def passward_validate(value):
mobile_re = re.compile(r"^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$")
ifnot mobile_re.match(value):
raise ValidationError("手机号码格式错误")
class RegForm(forms.Form):
username = forms.CharField(
min_length=8,
label="用户名",
initial="张三"# 设置默认值,初始值,input框里面的初始值
error_messages={ #重写错误信息。
"required": "不能为空",
"invalid": "格式错误",
"min_length": "用户名最短8位"
}
)
pwd = forms.CharField(
min_length=6,
label="密码",
widget=forms.widgets.PasswordInput(attrs={"class": "c1"}, render_value=True)
#给input标签添加class="c1",刷新页面保留原input框中的值
validators=[RegexValidator(r"^[0-9]+$", "请输入数字"), RegexValidator(r"^159[0-9]+$", "数字必须以159开头")], #自定义正则校验器,如果不符合正则匹配则显示"请输入数字"
validators=[passward_validate, ],#使用自定义验证函数
)
gender = forms.fields.ChoiceField(
choices=((1, "男"), (2, "女"), (3, "保密")),
label="性别",
initial=3,
widget=forms.widgets.RadioSelect() #单radio值为字符串
)
hobby = forms.fields.ChoiceField( #单选Select
choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
label="爱好",
initial=3,
widget=forms.widgets.Select()
)
hobby = forms.fields.MultipleChoiceField( #多选Select
choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
label="爱好",
initial=[1, 3],
widget=forms.widgets.SelectMultiple()
)
keep = forms.fields.ChoiceField( #单选checkbox
label="是否记住密码",
initial="checked",
widget=forms.widgets.CheckboxInput()
)
hobby = forms.fields.MultipleChoiceField( #多选checkbox
choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
label="爱好",
initial=[1, 3],
widget=forms.widgets.CheckboxSelectMultiple()
)
def__init__(self, *args, **kwargs): #动态choices选项
super(RegForm,self).__init__(*args, **kwargs)
# self.fields["hobby"].choices = ((1, "篮球"), (2, "足球"),)
self.fields["hobby"].choices = models.Hobby.objects.all().values_list("id","name")
# 使用form组件实现注册方式
def register2(request):
form_obj = RegForm()
if request.method == "POST":
form_obj = RegForm(request.POST) # 实例化form对象的时候,把post提交过来的数据直接传进去
if form_obj.is_valid(): # 调用form_obj校验数据的方法
#print(form_obj.cleaned_data) # 获取所有经过验证的数据
models.User.objects.create(**form_obj.cleaned_data)
return HttpResponse("注册成功")
return render(request, "register.html", {"form_obj": form_obj})
register.html:
<!DOCTYPE html><html lang="en">
<head>
<meta charset="UTF-8">
<title>注册2</title>
</head>
<body>
<form action="/reg2/" method="post" novalidate autocomplete="off">
{% csrf_token %}
<div>
<label for="{{ form_obj.username.id_for_label }}">
{{ form_obj.username.label }}
</label>
{{ form_obj.username }}
<span class="error">{{ form_obj.username.errors.0 }}</span>
</div>
<div>
<label for="{{ form_obj.pwd.id_for_label }}">
{{ form_obj.pwd.label }}
</label>
{{ form_obj.pwd }}
<span class="error">{{ form_obj.pwd.errors.0 }}</span>
</div>
<div>
<label for="">{{ form_obj.gender.label }}</label>
{{ form_obj.gender }}
<span class="error">{{ form_obj.gender.errors.0 }}</span>
</div>
<div>
<label for="">{{ form_obj.hobby.label }}</label>
{{ form_obj.hobby }}
<span class="error">{{ form_obj.hobby.errors.0 }}</span>
</div>
<div>
<label for="">{{ form_obj.keep.label }}</label>
{{ form_obj.keep }}
<span class="error">{{ form_obj.keep.errors.0 }}</span>
</div>
<div>
<input type="submit" class="btn btn-success" value="注册">
</div>
</form>
</body>
</html>
12.72 Hook方法
除了上面两种方式,还可以在Form类中定义钩子函数,来实现自定义的验证功能
局部钩子:
在Form类中定义 clean_字段名() 方法,就能够实现对特定字段进行校验
class LoginForm(forms.Form):username
= forms.CharField(min_length
=8,label
="用户名",initial
="张三",error_messages
={"required": "不能为空","invalid": "格式错误","min_length": "用户名最短8位"},
widget
=forms.widgets.TextInput(attrs={"class": "form-control"}))
...
# 定义局部钩子,用来校验username字段def clean_username(self):
value = self.cleaned_data.get("username")
if"666"in value:
raise ValidationError("光喊666是不行的")
else:
return value
全局钩子:
在Form类中定义 clean() 方法,就能够实现对字段进行全局校验
class LoginForm(forms.Form):...
password
= forms.CharField(min_length
=6,label
="密码",widget
=forms.widgets.PasswordInput(attrs={"class": "form-control"}, render_value=True))
re_password
= forms.CharField(min_length
=6,label
="确认密码",widget
=forms.widgets.PasswordInput(attrs={"class": "form-control"}, render_value=True))
...
# 定义全局的钩子,用来校验密码和确认密码字段是否相同def clean(self):
password_value = self.cleaned_data.get("password")
re_password_value = self.cleaned_data.get("re_password")
if password_value == re_password_value:
return self.cleaned_data
else:
self.add_error("re_password", "两次密码不一致")
raise ValidationError("两次密码不一致")
12.8 auth认证组件
urls.py:
from django.conf.urls import urlfrom django.contrib import adminfrom app01 import views
urlpatterns
= [url(r
"^admin/", admin.site.urls),url(r
"^login/", views.login),url(r
"^register/", views.register),url(r
"^home/", views.home),url(r
"^logout/", views.logout),url(r
"^set_password/", views.set_password),]
views.py:
from django.shortcuts import render, redirect, HttpResponsefrom django.contrib import authfrom django.contrib.auth.models import User# from app01.models import UserInfofrom django.contrib.auth.decorators import login_required
def login(request):
if request.method == "POST":
username = request.POST.get("username")
pwd = request.POST.get("pwd")
# authenticate():校验用户名、密码,认证成功返回user对象
user_obj = auth.authenticate(username=username, password=pwd)
if user_obj:
# 内置的login方法
auth.login(request, user_obj)
# 生成Session数据,存一下user_id 然后把sessionid写入Cookie
# 后续每一次请求来的时候,AuthenticationMiddleware中的process_request方法中
# 会取到user_id,进而取到user对象,然后添加到request.user属性中 --> request.user = user_obj
# 后续可以通过request.user拿到当前的登陆用户对象,否则得到一个匿名用户对象
return redirect("/home/")
return render(request, "login.html")
def register(request):
if request.method == "POST":
username = request.POST.get("username")
pwd = request.POST.get("pwd")
# 调用内置的创建普通用户的专用方法,创建一个新的普通用户
User.objects.create_user(username=username, password=pwd)
#调用内置的创建超级用户的专用方法,创建一个新的超级用户
#User.objects.create_superuser(username="用户名",password="密码")
return render(request, "register.html")
@login_required
#auth提供的装饰器工具,用来快捷的给某个视图添加登录校验。若用户没有登录,则会跳转到django默认的登录URL "/accounts/login/ " 并传递当前访问url的绝对路径 (登陆成功后,会重定向到该路径)。如果需要自定义登录的URL,则需要在settings.py文件中通过LOGIN_URL进行修改:LOGIN_URL = "/login/"
def home(request):
return render(request, "home.html")
# 调用auth内置的注销方法
#当调用该函数时,当前请求的session信息会全部清除。该用户即使没有登录,使用该函数也不会报错
def logout(request):
auth.logout(request)
return redirect("/login/")
@login_required
def set_password(request):
if request.method == "POST":
old_pwd = request.POST.get("old_pwd")
pwd = request.POST.get("pwd")
re_pwd = request.POST.get("re_pwd")
user_obj = request.user
if user_obj.check_password(old_pwd):# 先校验原密码是否正确,正确返回True,否则返回False
if pwd == re_pwd:
user_obj.set_password(pwd) # 去数据库修改密码
user_obj.save() # 修改密码一定要保存
return redirect("/login/")
else:
return HttpResponse("两次输入不一致")
else:
return HttpResponse("原密码错误")
return render(request, "set_password.html")
login.html:
<body><h1>欢迎登陆</h1>
<form action="" method="post">
{% csrf_token %}
<input type="text" name="username">
<input type="password" name="pwd">
<input type="submit" value="登录">
</form>
</body>
register.html:
<body><h1>欢迎注册</h1>
<form action="/reg/" method="post">
{% csrf_token %}
<input type="text" name="username">
<input type="password" name="pwd">
<input type="submit" value="注册">
</form>
</body>
home.html:
<body><h1>Hello,{{ request.user.username }}</h1> #request.user获取当前用户对象
<a href="/logout/">注销</a>
<a href="/set_password/">修改密码</a>
</body>
set_password.html:
<body><form action="" method="post">
{% csrf_token %}
<p>原密码:<input type="password" name="old_pwd"></p>
<p>新密码:<input type="password" name="pwd"></p>
<p>重复密码:<input type="password" name="re_pwd"></p>
<p><input type="submit" value="修改"></p>
</form>
</body>
12.81 扩展默认的auth_user表
User类内没有实现方法,只是继承内置的 AbstractUser 类,通过继承内置的 AbstractUser 类,来自定义一个Model类,这样既能根据项目需求灵活的设计用户表,又能使用Django强大的认证系统了
models:
from django.db import modelsfrom django.contrib.auth.models import AbstractUser
class UserInfo(AbstractUser):phone
= models.CharField(max_length=11)
注意:按上面的方式扩展了内置的auth_user表之后,一定要在settings.py中告诉Django,现在使用新定义的UserInfo表来做用户认证
# 引用Django自带的User表,继承使用时需要设置AUTH_USER_MODEL = "app01.UserInfo"
自定义认证系统默认使用的数据表之后,就可以像使用默认的auth_user表那样使用自定义的UserInfo表了,比如:
创建普通用户:
UserInfo.objects.create_user(username="用户名", password="密码")
创建超级用户:
UserInfo.objects.create_superuser(username="用户名", password="密码")
注意:一旦指定了新的认证系统所使用的表,就需要重新在数据库中创建该表,而不能继续使用原来默认的auth_user表
12.9 自定义图片验证码登录
login.html:
<!DOCTYPE html><html lang="en">
<head>
<meta charset="UTF-8">
<title>欢迎登陆</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.min.css">
<link rel="stylesheet" href="/static/mystyle.css">
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-4 col-md-offset-4" id="login-form">
<form autocomplete="off" novalidate> {# 去掉浏览器验证和提示 #}
<div class="form-group">
<label for="{{ form_obj.username.id_for_label }}">
{{ form_obj.username.label }}</label>
{{ form_obj.username }}
{# <span class="error">{{ form_obj.username.errors.0 }}</span> #}
{#ajax提交数据,此处不刷新#}
</div>
<div class="form-group">
<label for="{{ form_obj.password.id_for_label }}">
{{ form_obj.password.label }}</labelForm组件、auth认证组件、自定义图片验证码登录、自定义分页 的全部内容, 来源链接: utcz.com/z/529893.html