Django学习笔记(3):登录功能2

Django学习笔记(3):登录功能2

参考:
Django 2.0 项目实战: 扩展Django自带User模型,实现用户注册与登录
Django 2.0 项目实战 (2): 查看与编辑用户个人资料,扩展Django自带后台User Admin
Django 2.0 项目实战 (3): 用户重置密码与退出登录

目标

对Django自带user模型的访问,实现注册登录
代码版本:Django0619C

User模型

Django Auth模块自带User模型所包含字段
username:用户名
email: 电子邮件
password:密码
first_name:名
last_name:姓
is_active: 是否为活跃用户,默认是True
is_staff: 是否为员工。默认是False
is_superuser: 是否为管理员,默认是False
date_joined: 加入日期,系统自动生成。
在User模型的基础上扩展如下字段:
自定义的UserProfile模型
user: 与User是1对1关系
org:组织机构名
telephone: 电话
mod_date: 最后修改日期。系统自动生成

步骤

1.创建一个APP,命名为users
打开Terminal窗口,在命令行输入如下命令:
python manage.py startapp users
操作成功后,项目中增加一个user目录,修改项目中的settings.py,将’users’ 加到INSTALLED_APPS里

#修改settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'login',
    'users',
]

2.建立UserProfile模型
我们并没有改变Django Auth自带的User模型,也没有建立新的User模型。UserProfile只是对User模型的扩展。找到users/models.py, 并创建如下UserProfile模型。由于我们引用了Django Auth自带的User模型,所以我们必需开始先把它import进来。

#users/models.py
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
    org = models.CharField('Organization', max_length=128, blank=True)
    telephone = models.CharField('Telephone', max_length=50, blank=True)
    mod_date = models.DateTimeField('Last modified', auto_now=True)

    class Meta:
        verbose_name = 'User Profile'
    def __str__(self):
        return "{}".format(self.user.__str__())

然后你可以在终端输入以下命令,就可以创建UserProfile的数据表。

python manage.py makemigrations
python manage.py migrate
3.配置url
首先配置users/urls.py
从URL配置科研看出我们要实现的6个功能。下面是users/urls.py里的全部代码。你应该注意到,我们给动态链接/register/取了个名字’register’, 这样我们就可以在html模板里可以通过{% url ‘users:register’ %}调用这个链接了。

在这里插入代码片
from django.urls import path,re_path
from users import views
app_name='users'
urlpatterns = [
     re_path(r'^register/$', views.register, name='register'),
    re_path(r'^login/$', views.login, name='login'),
    re_path(r'^user/(?P\d+)/profile/$', views.profile, name='profile'),
    re_path(r'^user/(?P\d+)/profile/update/$', views.profile_update, name='profile_update'),
    re_path(r'^user/(?P\d+)/pwdchange/$', views.pwd_change, name='pwd_change'),
    re_path(r'^logout/$', views.logout, name='logout'),
]

然后配置顶层的Django0619/urls.py,把我们这个app的URLs也加进去,如下所示。这样当用户访问/accounts/register/时,浏览器会调用views.py里的register函数。

#在原有代码上增加
from users import views

urlpatterns = [
   ...
    url(r'^accounts/',include('users.urls')),
]

4.创建form
我们需要编写register和login两个视图, 让用户通过表单向我们提交数据,并处理这些数据。因为这两个视图都需要用表单,所以我们先在users目录下新建forms.py, 然后创建两个form,一个RegistrationForm,一个LoginForm。代码如下:

#forms.py
from django import forms
from django.contrib.auth.models import User
import re
def email_check(email):
    pattern = re.compile(r"\"?([-a-zA-Z0-9.`?{}]+@\w+\.\w+)\"?")
    return re.match(pattern, email)

class RegistrationForm(forms.Form):
    username = forms.CharField(label='用户名', max_length=50) #label='用户名Username',
    email = forms.EmailField(label='电子邮件',)# Email
    password1 = forms.CharField(label='密码', widget=forms.PasswordInput)#Password
    password2 = forms.CharField(label='确认密码', widget=forms.PasswordInput)#Password Confirmation
    # Use clean methods to define custom validation rules
    def clean_username(self):
        username = self.cleaned_data.get('username')
        if len(username) < 6:
            raise forms.ValidationError("Your username must be at least 6 characters long.")
        elif len(username) > 50:
            raise forms.ValidationError("Your username is too long.")
        else:
            filter_result = User.objects.filter(username__exact=username)
            if len(filter_result) > 0:
                raise forms.ValidationError("Your username already exists.")
        return username
    def clean_email(self):
        email = self.cleaned_data.get('email')
        if email_check(email):
            filter_result = User.objects.filter(email__exact=email)
            if len(filter_result) > 0:
                raise forms.ValidationError("Your email already exists.")
            else:
                raise forms.ValidationError("Please enter a valid email.")
        return email
    def clean_password1(self):
        password1 = self.cleaned_data.get('password1')
        if len(password1) < 6:
            raise forms.ValidationError("Your password is too short.")
        elif len(password1) > 20:
            raise forms.ValidationError("Your password is too long.")
        return password1
    def clean_password2(self):
        password1 = self.cleaned_data.get('password1')
        password2 = self.cleaned_data.get('password2')
        if password1 and password2 and password1 != password2:
            raise forms.ValidationError("Password mismatch. Please enter again.")
        return password2
class LoginForm(forms.Form):
    username = forms.CharField(label='用户名', max_length=50,error_messages={"required": "用户名必填"})
    password = forms.CharField(label='密  码', widget=forms.PasswordInput,error_messages={"required": "密码必填"})
    Log_auth="False"
    # Use clean methods to define custom validation rules
    def clean_username(self):
        username = self.cleaned_data.get('username')
        if email_check(username):
            filter_result = User.objects.filter(email__exact=username)
            if not filter_result:
                raise forms.ValidationError("This email does not exist.")
        else:
            filter_result = User.objects.filter(username__exact=username)
            if not filter_result:
                raise forms.ValidationError("This username does not exist. Please register first.")
        return username

千万不要上面的代码吓到。之所以代码这么长是因为我们用clean方法加入了很多表单验证项,比如检查用户名是否过短,用户名是否已经存在。如果你把表单验证拿掉,其实代码非常少。我之所以加上这些验证规则,是让你了解最真实的网站开发。
当然你也可以不用新建forms.py而直接在html模板里写表单,但我并不建议这么做。用forms.py的好处显而易见: 所有的表单在一个文件里,非常便于后期维护,比如增添或修订字段。forms.py可通过clean方法自定义表单验证,非常便捷。不用在views.py里再进行表单验证(比如检查用户是否已存在),逻辑上更清晰。
5.编写view
修改users/views.py,创建register函数,用于处理用户注册过程。

在这里插入代码片
from django.shortcuts import render, get_object_or_404
from django.contrib.auth.models import User
from .models import UserProfile
from django.contrib import auth
from .forms import RegistrationForm, LoginForm
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.contrib.auth.decorators import login_required

def register(request):
    if request.method =='POST':
        form = RegistrationForm(request.POST)
        if form.is_valid():
            username = form.cleaned_data['username']
            email = form.cleaned_data['email']
            password = form.cleaned_data['password2']
             # 使用内置User自带create_user方法创建用户,不需要使用save()
            user = User.objects.create_user(username=username, password=password, email=email)
             # 如果直接使用objects.create()方法后不需要使用save()
            user_profile = UserProfile(user=user)
            user_profile.save()          
            return HttpResponseRedirect("/accounts/login/")
        else:
            return render(request, 'users/registration.html', {'form': form})
    else:
        form = RegistrationForm()
        return render(request, 'users/registration.html', {'form': form})      

我们先看下views.register函数是怎么工作的:

当用户通过POST方法提交表单,我们先验证表单RegistrationForm的数据是否有效。如果有效,我们先用Django User模型自带的create_user方法创建user对象,再创建user_profile。用户通过一张表单提交数据,我们实际上分别存储在两张表里。
如果用户注册成功,我们通过HttpResponseRedirect方法转到登陆页面,如果用户没有提交表单或不是通过POST方法提交表单,我们转到注册页面,生成一张空的RegistrationForm。

创建login函数,用于处理登录

在这里插入代码片
def login(request):
    errmsg = ""
    if request.method =='POST':
        print("POST")
        form = LoginForm(request.POST)  
        status = form.is_valid()      
        if status:          
            username = form.cleaned_data['username']
            password = form.cleaned_data['password']
            user = auth.authenticate(username=username, password=password)
            if user is not None and user.is_active:               
                auth.login(request, user)
                form.Log_auth = "Ture"               
                return render(request, 'homepage.html', {'form': form})
            else: 
                errmsg = "密码错误!"            
                return render(request, 'users/login.html', {'form': form, 'err_msg': errmsg})             
        else        
            errmsg = "用户名或密码错误!"
            form = LoginForm()
            return render(request, 'users/login.html', {'form': form,'err_msg': errmsg})
    if request.method =='GET':      
        form = LoginForm()
        return render(request, 'users/login.html', {'form': form})

我们再看下views.login函数是怎么工作的:
当用户通过POST方法提交表单,我们先验证表单LoginForm的数据是否有效。如果有效,我们调用Django自带的auth.authenticate() 来验证用户名和密码是否正确。如果正确且用户是活跃的,我们调用auth.login()来进行登录。如果用户登录失败,会重新转到登录页面,并返回错误信息。如果用户登录成功,我们通过HttpResponseRedirect方法转到用户个人信息页面
如果用户没有提交表单或不是通过POST方法提交表单,我们转到登录页面,生成一张空的LoginForm
6.编写html模板
在users目录下创建/templates/users/文件夹,编写html模板registration.html和login.html。其目录结构应该如下图所示:
Django学习笔记(3):登录功能2_第1张图片
registration.html主要代码如下:

在这里插入代码片

注 册

{% csrf_token %} {% for field in form %}
{ { field.label_tag }}
{ { field }}{ { field.errors }} {% if field.help_text %}

{ { field.help_text|safe }}

{% endif %}
{% endfor %}

已有账号?[立即登录]

login.html主要代码如下:

在这里插入代码片

帐号登录

{% csrf_token %}
{ { err_msg }}

7.运行
python manage.py runserver
打开浏览器http://127.0.0.1:8000/
点击登录,在弹出的页面可测试登录功能
Django学习笔记(3):登录功能2_第2张图片
点击注册,在弹出的页面可测试注册功能
Django学习笔记(3):登录功能2_第3张图片
8小结:
本文利用Django 2.0实现了用户注册与登录的两个功能,扩展了Django自带的User模型,并分享了代码。接下来我会分享如何实现查看用户资料,允许用户修改自己资料,修改密码和退出登录的其它4个功能。

你可能感兴趣的:(Django学习笔记(3):登录功能2)