Form组件、auth认证组件、自定义图片验证码登录、自定义分页

python

12.7 Form组件

Django form组件实现的功能:生成页面可用的HTML标签、对用户提交的数据进行校验、保留上次输入内容

12.71 使用form组件实现注册功能

views.py:

# 按照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 url

from django.contrib import admin

from 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, HttpResponse

from django.contrib import auth

from django.contrib.auth.models import User

# from app01.models import UserInfo

from 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 models

from 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

回到顶部