一、数据表结构设计
项目应用account的模型MyUser是项目中的核心数据,它与每个项目应用的模型都存在数据关联。模型MyUser继承内置模型User,在内置模型User的基础上添加新的字段,用于完善用户信息。打开项目应用account的models.py定义模型MyUser,代码如下:
class MyUser(AbstractUser):
name = models.CharField(verbose_name="姓名",max_length=50,default='匿名用户')
introduce = models.TextField(verbose_name='简介',default="暂无介绍")
company = models.CharField(verbose_name="公司",max_length=100,default='暂无信息')
profession = models.CharField(verbose_name='职业',max_length=100,default='暂无信息')
address = models.CharField(verbose_name='地址', max_length=100, default='暂无信息')
telephone = models.CharField(verbose_name='电话', max_length=11, default='暂无信息')
wx = models.CharField(verbose_name='微信', max_length=50, default='暂无信息')
qq = models.CharField(verbose_name='qq',max_length=50,default='暂无信息')
wb = models.CharField(verbose_name='微博', max_length=100, default='暂无信息')
photo = models.ImageField(verbose_name='头像', blank=True,upload_to='images/user/')
create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
class Meta:
verbose_name = '用户'
verbose_name_plural = verbose_name
db_table = 'MyUser'
def __str__(self):
return self.name
二、路由定义
采用路由下发的方式,我们在Myblog的urls.py下设置account的路由
# Myblog的 urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path('user/', include('app.account.urls')),
]
# account的 urls.py
urlpatterns = [
path('register', Register.as_view(), name="register"),
path('login', UserLogin.as_view(), name="userLogin"),
]
三、编写视图类
我们在account创建一个一个forms.py用来创建UserForm类,用来进行表单认证:
from django import forms
from django.forms import Form
from app.account.models import MyUser
from captcha.fields import CaptchaField
class UserForm(Form):
username = forms.CharField(
widget=forms.TextInput
)
password = forms.CharField(
widget=forms.PasswordInput
)
cp = forms.CharField(
widget=forms.PasswordInput,
required=False
)
type = forms.CharField(
widget=forms.TextInput
)
captcha = CaptchaField()
def clean(self):
username = self.cleaned_data.get("username", '')
if self.cleaned_data.get("type", '') == 'register':
if not username:
raise forms.ValidationError("用户名不能为空")
else:
user = MyUser.objects.filter(username=username).exists()
if user:
raise forms.ValidationError("用户名已存在")
p = self.cleaned_data.get("password", '')
cp = self.cleaned_data.get("cp", '')
if p != cp:
raise forms.ValidationError("两次密码不一致")
else:
d = {
'username': username,
'password': p,
'is_superuser': 1,
'is_staff': 1
}
user = MyUser.objects.create_user(**d)# create_user自动将明文密码hash加密
user.save()
else:
if not username:
raise forms.ValidationError("用户名不能为空")
在account的view.py添加如下代码
from django.shortcuts import render, redirect, reverse
from django.views.generic import View
from .forms import *
from django.contrib.auth import authenticate, login
from captcha.models import CaptchaStore
from captcha.helpers import captcha_image_url
class Register(View):
info = {
'title': '注册博客',
'pageTitle': '用户注册',
"confirmPassword": True,
'button': '注册',
"urlText": '用户登录',
"submitUrl": 'register',
"urlName": 'userLogin',
"tips": '',
'form': '',
}
def get(self, request):
self.info['form'] = UserForm()
return render(request, 'user.html', self.info)
def post(self, request):
user_from = UserForm(request.POST)
if user_from.is_valid():
self.info["tips"] = '注册成功,请登录'
return redirect(reverse("register"), self.info)
else:
self.info["tips"] = user_from.errors.as_data().values()
return render(request, 'user.html', self.info)
class UserLogin(View):
info = {
'title': '登录博客',
'pageTitle': '用户登录',
'button': '登录',
'urlText': '用户注册',
'urlName': 'register',
'submitUrl': 'userLogin',
'tips': '',
'form': '',
'new_key': '',
'image_url': ''
}
def get(self, request):
self.info['new_key'] = CaptchaStore.pick() # 生成hashkey
self.info['image_url'] = captcha_image_url(self.info['new_key']) # 生成验证码图片url地址
self.info['form'] = UserForm()
return render(request, 'user.html', self.info)
def post(self, request):
user_from = UserForm(request.POST)
# 表单验证
if user_from.is_valid():
username = user_from.cleaned_data.get("username", '')
password = user_from.cleaned_data.get("password", '')
if not username or not password:
self.info['tips'] = "用户名或密码不能为空"
return render(request, 'user.html', self.info)
else:
if MyUser.objects.filter(username=username).exists():
user = authenticate(username=username, password=password)
if user:
if user.is_active:
'''
'''
login(request, user)
return redirect(reverse("index"), self.info)
else:
self.info['tips'] = '密码错误'
return render(request, 'user.html', self.info)
else:
self.info['tips'] = '用戶不存在'
return render(request, 'user.html', self.info)
else:
self.info["tips"] = user_from.errors.as_data().values()
return render(request, 'user.html', locals())
四、jinja2模板引擎
更换django自带的模板引擎,采用jinja2模板引擎,在Myblog的setting中,在TEMPLATES配置中设置jinja2,用Myblog创建jinja2.py添加jinja2环境
# Myblog的setting中
TEMPLATES = [
{
'BACKEND': 'django.template.backends.jinja2.Jinja2',
'DIRS': [os.path.join(BASE_DIR, 'templates')]
,
'APP_DIRS': True,
'OPTIONS': {
'environment': 'Myblog.jinja2.environment',
},
},
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')]
,
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
# jinja2.py
from django.contrib.staticfiles.storage import staticfiles_storage
from django.urls import reverse
from jinja2 import Environment
# 将jinja2 模板设置到项目环境中
def environment(**options):
env = Environment(**options)
env.globals.update({
'static': staticfiles_storage.url,
'url': reverse,
})
return env
五、模板编写
jinja2模板引擎编写,跟django自带的模板用法类似
{{ title }}
{{ pageTitle }}
六、验证码