参考:
Django 2.0 项目实战: 扩展Django自带User模型,实现用户注册与登录
Django 2.0 项目实战 (2): 查看与编辑用户个人资料,扩展Django自带后台User Admin
Django 2.0 项目实战 (3): 用户重置密码与退出登录
对Django自带user模型的访问,实现注册登录
代码版本:Django0619C
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。其目录结构应该如下图所示:
registration.html主要代码如下:
在这里插入代码片
login.html主要代码如下:
在这里插入代码片
帐号登录