Auth模块
auth模块是Django自带的用户认证模块:
我们在开发一个网站的时候,无可避免的需要设计实现网站的用户系统。此时我们需要实现包括用户注册、用户登录、用户认证、注销、修改密码等功能,这还真是个麻烦的事情呢。
Django作为一个完美主义者的终极框架,当然也会想到用户的这些痛点。它内置了强大的用户认证系统--auth,它默认使用 auth_user 表来存储用户数据。
为了方便快捷的帮开发者完成登录相关的认证交互功能。
auth_user表常用操作:
from django.contrib.auth.models import User #创建普通用户 User.objects.create_user(username='Owen', password='123') #创建超级用户 User.objects.create_superuser(username='root',password='root',email='root@root.com') #获取第一个用户 user = User.objects.first() #修改密码 user.set_password('000') user.save() #注:修改完成后必须要进行保存,即执行save()方法 #校验密码 res = user.check_password('000')
auth组件常用功能:
# 校验用户账号及密码,校验成功返回user对象 from django.contrib.auth import authenticate #该模块需要两个参数,用户名和密码 user=authenticate(username=usr, password=pwd) # 注册用户到request对象中,注册成功可以用request.user访问当前登录用户(会形成session记录) from django.contrib.auth import login login(request, user) # 注册authenticate成功(当前登录)的用户 # 注销当前注册的user(用户注销) from django.contrib.auth import logout logout(request) # 校验用户登录状态 # 视图函数中使用 if request.user.is_authenticated(): pass # 模板语言中使用 {% if request.user.is_authenticated %} {% else %} {% endif %} # 校验登录状态的装饰器 from django.contrib.auth.decorators import login_required @login_required(login_url='/user_login/') def user_home(request): return render(request, 'user.html', locals())
若用户没有登录,则会跳转到django默认的 登录URL '/accounts/login/ ' 并传递当前访问url的绝对路径 (登陆成功后,会重定向到该路径)。
如果需要自定义登录的URL,则需要在settings.py文件中通过LOGIN_URL进行修改。
# 在settings.py中设置: LOGIN_URL = '/login/' # 这里配置成你项目登录页面的路由
扩展User表:
# app/models.py #第一种方式:(建议使用) from django.contrib.auth.models import AbstractUser class User(AbstractUser): # 增加自定义字段 info = models.TextField(null=True) # settings.py配置 AUTH_USER_MODEL = 'app.User' # 在视图函数中导入的模块就是: from app.models import User
#第二种方式:(不建议使用) from django.contrib.auth.models import User Create your models here. class UserInfo(models.Model): id = models.AutoField(primary_key=True) info = models.TextField(null=True) user = models.OneToOneField(to=User, to_field='username', db_constraint=False, null=True, on_delete=models.SET_NULL)
Forms组件
表单字段的校验:
<!-- register.html核心代码 --> <form action="" method="post" novalidate> <input type="text" name="usr"> <input type="password" name="pwd"> <input type="email" name="email"> <input type="submit" value="注册"> </form>
# views.py核心代码 from django.shortcuts import render, HttpResponse from django import forms # 自定义校验表单字段的类,继承forms.Form,并用forms下具体字段完成校验 class CheckForm(forms.Form): # 通过error_messages自定义错误信息 usr = forms.CharField(min_length=3, max_length=10, error_messages={'min_length':'长度至少为3'}) pwd = forms.CharField(min_length=3, max_length=10) email = forms.EmailField(error_messages={'invalid':'邮箱不合法', 'required': '必填项'}) def register(request): if request.method == "GET": return render(request, 'register.html') if request.method == "POST": # 校验请求的所有数据 check_form = CheckForm(request.POST) if check_form.is_valid(): # 查看校验成功的数据,为字典类型 print(check_form.cleaned_data) return HttpResponse('注册成功') else: # 查看校验失败的数据,为封装的字典类型 print(check_form.errors) return HttpResponse('注册失败')
表单元素的渲染:
# view.py改动代码 class CheckForm(forms.Form): usr = forms.CharField(min_length=3, max_length=10, label="用户名") pwd = forms.CharField(min_length=3, max_length=10, label="密码") email = forms.EmailField(, label="邮箱") def register(request): if request.method == "GET": check_form = CheckForm() return render(request, 'register.html', {'check_form': check_form})
<!-- register.html核心代码 --> <!-- 方式一 --> <form action="" method="post"> {{ check_form.usr }} {{ check_form.pwd }} {{ check_form.email }} <input type="submit" value="注册"> </form> <!-- 方式二 --> <form action="" method="post"> {% for foo in check_form %} <label for="{{ foo.id_for_label }}" class="col-sm-2 control-label">{{ foo.label }}</label> {{ foo }} {% endfor %} <input type="submit" value="注册"> </form> <!-- 方式三 --> <form action="" method="post"> <table>{{ check_form.as_table}}</table> <input type="submit" value="注册"> </form> <!-- 方式四 --> <form action="" method="post"> <ul>{{ check_form.as_ul}}</ul> <input type="submit" value="注册"> </form> <!-- 方式五 --> <form action="" method="post"> {{ check_form.as_p}} <input type="submit" value="注册"> </form>
错误信息的渲染:
# views.py class CheckForm(forms.Form): usr = forms.CharField( min_length=3, max_length=10, error_messages={ 'min_length': '长度至少为3', 'max_length': '长度最多为10', 'required': '必填项' }, label="用户名" ) pwd = forms.CharField( min_length=3, max_length=10, error_messages={ 'min_length': '长度至少为3', 'max_length': '长度最多为10', 'required': '必填项' }, label="密码" ) email = forms.EmailField( error_messages={ 'invalid': '邮箱不合法', 'required': '必填项'} ) def register(request): if request.method == "GET": check_form = CheckForm() if request.method == "POST": check_form = CheckForm(request.POST) if check_form.is_valid(): return HttpResponse('注册成功') return render(request, 'register.html', locals())
<form action="" method="post" novalidate> {% for ele in check_form %} <p> {{ ele.label }}:{{ ele }} <span style="color: red">{{ ele.errors.0 }}</span> </p> {% endfor %} <input type="submit" value="注册"> </form>
组件的参数设置:
class Ret(Form): name = forms.CharField(max_length=10, min_length=2, label='用户名', error_messages={'required': '该字段不能为空', 'invalid': '格式错误', 'max_length': '太长', 'min_length': '太短'}, widget=widgets.TextInput(attrs={'class':'form-control'})) pwd = forms.CharField(max_length=10, min_length=2, widget=widgets.PasswordInput(attrs={'class':'form-control'})) email = forms.EmailField(label='邮箱', error_messages={'required': '该字段不能为空', 'invalid': '格式错误'})
局部钩子:
# 在自定义验证类CheckForm中添加局部验证钩子 class CheckForm(forms.Form): ... def clean_usr(self): name = self.cleaned_data.get('usr') # type: str import re if re.match('^[0-9]', name): from django.core.exceptions import ValidationError raise ValidationError('不能以数字开头') return name
全局钩子:
# views.py class CheckForm(forms.Form): usr = forms.CharField( min_length=3, max_length=10, error_messages={ 'min_length': '长度至少为3', 'max_length': '长度最多为10', 'required': '必填项' }, label="用户名", widget=forms.TextInput(attrs={'placeholder': '请输入用户名'}) ) pwd = forms.CharField( min_length=3, max_length=10, error_messages={ 'min_length': '长度至少为3', 'max_length': '长度最多为10', 'required': '必填项' }, label="密码", widget=forms.PasswordInput(attrs={'placeholder': '请输入密码'}) ) re_pwd = forms.CharField( min_length=3, max_length=10, error_messages={ 'min_length': '长度至少为3', 'max_length': '长度最多为10', 'required': '必填项' }, label="确认密码", widget=forms.PasswordInput(attrs={'placeholder': '请确认密码'}) ) def clean(self): pwd = self.cleaned_data.get('pwd') re_pwd = self.cleaned_data.get('re_pwd') if pwd == re_pwd: return self.cleaned_data from django.core.exceptions import ValidationError raise ValidationError('两次密码不一致') def register(request): if request.method == "GET": check_form = CheckForm() if request.method == "POST": check_form = CheckForm(request.POST) if check_form.is_valid(): return HttpResponse('注册成功') else: # 拿到全局钩子抛出的错误信息 all_error = check_form.errors.get('__all__', None) return render(request, 'register.html', locals())
<form action="" method="post" novalidate> {% for ele in check_form %} <p> {{ ele.label }}:{{ ele }} <span style="color: red">{{ ele.errors.0 }}</span> {% if ele.label == '确认密码' %} <span style="color: red">{{ all_error.0 }}</span> {% endif %} </p> {% endfor %} <input type="submit" value="注册"> </form>