python3 manage.py startproject 项目名字
# manage.py则是每个Django项目中自动生成的一个用于管理项目的脚本文件,需要在cmd窗口中cd到Django项目的manage.py所在的目录后通过python命令执行。其中的command是Django内置的或者你自定义的命令
命令行进入项目目录
python3 manegy.py startapp app名字
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_L10N = True
USE_TZ = False
class User(models.Model):
gender = (
('male', "男"),
('female', "女"),
)
name = models.CharFiel(max_length=128unique=True)
password = models.CharField(max_length=256)
email = models.EmailField(unique=True)
sex = models.CharField(max_length=32choices=gender, default="男")
c_time = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
class Meta:
ordering = ["-c_time"]
verbose_name = "用户"
verbose_name_plural = "用户"
show variables like '%char%';#显示你数据库字符集列表
set character_set_client=utf8;
set character_set_connection=utf8;
set character_set_database=utf8;
set character_set_results=utf8;
set character_set_server=utf8;
set character_set_system=utf8;
set collation_connection=utf8;
set collation_database=utf8;
set collation_server=utf8;
上面代码分行写,分别运行,不要管警告
---------------------
作者:胖虎艾春辉
来源:CSDN
原文:https://blog.csdn.net/weixin_42479155/article/details/85345973
版权声明:本文为博主原创文章,转载请附上博文链接!
python3 manage.py migrate
admin.site.register(models.User)
python3 manage.py createsuperuser
urls里面的分配:
from django.contrib import admin
from django.urls import path
from login import views
from django.conf.urls import include
from django.urls import re_path
urlpatterns = [
path('admin/', admin.site.urls),
path('index/', views.index, name = 'index'),
path('login/',views.login,name = 'login'),
#path('',views.base,name ='base'),
path('',views.index),
path('register/',views.register,name = 'register'),
path('logout/',views.logout,name = 'logout'),
]
#**这里我需要提醒,为了避免函数调用出现问题,我们给每一个映射都设计一个命名空间**
from django.shortcuts import render
from django.shortcuts import redirect
# Create your views here.
def index(request):
pass
return render(request, 'login/index.html')
def login(request):
pass
return render(request, 'login/login.html')
def register(request):
pass
return render(request, 'login/register.html')
def logout(request):
pass
return redirect("/index/")
# 这里我提醒:导入redirect是为了重定向
render函数有两个参数,第一个request准备返回,固定参数,不要随意改变,第二个参数是需要渲染的页面
登录
欢迎登录!
这样的页面非常丑
这个框架弥补你对前端开发的不足,
同时相匹配的jquery下载
(http://www.bootcss.com/)
对于静态文件的引入,在settings文件中,它有一个STATICFILES_DIRS的模块,所以在最下面一行加入引导路径
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static"),
]
Bootstrap 101 Template
你好,世界!
{% load staticfiles %}
{% block title %}base{% endblock %}
{% block css %}{% endblock %}
{% block content %}{% endblock %}
{% extends 'base.html' %}
{% load staticfiles %}
{% block title %}登录{% endblock %}
{% block css %}{% endblock %}
{% block content %}
{% endblock %}
body{
background-image: url("8b13632762d0f703a7484cf103fa513d2697c521.jpg");
}
.form-login{
max-width: 330px;
padding: 15px;
margin: 0 auto;
}
.form-login .form-control{
position: relative;
height: auto;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
padding: 10px;
font-size: 16px;
}
.form-login .form-control:focus{
z-index: 2;
}
.form-login input[type = "text"]{
margin-bottom: -1px;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
.form-login input[type = password]{
margin-bottom: 10px;
border-bottom-left-radius: 0;
border-bottom-left-radius: 0;
}
def login(request):
if request.method == "POST":
username = request.POST.get('username')
password = request.POST.get('password')
print(username, password)
return redirect('/index/')
return render(request, 'login/login.html')
解释:
1. 每一个视图函数都至少接受一个参数,并且是第一位置参数,该参数封装了当前请求的所有数据
2. request.method分装了数据请求大写POST,将执行if语句
3. get('username')的键名字是html表单中input元素中name属性定义的值,所以不能忘记添加name属性
4. 利用redirect方法,将页面重定向到index页
5. 但是你这样也是不成功的,为什么呢?因为django有一部分的内置防御功能,解决问题就是在所有的form里面,添加:{% csrf_token %}
def login(request):
if request.method == "POST":
username = request.POST.get('username', None)
password = request.POST.get('password', None)
if username and password: # 确保用户名和密码都不为空
username = username.strip()
# 用户名字符合法性验证
# 密码长度验证
# 更多的其它验证.....
return redirect('/index/')
return render(request, 'login/login.html')
def login(request):
if request.method == "POST":
username = request.POST.get('username', None)
password = request.POST.get('password', None)
if username and password: # 确保用户名和密码都不为空
username = username.strip()
# 用户名字符合法性验证
# 密码长度验证
# 更多的其它验证.....
try:
user = models.User.objects.get(name=username)
except:
return render(request, 'login/login.html')
if user.password == password:
return redirect('/index/')
return render(request, 'login/login.html')
解释:
1. 导入models模块
2. models.User.objects.get(name=username)是Django提供的最常用的数据查询API,因为我们之前设计好了数据库的表
def login(request):
if request.method == "POST":
username = request.POST.get('username', None)
password = request.POST.get('password', None)
message = "所有字段都必须填写!"
if username and password: # 确保用户名和密码都不为空
username = username.strip()
# 用户名字符合法性验证
# 密码长度验证
# 更多的其它验证.....
try:
user = models.User.objects.get(name=username)
if user.password == password:
return redirect('/index/')
else:
message = "密码不正确!"
except:
message = "用户名不存在!"
return render(request, 'login/login.html', {"message": message})
return render(request, 'login/login.html')
from django import forms
class UserForm(forms.Form):
username = forms.CharField(label="用户名", max_length=128)
password = forms.CharField(label="密码", max_length=256, widget=forms.PasswordInput)
解释:
1. 导入forms模块
2. 所有的表单都需要继承自forms.Form类
3. 每个表单字段都有自己的字段类型比如CharField,它们分别对应一种HTML语言中
def login(request):
if request.method == "POST":
login_form = forms.UserForm(request.POST)
message = "请检查填写的内容!"
if login_form.is_valid():
username = login_form.cleaned_data['username']
password = login_form.cleaned_data['password']
try:
user = models.User.objects.get(name=username)
if user.password == password:
return redirect('/index/')
else:
message = "密码不正确!"
except:
message = "用户不存在!"
return render(request, 'login/login.html', locals())
login_form = forms.UserForm()
return render(request, 'login/login.html', locals())
1. 对于请求不是post的返回空的表格
2. 对于post表格,接收表单数据,并验证
3. 采用is_valid进行验证,验证过程有:#先来归纳一下整个流程
#(1)首先is_valid()起手,看seld.errors中是否值,只要有值就是flase
#(2)接着分析errors.里面判断_errors是都为空,如果为空返回self.full_clean(),否则返回self._errors
#(3)现在就要看full_clean(),是何方神圣了,里面设置_errors和cleaned_data这两个字典,一个存错误字段,一个存储正确字段。
#(4)在full_clean最后有一句self._clean_fields(),表示校验字段
#(5)在_clean_fields函数中开始循环校验每个字段,真正校验字段的是field.clean(value),怎么校验的不管
#(6)在_clean_fields中可以看到,会将字段分别添加到_errors和cleaned_data这两个字典中
#(7)结尾部分还设置了钩子,找clean_XX形式的,有就执行。执行错误信息也会添加到_errors中
#(8)整个校验过程完成
4. 验证成功后可以从表单对象的cleaned_data数据字典中获取表单的具体值
5. 此外使用了locals这个函数,它返回当前所有的本地变量字典,直接打包,提高了效率
{% extends 'base.html' %}
{% load staticfiles %}
{% block title %}登录{% endblock %}
{% block css %}{% endblock %}
{% block content %}
{% endblock %}
1. 使用一个{
{login_form}}就直接完成了表单内容的生成工作,而这个变量来自在视图函数中生成的form实例的变量名,同时,locals将其传入
2. 使用post的时候,必添加{% csrf_token %}用于处理csrf安全机制
3. 实际上除了通过{
{ login_form }}简单地将表单渲染到HTML页面中了,还有下面几种方式:
{
{ login_form.as_table }} 将表单渲染成一个表格元素,每个输入框作为一个标签
{
{ login_form.as_p }} 将表单的每个输入框包裹在一个标签内
{
{ login_form.as_ul }} 将表单渲染成一个列表元素,每个输入框作为一个
标签
- 但其实这个一点也不好看,我有强迫症,所以手动渲染:
{
{ login_form.username.label_tag }}
{
{ login_form.username}}
{
{ login_form.password.label_tag }}
{
{ login_form.password }}
- 为了还原bootstarp框架一个清白,我们再次修改forms代码:
from django import forms
class UserForm(forms.Form):
username = forms.CharField(label="用户名", max_length=128, widget=forms.TextInput(attrs={'class': 'form-control'}))
password = forms.CharField(label="密码", max_length=256, widget=forms.PasswordInput(attrs={'class': 'form-contro
第七课堂: 图片验证码
- 为了防止爬虫无限制的爬你的网站,导致你的服务器瘫痪,为此,我们需要提供验证码功能
- 步骤
- 看你的系统,我的系统是ubuntu18.04所以,我使用命令行输入
pip3 install django-simple-captcha
但是我遇到了问题上面显示我的mysqldb不能安装
没办法,只能sudo apt-get install python3-mysql解决了
- 注册app,captcha是一个系统内置的app,记住,不需要你取新建这个名字的app,而是只需要你在app列表进行注册就行
- 同时,在终端下执行下列语句:这句话的意思是将验证码自己制造的表推送到目的地
python3 manage.py migrate
- 使用二级路由,加入内置的路由,这是我个人的设置大家可以仿照一下
from django.contrib import admin
from django.urls import path
from login import views
from django.conf.urls import include
from django.urls import re_path
urlpatterns = [
path('admin/', admin.site.urls),
path('index/', views.index, name = 'index'),
path('login/',views.login,name = 'login'),
#path('',views.base,name ='base'),
path('register/',views.register,name = 'register'),
path('logout/',views.logout,name = 'logout'),
re_path(r'^captcha',include('captcha.urls'))#添加captcha相对应的网址
]
- 在forms里面添加captchafield,这个文件下代码如下
from django import forms
#添加图形验证码
from captcha.fields import CaptchaField
class UserForm(forms.Form):
username = forms.CharField(label="用户名:",max_length=128,widget=forms.TextInput(attrs={'class': 'form-control'}))
password = forms.CharField(label="密码:",max_length=256,widget=forms.PasswordInput(attrs={'class': 'form-control'}))
captcha = CaptchaField(label='验证码')
- 修改login.html
{
{ login_form.username.label_tag }}
{
{ login_form.username }}
{
{ login_form.password.label_tag }}
{
{ login_form.password}}
{
{ login_form.captcha.errors }}#指示用户,你的验证码有问题
{
{ login_form.captcha.label_tag }}
{
{ login_form.captcha }}
第八课堂: sessions会话
- 因为http协议特性,每一次来自于用户的浏览器请求是无状态的、独立的,也就是说无法保存用户状态,你可以在网页中尝试你把cookies进行关闭,看看你能不能访问天猫淘宝等
- 所有现代网站通常将cookies保存不重要的东西,大部分重要的东西通过sessions会话功能进行保存在服务器端
- django提供了一个通用sessions框架,并且可以使用多种sessions数据保存方式
- 保存在数据库里面
- 保存到缓存
- 保存到文件里
- 保存在cookies内
- django默认session框架,你不要修改就行,大致是这样,在settings文件下
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',#sessions会话窗口,相当于认证你是不是用户还是陌生人
'django.contrib.messages',
'django.contrib.staticfiles',
'login',
'captcha'
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',#启用sessions
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
- sessions 用法
class backends.base.SessionBase
# 这是所有会话对象的基类,包含标准的字典方法:
__getitem__(key)
Example: fav_color = request.session['fav_color']
__setitem__(key, value)
Example: request.session['fav_color'] = 'blue'
__delitem__(key)
Example: del request.session['fav_color'] # 如果不存在会抛出异常
__contains__(key)
Example: 'fav_color' in request.session
get(key, default=None)
Example: fav_color = request.session.get('fav_color', 'red')
pop(key, default=__not_given)
Example: fav_color = request.session.pop('fav_color', 'blue')
# 类似字典数据类型的内置方法
keys()
items()
setdefault()
clear()
# 它还有下面的方法:
flush()
# 删除当前的会话数据和会话cookie。经常用在用户退出后,删除会话。
set_test_cookie()
# 设置一个测试cookie,用于探测用户浏览器是否支持cookies。由于cookie的工作机制,你只有在下次用户请求的时候才可以测试。
test_cookie_worked()
# 返回True或者False,取决于用户的浏览器是否接受测试cookie。你必须在之前先调用set_test_cookie()方法。
delete_test_cookie()
# 删除测试cookie。
set_expiry(value)
# 设置cookie的有效期。可以传递不同类型的参数值:
• 如果值是一个整数,session将在对应的秒数后失效。例如request.session.set_expiry(300) 将在300秒后失效.
• 如果值是一个datetime或者timedelta对象, 会话将在指定的日期失效
• 如果为0,在用户关闭浏览器后失效
• 如果为None,则将使用全局会话失效策略
失效时间从上一次会话被修改的时刻开始计时。
get_expiry_age()
# 返回多少秒后失效的秒数。对于没有自定义失效时间的会话,这等同于SESSION_COOKIE_AGE.
# 这个方法接受2个可选的关键字参数
• modification:会话的最后修改时间(datetime对象)。默认是当前时间。
•expiry: 会话失效信息,可以是datetime对象,也可以是int或None
get_expiry_date()
# 和上面的方法类似,只是返回的是日期
get_expire_at_browser_close()
# 返回True或False,根据用户会话是否是浏览器关闭后就结束。
clear_expired()
# 删除已经失效的会话数据。
cycle_key()
# 创建一个新的会话秘钥用于保持当前的会话数据。django.contrib.auth.login() 会调用这个方法。
- 步骤
- 使用session,修改login视图函数
def login(request):
if request.session.get('is_login',None):
return redirect('/index/')
if request.method == "POST":
login_form = forms.UserForm(request.POST)
message = "请检查填写的内容"
if login_form.is_valid():
username = login_form.cleaned_data['username']
password = login_form.cleaned_data['password']
#用户名字符合法性验证
#密码长度验证
try :
user = models.User.objects.get(name=username)
if user.password == password:
request.session['is_login'] = True
request.session['user_id'] = user.id
request.session['user_name'] = user.name
return redirect('/index/')
else:
message = "密码不正确"
except:
message = "用户名不存在"
return render(request,'login/login.html',locals())
login_form = forms.UserForm
return render(request, 'login/login.html',locals())
- 修改页面,不要担心request没有加载出来,它是内置的,只是不同步,导致没有提示而已
- 修改index内容
{% extends 'base.html' %}
{% block title %}主页{% endblock %}
{% block content %}
{% if request.session.is_login %}
你好,{
{ request.session.user_name }}!欢迎回来!
{% else %}
你尚未登录,只能访问公开内容!
{% endif %}
{% endblock %}
第九课堂: 注册
- 竟然登录都已经写好了登录代码,那么你需要一个注册代码,这样才使得和前后端通信完美
- 步骤
- 我们在login的forms文件中在userform的下面新建一个类,那就是我们的注册类
class RegisterForm(forms.Form):
gender = (
('male',"男"),
('female',"女"),
)
username = forms.CharField(label="用户名",max_length=128,widget=forms.TextInput(attrs={'class':'form-control'}))
password1 = forms.CharField(label="密码",max_length=256,widget=forms.PasswordInput(attrs={'class':'form-control'}))
password2 = forms.CharField(label="确认密码",max_length=256,widget=forms.PasswordInput(attrs={'class':'form-control'}))
email = forms.EmailField(label="邮箱地址",widget=forms.EmailInput(attrs={'class':'form-control'}))
sex = forms.ChoiceField(label='性别',choices=gender)
captcha = CaptchaField(label='验证码')
解释:
1. gender字典里面和user模型中的一样,可以当成常量使用
2. password1和2是为了检验两次输入密码的相同性,防止误输入密码
3. email是一个邮箱输入框
4. sex是一个select下拉框
- 为了与表单相适应,我们在register.html进行对login依样画葫芦
{% extends 'base.html' %}
{% load staticfiles %}
{% block title %}注册{% endblock %}
{% block content %}
{% endblock %}
- 完善views里面的映射函数,和url构建的想对应
def register(request):
if request.session.get('is_login',None):
#思考一下,登录状态下注册,肯定不可行
return redirect('index/')
if request.method == "POST":
register_form = forms.RegisterForm(request.POST)
message = "请检查填写的内容"
if register_form.is_valid():
username = register_form.cleaned_data['username']
password1 = register_form.cleaned_data['password1']
password2 = register_form.cleaned_data['password2']
email = register_form.cleaned_data['email']
sex = register_form.cleaned_data['sex']
if password1 != password2:
message = "两次输入的密码不同"
return render(request,'login/register.html',locals())
else:
same_name_user = models.User.objects.filter(name=username)
if same_name_user:
message = '用户已经存在,请重新选择用户名'
return render(request,'login/register.html',locals())
same_email_user = models.User.objects.filter(email=email)
if same_email_user:
message = '该邮箱地址已经被注册,请使用别的邮箱'
return render(request,'login/register.html',locals())
#当然在上述都没错误的话,我们开始使用我们的东西了
new_user = models.User()#对于数据库里面表进行实例化,方便使用
new_user.name = username
new_user.password =hash_code(password1)
new_user.email = email
new_user.sex = sex
new_user.save()#进行保存
return redirect('/login/')#重定向到指定的位置
register_form = forms.RegisterForm()
return render(request,'login/register.html',locals())
- 思考一下,想阿里等大公司,你的密码肯定不可能是显示出来的密码,肯定加密了,对此,我们也使用加密
在views中加入一下
import hashlib
def hash_code(s, salt='mysite'):# 加点盐
h = hashlib.sha256()
s += salt
h.update(s.encode()) # update方法只接收bytes类型
return h.hexdigest()
同时对login中password的比较进行修改
if user.password == hash_code(password): # 哈希值和数据库内的值进行比对
new_user.password = hash_code(password1) # 使用加密密码
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190120121651475.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjQ3OTE1NQ==,size_16,color_FFFFFF,t_70)
# 使用sha256算法,将输入密码单向转换为字符串储存在数据库中,这样的话,用户隐私得到很大保护
- 对相应的登录和注册进行修改
就是对应的密码储存,或者比对需要进行相应的加密就行
def login(request):
if request.session.get('is_login',None):
return redirect('/index/')
if request.method == "POST":
login_form = forms.UserForm(request.POST)
message = "请检查填写的内容"
if login_form.is_valid():
username = login_form.cleaned_data['username']
password = login_form.cleaned_data['password']
#用户名字符合法性验证
#密码长度验证
try :
user = models.User.objects.get(name=username)
# 1.
# 导入models模块
# 2.
# models.User.objects.get(name=username)
# 是Django提供的最常用的数据查询API, 因为我们之前设计好了数据库的表
if not user.has_confirmed:#进行邮件确认
message = "用户还未通过邮件确认"
return render(request, 'login/login.html',locals())
# if user.password == password:将密码与数据库里面值进行比对,而不是提取出来,浪费时间
# 好像数据库里面的东西拿出来会自动反转
print(user.password)
if user.password == hash_code(password):
request.session['is_login'] = True
request.session['user_id'] = user.id
request.session['user_name'] = user.name
return redirect('/index/')
else:
message = "密码不正确"
except:
message = "用户名不存在"
# return render(request, 'login/login.html', {"message": message})
return render(request,'login/login.html',locals())#local更为强大,所有的有关内容,均传递
login_form = forms.UserForm
return render(request, 'login/login.html',locals())
def register(request):
if request.session.get('is_login',None):
#思考一下,登录状态下注册,肯定不可行
return redirect('index/')
if request.method == "POST":
register_form = forms.RegisterForm(request.POST)
message = "请检查填写的内容"
if register_form.is_valid():
username = register_form.cleaned_data['username']
password1 = register_form.cleaned_data['password1']
password2 = register_form.cleaned_data['password2']
email = register_form.cleaned_data['email']
sex = register_form.cleaned_data['sex']
if password1 != password2:
message = "两次输入的密码不同"
return render(request,'login/register.html',locals())
else:
same_name_user = models.User.objects.filter(name=username)
if same_name_user:
message = '用户已经存在,请重新选择用户名'
return render(request,'login/register.html',locals())
same_email_user = models.User.objects.filter(email=email)
if same_email_user:
message = '该邮箱地址已经被注册,请使用别的邮箱'
return render(request,'login/register.html',locals())
#当然在上述都没错误的话,我们开始使用我们的东西了
new_user = models.User()#对于数据库里面表进行实例化,方便使用
new_user.name = username
new_user.password =hash_code(password1)
new_user.email = email
new_user.sex = sex
new_user.save()#进行保存
code = make_confirm_string(new_user)
send_email(email,code)
return render(request,'login/confirm.html',locals())#跳转到等待邮件确认页面
register_form = forms.RegisterForm()
return render(request,'login/register.html',locals())
第十课堂: 发送邮件
- 在django中发送邮件需要在settings中配置参数
# 邮件配置
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
#是否使用SSL加密,qq企业邮箱要求使用,我们又不是企业邮箱,所以不要使用ssl加密
EMAIL_HOST = 'smtp.163.com'
#指定的smtp服务器名称
EMAIL_PORT = 25
EMAIL_HOST_USER = '[email protected]'
EMAIL_HOST_PASSWORD = 'qq1685715822'#授权码
# 注册有效期天数
CONFIRM_DAYS = 7
- 先写一个例子,在django里面发邮件的样式:
在mysite文件夹创建一个send_mail.py
import os
from django.core.mail import EmailMultiAlternatives
from django.core.mail import send_mail
os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'
if __name__ == '__main__':
# send_mail(
# '测试邮件',
# '邮件验证',
# '[email protected]',
# ['[email protected]']
# )
# 某些邮件公司可能不开放smtp服务
# 某些公司要求使用ssl安全机制
# 某些smtp服务对主机名格式有要求
subject,from_email,to = '测试邮件','[email protected]','[email protected]'
text_content = '欢迎'
html_content = '欢迎访问艾春辉的主页
'
msg = EmailMultiAlternatives(subject,text_content,from_email,[to])
msg.attach_alternative(html_content,"text/html")
msg.send()
第十一课堂:确认邮件注册:
- 我们需要创建一个邮件注册表,用来保存用户的确认码和注册时间
- 在/login/models.py文件中写入
from django.db import models
# Create your models here.
class User(models.Model):
gender = (
('male', "男"),
('female', "女"),
)
name = models.CharField(max_length=128, unique=True)
password = models.CharField(max_length=256)
email = models.EmailField(unique=True)
sex = models.CharField(max_length=32, choices=gender, default="男")
c_time = models.DateTimeField(auto_now_add=True)
has_confirmed = models.BooleanField(default=False)
def __str__(self):
return self.name
class Meta:
ordering = ["-c_time"]
verbose_name = "用户"
verbose_name_plural = "用户"
class ConfirmString(models.Model):
code = models.CharField(max_length=256)
user = models.OneToOneField('User')
c_time = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.user.name + ": " + self.code
class Meta:
ordering = ["-c_time"]
verbose_name = "确认码"
verbose_name_plural = "确认码"
#user模型中增加了确认邮件是否注册的bool型值
#注册模型保存了用户和注册码之间的关系,一对一形式
c_time就是注册时间
- 在终端里执行:python3 manage.py migrate
- 在/login/admin里面将模型注册进入
- 修改注册模型
def register(request):
if request.session.get('is_login', None):
# 登录状态不允许注册。你可以修改这条原则!
return redirect("/index/")
if request.method == "POST":
register_form = forms.RegisterForm(request.POST)
message = "请检查填写的内容!"
if register_form.is_valid(): # 获取数据
username = register_form.cleaned_data['username']
password1 = register_form.cleaned_data['password1']
password2 = register_form.cleaned_data['password2']
email = register_form.cleaned_data['email']
sex = register_form.cleaned_data['sex']
if password1 != password2: # 判断两次密码是否相同
message = "两次输入的密码不同!"
return render(request, 'login/register.html', locals())
else:
same_name_user = models.User.objects.filter(name=username)
if same_name_user: # 用户名唯一
message = '用户已经存在,请重新选择用户名!'
return render(request, 'login/register.html', locals())
same_email_user = models.User.objects.filter(email=email)
if same_email_user: # 邮箱地址唯一
message = '该邮箱地址已被注册,请使用别的邮箱!'
return render(request, 'login/register.html', locals())
# 当一切都OK的情况下,创建新用户
new_user = models.User()
new_user.name = username
new_user.password = hash_code(password1) # 使用加密密码
new_user.email = email
new_user.sex = sex
new_user.save()
code = make_confirm_string(new_user)
send_email(email, code)
message = '请前往注册邮箱,进行邮件确认!'
return render(request, 'login/confirm.html', locals()) # 跳转到等待邮件确认页面。
register_form = forms.RegisterForm()
return render(request, 'login/register.html', locals())
#其实就是多了两行代码
- 在views里面添加make_confirm_string(创建确认码对象)
def make_confirm_string(user):
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
code = hash_code(user.name, now)
models.ConfirmString.objects.create(code=code, user=user,)
return code
- 创建一个发送邮件函数:
def send_email(email, code):
from django.core.mail import EmailMultiAlternatives
subject = '来自艾春辉的注册确认邮件'
text_content = '''感谢注册'''
html_content = '''
感谢注册www.aichunhui.cn
请点击站点链接完成注册确认!
此链接有效期为{}天!
'''.format('127.0.0.1:8000', code, settings.CONFIRM_DAYS)
msg = EmailMultiAlternatives(subject, text_content, settings.EMAIL_HOST_USER, [email])
msg.attach_alternative(html_content, "text/html")
msg.send()
- 发送注册的邮件都解决了,那么我们现在来处理邮件确认请求
def user_confirm(request):
code = request.GET.get('code', None)
message = ''
try:
confirm = models.ConfirmString.objects.get(code=code)
except:
message = '无效的确认请求!'
return render(request, 'login/confirm.html', locals())
c_time = confirm.c_time
now = datetime.datetime.now()
if now > c_time + datetime.timedelta(settings.CONFIRM_DAYS):
confirm.user.delete()
message = '您的邮件已经过期!请重新注册!'
return render(request, 'login/confirm.html', locals())
else:
confirm.user.has_confirmed = True
confirm.user.save()
confirm.delete()
message = '感谢确认,请使用账户登录!'
return render(request, 'login/confirm.html', locals())
- 在template里面写入一个confirm.html
{% extends 'base.html' %}
{% block title %}注册确认{% endblock %}
{% block content %}
{
{ message }}
{% endblock %}
- 在login中比对密码时候进行比对是否注册:插入以下代码
if not user.has_confirmed:
message = "该用户还未通过邮件确认!"
return render(request, 'login/login.html', locals())
- 最后看我的views里面所有的代码:
from django.shortcuts import render
from django.shortcuts import redirect
from . import models
#导入本地的,不是使用默认的from django import forms
from . import forms
from django.conf import settings
import hashlib
import datetime
from mysite import settings
# Create your views here.
def user_confirm(request):
code = request.GET.get('code', None)
message = ''
try:
confirm = models.ConfirmString.objects.get(code=code)
except:
message = '无效的确认请求!'
return render(request, 'login/confirm.html', locals())
c_time = confirm.c_time
now = datetime.datetime.now()
if now > c_time + datetime.timedelta(settings.CONFIRM_DAYS):
confirm.user.delete()
message = '您的邮件已经过期!请重新注册!'
return render(request, 'login/confirm.html', locals())
else:
confirm.user.has_confirmed = True
confirm.user.save()
confirm.delete()
message = '感谢确认,请使用账户登录!'
return render(request, 'login/confirm.html', locals())
def send_email(email, code):
from django.core.mail import EmailMultiAlternatives
subject = '来自艾春辉的注册确认邮件'
text_content = '''感谢注册'''
html_content = '''
感谢注册www.aichunhui.cn
请点击站点链接完成注册确认!
此链接有效期为{}天!
'''.format('127.0.0.1:8000', code, settings.CONFIRM_DAYS)
msg = EmailMultiAlternatives(subject, text_content, settings.EMAIL_HOST_USER, [email])
msg.attach_alternative(html_content, "text/html")
msg.send()
def make_confirm_string(user):
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
code = hash_code(user.name, now)
models.ConfirmString.objects.create(code=code, user=user,)
return code
def hash_code(s, salt = 'mysite'):
#使用sha256
h = hashlib.sha256()
s += salt
h.update(s.encode())#update方法只接受bytes流类型
return h.hexdigest()
def index(request):
return render(request, 'login/index.html')
def login(request):
if request.session.get('is_login',None):
return redirect('/index/')
if request.method == "POST":
login_form = forms.UserForm(request.POST)
message = "请检查填写的内容"
if login_form.is_valid():
username = login_form.cleaned_data['username']
password = login_form.cleaned_data['password']
#用户名字符合法性验证
#密码长度验证
try :
user = models.User.objects.get(name=username)
# 1.
# 导入models模块
# 2.
# models.User.objects.get(name=username)
# 是Django提供的最常用的数据查询API, 因为我们之前设计好了数据库的表
if not user.has_confirmed:#进行邮件确认
message = "用户还未通过邮件确认"
return render(request, 'login/login.html',locals())
# if user.password == password:将密码与数据库里面值进行比对,而不是提取出来,浪费时间
# 好像数据库里面的东西拿出来会自动反转
print(user.password)
if user.password == hash_code(password):
request.session['is_login'] = True
request.session['user_id'] = user.id
request.session['user_name'] = user.name
return redirect('/index/')
else:
message = "密码不正确"
except:
message = "用户名不存在"
# return render(request, 'login/login.html', {"message": message})
return render(request,'login/login.html',locals())#local更为强大,所有的有关内容,均传递
login_form = forms.UserForm
return render(request, 'login/login.html',locals())
def register(request):
if request.session.get('is_login',None):
#思考一下,登录状态下注册,肯定不可行
return redirect('index/')
if request.method == "POST":
register_form = forms.RegisterForm(request.POST)
message = "请检查填写的内容"
if register_form.is_valid():
username = register_form.cleaned_data['username']
password1 = register_form.cleaned_data['password1']
password2 = register_form.cleaned_data['password2']
email = register_form.cleaned_data['email']
sex = register_form.cleaned_data['sex']
if password1 != password2:
message = "两次输入的密码不同"
return render(request,'login/register.html',locals())
else:
same_name_user = models.User.objects.filter(name=username)
if same_name_user:
message = '用户已经存在,请重新选择用户名'
return render(request,'login/register.html',locals())
same_email_user = models.User.objects.filter(email=email)
if same_email_user:
message = '该邮箱地址已经被注册,请使用别的邮箱'
return render(request,'login/register.html',locals())
#当然在上述都没错误的话,我们开始使用我们的东西了
new_user = models.User()#对于数据库里面表进行实例化,方便使用
new_user.name = username
new_user.password =hash_code(password1)
new_user.email = email
new_user.sex = sex
new_user.save()#进行保存
code = make_confirm_string(new_user)
send_email(email,code)
return render(request,'login/confirm.html',locals())#跳转到等待邮件确认页面
register_form = forms.RegisterForm()
return render(request,'login/register.html',locals())
def logout(request):
if not request.session.get('is_login',None):
#如果本来就没有登录,也就没有等出一说
return redirect("/index/")
request.session.flush()
# 或者使用下面的方法
# del request.session['is_login']
# del request.session['user_id']
# del request.session['user_name']
return redirect("/index/")
- url里面代码:
from django.contrib import admin
from django.urls import path
from login import views
from django.conf.urls import include
from django.urls import re_path
urlpatterns = [
path('admin/', admin.site.urls),
path('index/', views.index, name='index'),
path('login/', views.login, name='login'),
# path('',views.base,name ='base'),
path('', views.index),
path('register/', views.register, name='register'),
path('logout/', views.logout, name='logout'),
re_path(r'^captcha/', include('captcha.urls'), name='captchas'), # 添加captcha相对应的网址
re_path(r'^confirm/$', views.user_confirm, name='cofirms')
]
结课:
- 源码地址
- 借鉴自刘江先生的博客
你可能感兴趣的:(学生,python,django,python)