Auth模块、Forms组件

Auth模块

auth模块是Django自带的用户认证模块:

我们在开发一个网站的时候,无可避免的需要设计实现网站的用户系统。此时我们需要实现包括用户注册、用户登录、用户认证、注销、修改密码等功能,这还真是个麻烦的事情呢。

Django作为一个完美主义者的终极框架,当然也会想到用户的这些痛点。它内置了强大的用户认证系统–auth,它默认使用 auth_user 表来存储用户数据。

为了方便快捷的帮开发者完成登录相关的认证交互功能。

auth_user表常用操作:

from django.contrib.auth.models import User
#创建普通用户
User.objects.create_user(username=‘Owen’, password=‘’) #创建超级用户
User.objects.create_superuser(username=‘root’,password=‘root’,email=‘root@root.com’) #获取第一个用户
user = User.objects.first() #修改密码
user.set_password(‘’)
user.save() #注:修改完成后必须要进行保存,即执行save()方法 #校验密码
res = user.check_password(‘’)

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):

# 增加自定义字段<br/>
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)<br/>
 info = models.TextField(null=True)<br/>
 user = models.OneToOneField(to=User, to_field=&#39;username&#39;, db_constraint=False, null=True, on_delete=models.SET_NULL)</pre>

Forms组件

表单字段的校验:

&lt;!– register.html核心代码 –&gt;
&lt;form action=“” method=“post” novalidate&gt;

&lt;input type=&#34;text&#34; name=&#34;usr&#34;&gt;<br/>
&lt;input type=&#34;password&#34; name=&#34;pwd&#34;&gt;<br/>
&lt;input type=&#34;email&#34; name=&#34;email&#34;&gt;<br/>
&lt;input type=&#34;submit&#34; value=&#34;注册&#34;&gt;<br/>

&lt;/form&gt;

# views.py核心代码
from django.shortcuts import render, HttpResponse
from django import forms

自定义校验表单字段的类,继承forms.Form,并用forms下具体字段完成校验

class CheckForm(forms.Form):

# 通过error_messages自定义错误信息<br/>
usr = forms.CharField(min_length=3, max_length=10, error_messages={&#39;min_length&#39;:&#39;长度至少为3&#39;})<br/>
pwd = forms.CharField(min_length=3, max_length=10)<br/>
email = forms.EmailField(error_messages={&#39;invalid&#39;:&#39;邮箱不合法&#39;, &#39;required&#39;: &#39;必填项&#39;})

def register(request):

if request.method == &#34;GET&#34;:<br/>
    return render(request, &#39;register.html&#39;)<br/>
if request.method == &#34;POST&#34;:<br/>
    # 校验请求的所有数据<br/>
    check_form = CheckForm(request.POST)<br/>
    if check_form.is_valid():<br/>
        # 查看校验成功的数据,为字典类型<br/>
        print(check_form.cleaned_data)<br/>
        return HttpResponse(&#39;注册成功&#39;)<br/>
    else:<br/>
        # 查看校验失败的数据,为封装的字典类型<br/>
        print(check_form.errors)<br/>
return HttpResponse(&#39;注册失败&#39;)</pre>

表单元素的渲染:

# view.py改动代码
class CheckForm(forms.Form):

usr = forms.CharField(min_length=3, max_length=10, label=&#34;用户名&#34;)<br/>
pwd = forms.CharField(min_length=3, max_length=10, label=&#34;密码&#34;)<br/>
email = forms.EmailField(, label=&#34;邮箱&#34;)

def register(request):

if request.method == &#34;GET&#34;:<br/>
    check_form = CheckForm()<br/>
    return render(request, &#39;register.html&#39;, {&#39;check_form&#39;: check_form})</pre>

&lt;!– register.html核心代码 –&gt;
&lt;!– 方式一 –&gt;
&lt;form action=“” method=“post”&gt;

{{ check_form.usr }}<br/>
{{ check_form.pwd }}<br/>
{{ check_form.email }}<br/>
&lt;input type=&#34;submit&#34; value=&#34;注册&#34;&gt;<br/>

&lt;/form&gt;
&lt;!– 方式二 –&gt;
&lt;form action=“” method=“post”&gt;

{% for foo in check_form %}<br/>
     &lt;label for=&#34;{{ foo.id_for_label }}&#34; class=&#34;col-sm-2 control-label&#34;&gt;{{ foo.label }}&lt;/label&gt;<br/>
     {{ foo }}<br/>
 {% endfor %}<br/>
&lt;input type=&#34;submit&#34; value=&#34;注册&#34;&gt;<br/>

&lt;/form&gt;
&lt;!– 方式三 –&gt;
&lt;form action=“” method=“post”&gt;

&lt;table&gt;{{ check_form.as_table}}&lt;/table&gt;<br/>
&lt;input type=&#34;submit&#34; value=&#34;注册&#34;&gt;<br/>

&lt;/form&gt;
&lt;!– 方式四 –&gt;
&lt;form action=“” method=“post”&gt;

&lt;ul&gt;{{ check_form.as_ul}}&lt;/ul&gt;<br/>
&lt;input type=&#34;submit&#34; value=&#34;注册&#34;&gt;<br/>

&lt;/form&gt;
&lt;!– 方式五 –&gt;
&lt;form action=“” method=“post”&gt;

{{ check_form.as_p}}<br/>
&lt;input type=&#34;submit&#34; value=&#34;注册&#34;&gt;<br/>

&lt;/form&gt;

错误信息的渲染:

# views.py
class CheckForm(forms.Form):

usr = forms.CharField(<br/>
    min_length=3,<br/>
    max_length=10,<br/>
    error_messages={<br/>
        &#39;min_length&#39;: &#39;长度至少为3&#39;,<br/>
        &#39;max_length&#39;: &#39;长度最多为10&#39;,<br/>
        &#39;required&#39;: &#39;必填项&#39;<br/>
    },<br/>
    label=&#34;用户名&#34;<br/>
)<br/>
pwd = forms.CharField(<br/>
    min_length=3,<br/>
    max_length=10,<br/>
    error_messages={<br/>
        &#39;min_length&#39;: &#39;长度至少为3&#39;,<br/>
        &#39;max_length&#39;: &#39;长度最多为10&#39;,<br/>
        &#39;required&#39;: &#39;必填项&#39;<br/>
    },<br/>
    label=&#34;密码&#34;<br/>
)<br/>
email = forms.EmailField(<br/>
    error_messages={<br/>
        &#39;invalid&#39;: &#39;邮箱不合法&#39;,<br/>
        &#39;required&#39;: &#39;必填项&#39;}<br/>
)

def register(request):

if request.method == &#34;GET&#34;:<br/>
    check_form = CheckForm()<br/>
if request.method == &#34;POST&#34;:<br/>
    check_form = CheckForm(request.POST)<br/>
    if check_form.is_valid():<br/>
        return HttpResponse(&#39;注册成功&#39;)<br/>
return render(request, &#39;register.html&#39;, locals())</pre>

&lt;form action=“” method=“post” novalidate&gt;

{% for ele in check_form %}<br/>
&lt;p&gt;<br/>
    {{ ele.label }}:{{ ele }}<br/>
    &lt;span style=&#34;color: red&#34;&gt;{{ ele.errors.0 }}&lt;/span&gt;<br/>
&lt;/p&gt;<br/>
{% endfor %}

&lt;input type=“submit” value=“注册”&gt;
&lt;/form&gt;

组件的参数设置:

class Ret(Form):

name = forms.CharField(max_length=10, min_length=2, label=&#39;用户名&#39;,<br/>
                       error_messages={&#39;required&#39;: &#39;该字段不能为空&#39;, &#39;invalid&#39;: &#39;格式错误&#39;, &#39;max_length&#39;: &#39;太长&#39;,<br/>
                                       &#39;min_length&#39;: &#39;太短&#39;},<br/>
                       widget=widgets.TextInput(attrs={&#39;class&#39;:&#39;form-control&#39;}))<br/>
pwd = forms.CharField(max_length=10, min_length=2, widget=widgets.PasswordInput(attrs={&#39;class&#39;:&#39;form-control&#39;}))<br/>
email = forms.EmailField(label=&#39;邮箱&#39;, error_messages={&#39;required&#39;: &#39;该字段不能为空&#39;, &#39;invalid&#39;: &#39;格式错误&#39;})</pre>

局部钩子:

# 在自定义验证类CheckForm中添加局部验证钩子
class CheckForm(forms.Form):

...<br/>
def clean_usr(self):<br/>
    name = self.cleaned_data.get(&#39;usr&#39;)  # type: str<br/>
    import re<br/>
    if re.match(&#39;^[0-9]&#39;, name):<br/>
        from django.core.exceptions import ValidationError<br/>
        raise ValidationError(&#39;不能以数字开头&#39;)<br/>
    return name</pre>

全局钩子:

# views.py
class CheckForm(forms.Form):

usr = forms.CharField(<br/>
    min_length=3,<br/>
    max_length=10,<br/>
    error_messages={<br/>
        &#39;min_length&#39;: &#39;长度至少为3&#39;,<br/>
        &#39;max_length&#39;: &#39;长度最多为10&#39;,<br/>
        &#39;required&#39;: &#39;必填项&#39;<br/>
    },<br/>
    label=&#34;用户名&#34;,<br/>
    widget=forms.TextInput(attrs={&#39;placeholder&#39;: &#39;请输入用户名&#39;})<br/>
)<br/>
pwd = forms.CharField(<br/>
    min_length=3,<br/>
    max_length=10,<br/>
    error_messages={<br/>
        &#39;min_length&#39;: &#39;长度至少为3&#39;,<br/>
        &#39;max_length&#39;: &#39;长度最多为10&#39;,<br/>
        &#39;required&#39;: &#39;必填项&#39;<br/>
    },<br/>
    label=&#34;密码&#34;,<br/>
    widget=forms.PasswordInput(attrs={&#39;placeholder&#39;: &#39;请输入密码&#39;})<br/>
)<br/>
re_pwd = forms.CharField(<br/>
    min_length=3,<br/>
    max_length=10,<br/>
    error_messages={<br/>
        &#39;min_length&#39;: &#39;长度至少为3&#39;,<br/>
        &#39;max_length&#39;: &#39;长度最多为10&#39;,<br/>
        &#39;required&#39;: &#39;必填项&#39;<br/>
    },<br/>
    label=&#34;确认密码&#34;,<br/>
    widget=forms.PasswordInput(attrs={&#39;placeholder&#39;: &#39;请确认密码&#39;})<br/>
)<br/>
def clean(self):<br/>
    pwd = self.cleaned_data.get(&#39;pwd&#39;)<br/>
    re_pwd = self.cleaned_data.get(&#39;re_pwd&#39;)<br/>
    if pwd == re_pwd:<br/>
        return self.cleaned_data<br/>
    from django.core.exceptions import ValidationError<br/>
    raise ValidationError(&#39;两次密码不一致&#39;)

def register(request):

if request.method == &#34;GET&#34;:<br/>
    check_form = CheckForm()<br/>
if request.method == &#34;POST&#34;:<br/>
    check_form = CheckForm(request.POST)<br/>
    if check_form.is_valid():<br/>
        return HttpResponse(&#39;注册成功&#39;)<br/>
    else:<br/>
        # 拿到全局钩子抛出的错误信息<br/>
        all_error = check_form.errors.get(&#39;__all__&#39;, None)<br/>
return render(request, &#39;register.html&#39;, locals())</pre>

&lt;form action=“” method=“post” novalidate&gt;

{% for ele in check_form %}<br/>
    &lt;p&gt;<br/>
        {{ ele.label }}:{{ ele }}<br/>
        &lt;span style=&#34;color: red&#34;&gt;{{ ele.errors.0 }}&lt;/span&gt;<br/>
        {% if ele.label == &#39;确认密码&#39; %}<br/>
            &lt;span style=&#34;color: red&#34;&gt;{{ all_error.0 }}&lt;/span&gt;<br/>
        {% endif %}<br/>
    &lt;/p&gt;<br/>
{% endfor %}<br/>
&lt;input type=&#34;submit&#34; value=&#34;注册&#34;&gt;<br/>

&lt;/form&gt;