从零开始做个人网站(3)
写在前面:
由于作者仅仅是自学,且是独自做这个项目,代码中出现不少漏洞、错误、累赘或常识问题是难免的,作者也在不断努力学习中,请各位看官多提意见,轻喷~
基本信息
1. 项目环境
Python 3.10.7
Django 4.2
编辑器:VSCode
操作系统:Windows 10
2. 项目背景
正好近一段时间在自学 Django,突发奇想不妨试着做个个人网站练练手吧~
3. 项目构思
暂定为:登录系统 + 个人主页 + 个人博客 + 个人作品
项目代码
今天的任务是做完登录系统的视图 ~
tips: 本次所有代码除特殊说明,仍在 /LZLBlog/login/views.py 中编写
1. 登出视图
大体思路如下:
- 如果没有登录,跳转至登录页面(都没登录自然没有登出一说)
- 如果登录了,则清除之前设置的所有状态
登出视图函数代码如下:
def logout(request):
if not request.session.get('is_login', ''):
return redirect('/login/login/')
try:
response = redirect('/login/login/')
response.delete_cookie(key=hashcode('LZLBlog'))
request.session.flush()
redirect_href = conditional_escape(request.COOKIES.get('redirect_href',''))
if redirect_href:
return redirect(redirect_href)
else:
return response
except:
request.session.flush()
redirect_href = conditional_escape(request.COOKIES.get('redirect_href',''))
if redirect_href:
return redirect(redirect_href)
else:
return redirect('/login/login/')
代码注释:
1. key = hashcode('LZLBlog') 获取到的 Cookie 是 "记住我" 的标记
2. request.session.flush() 用于清空所有 session 会话
3. 如果有 redirect_href,那么跳转至其指定地址,若没有则跳转至登录页面
2. 重置密码视图函数
大体思路如下:
- 在第一个页面获取前端用户输入的邮箱,并发送验证链接至用户邮箱(带有标识符)
- 用户点击链接进入第二个页面,检查标识符是否正确且是否未过期
- 若标识符不正确,重新渲染页面并提示错误,若标识符过期,删除标识符,再重新渲染页面并提示错误
- 若检查通过,获取前端用户输入的密码与再次确认的密码,进行验证
- 验证未通过,重新渲染页面并提示错误
- 验证通过,更改用户密码并删除标识符,清除用户登录状态,跳转至登录页面
重置密码视图函数如下:
def reset(request):
message = ''
if request.method == 'POST':
email = conditional_escape(request.POST.get('email', ''))
message = '请检查填写的内容格式是否正确!'
if email:
if email_verification(email):
message = email_verification(email)
return render(request, 'login/reset.html', {'message':message})
try:
user = models.User.objects.get(email=email)
except:
message = '请检查填写的邮箱是否正确!'
return render(request, 'login/reset.html', {'message':message})
code = make_reset_password_confirm_string(user)
send_reset_password_email(email, code)
message = '邮件已发送,请查收邮件并通过邮件中的链接修改密码!'
return render(request, 'login/reset.html', {'message':message})
return render(request, 'login/reset.html', {'message':message})
return render(request, 'login/reset.html', {'message':message})
def resetpassword(request):
code = conditional_escape(request.GET.get('code', ''))
message = ''
if request.method == 'POST':
message = '请检查填写的内容是否符合格式!'
try:
confirm = models.ResetString.objects.get(code=code)
except:
message = '无效的修改密码链接!'
return render(request, 'login/resetpassword.html', {'message':message, 'code':''})
c_time = confirm.c_time
user = confirm.user
password = conditional_escape(request.POST.get('password', ''))
password_repeat = conditional_escape(request.POST.get('password_repeat', ''))
now = datetime.datetime.now()
now = now.replace(tzinfo=pytz.timezone('UTC'))
if now > c_time + datetime.timedelta(settings.CONFIRM_DAYS):
message = '邮件已过期,请重新重置密码!'
confirm.delete()
return render(request, 'login/resetpassword.html', {'message':message, 'code':code})
if password and password_repeat:
if password != password_repeat:
message = '两次输入的密码不同!'
return render(request, 'login/resetpassword.html', {'message':message, 'code':code})
if password_verification(password):
message = password_verification(password)
return render(request, 'login/resetpassword.html', {'message':message, 'code':code})
user.password = hashcode(password_repeat)
user.save()
confirm.delete()
response = redirect('/login/login/')
try:
response.delete_cookie(key=hashcode('LZLBlog'))
request.session.flush()
except:
request.session.flush()
return response
return render(request, 'login/resetpassword.html', {'message':message, 'code':code})
return render(request, 'login/resetpassword.html', {'message':message, 'code':code})
相信逻辑应该比较清楚,这里的代码注释不写了,可以参考前面注册视图理解
重置密码视图中出现的一些小函数:
1. 邮箱格式验证与密码验证函数
email_verification() 与 password_verification()
之前都提到过,与注册视图用到的函数是一致的,此处不再做解释
2. 创建重置密码标识符函数
作用:在邮箱验证通过后创建重置密码标识符,为下面的发送邮件做准备
def make_reset_password_confirm_string(user):
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
code = hashcode(user.name, now)
repeat_reset_list = models.ResetString.objects.filter(user=user)
if repeat_reset_list:
for repeat_reset in repeat_reset_list:
repeat_reset.delete()
models.ResetString.objects.create(code=code, user=user)
代码注释:
1. 使用用户名加密,用户创建的时间(精确到秒)作为盐,确保验证码的值是独一无二的
2. 首先检查是否有重复标识符,如果有,那么先删掉所有重复标识符再创建当前标识符
3. 发送邮件函数
作用:发送带有重置密码链接的邮件到用户刚刚输入的邮箱地址
def send_reset_password_email(email, code):
from django.core.mail import EmailMultiAlternatives
subject = "来自 www.LZLBlog.com 的修改密码邮件"
text_content = '''感谢来到 www.LZLBlog.com, 欢迎阅读作者的博客并发表评论与改进意见,
如果您看到这条信息,说明您的邮箱服务器不支持 HTML 链接功能,请检查或升级系统以解决问题!'''
html_content = '''
<p>感谢来到<a href="http://{}/index/index/" target=_blank> www.LZLBlog.com </a>,
欢迎阅读作者的博客并发表评论与改进意见!</p>
<h2>点击此链接以重置密码:<a href="http://{}/login/resetpassword/?code={}">重置密码链接</a></h2>
<p>此链接有效期为 {} 天!</p>
'''.format('127.0.0.1:8000', '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()
仍然假装自己有域名
代码注释:
1. 同注册视图中的发送邮件函数,这里需要有个开通 smtp 服务的邮箱,settings.py 中也要配置
2. 这里发送的是重置密码的 链接,而不是一个验证码
3. 用户主页视图函数
大体思路如下:
- 首先通过传递的 name 参数尝试获取用户,若不成功,直接返回
- 比对当前 登录的 用户是否是用户主页的用户
- 如果不是,打上限制标记,直接返回
- 如果是,获取前端用户输入的信息,更改相关用户信息(如签名、个人介绍等)
用户主页视图函数如下:
def index(request, name):
try:
user = models.User.objects.get(name=name)
username = user.name
except:
user = None
username = None
if not(user):
limits = 1
render(request, 'login/index.html', {'user':user, 'limits':limits, 'username':username, 'login':request.session.get('is_login', '')})
elif not(request.session.get('is_login', '')) or request.session.get('user_name','') != user.name:
limits = 1
return render(request, 'login/index.html', {'user':user, 'limits':limits, 'username':username, 'login':request.session.get('is_login', '')})
else:
limits = 0
if request.method == "POST":
big_detail = request.POST.get("big_detail", "")
if big_detail:
user.big_detail = big_detail
user.save()
small_description = conditional_escape(request.POST.get('small_description', ''))
if small_description:
user.small_description = small_description
user.save()
try:
avatar = request.FILES['avatar']
except:
avatar = None
if avatar:
user.avatar = avatar
user.save()
return render(request, 'login/index.html', {'user':user, "limits":limits, 'username':username, 'login':request.session.get('is_login', '')})
@csrf_exempt
def upload_image(request):
import os
if request.method == "POST":
file_obj = request.FILES['file']
file_name_suffix = file_obj.name.split(".")[-1]
if file_name_suffix not in ["jpg", "png", "gif", "jpeg"]:
return JsonResponse({"message": "错误的文件格式"})
upload_time = timezone.now()
path = os.path.join(
settings.MEDIA_ROOT,
'tinymce',
str(upload_time.year),
str(upload_time.month),
str(upload_time.day)
)
if not os.path.exists(path):
os.makedirs(path)
file_path = os.path.join(path, file_obj.name)
file_url = f'{settings.MEDIA_URL}tinymce/{upload_time.year}/{upload_time.month}/{upload_time.day}/{file_obj.name}'
if os.path.exists(file_path):
return JsonResponse({'message': '文件已存在', 'location': file_url})
with open(file_path, 'wb+') as f:
for chunk in file_obj.chunks():
f.write(chunk)
return JsonResponse({'message': '上传图片成功', 'location': file_url})
return JsonResponse({'detail': '错误的请求'})
代码注释:
1. upload_image() 函数是一个配置 tinymce 富文本编辑器上传图片的函数,与个人主页无关
2. 由于我在前端使用了 tinymce 富文本编辑器,因此需要配置这个函数
3. 这里仍然需要配置 media,还是等到后面再说
4. @csrf_exempt 装饰器用于取消 Django 在当前视图函数上的 CSRF 防御机制,不写会有 CSRF Forbidden 的问题
4. 404 处理函数
作用:处理 404(此视图只会在关闭开发服务器,即 settings.py 中的 DEBUG = False 时才会被使用)
代码如下:
@requires_csrf_token
def page_not_found(request, exception):
return render(request, 'login/404.html')
这里需要在 根 URLconf 即 LZLBlog/LZLBlog/urls.py 中配置:
"""LZLBlog URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/dev/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from login import views # 新添加的
urlpatterns = [
path('admin/', admin.site.urls),
]
handler404 = views.page_not_found # 新添加的
5. 全部代码
def logout(request):
if not request.session.get('is_login', ''):
return redirect('/login/login/')
try:
response = redirect('/login/login/')
response.delete_cookie(key=hashcode('LZLBlog'))
request.session.flush()
redirect_href = conditional_escape(request.COOKIES.get('redirect_href',''))
if redirect_href:
return redirect(redirect_href)
else:
return response
except:
request.session.flush()
redirect_href = conditional_escape(request.COOKIES.get('redirect_href',''))
if redirect_href:
return redirect(redirect_href)
else:
return redirect('/login/login/')
def make_reset_password_confirm_string(user):
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
code = hashcode(user.name, now)
repeat_reset_list = models.ResetString.objects.filter(user=user)
if repeat_reset_list:
for repeat_reset in repeat_reset_list:
repeat_reset.delete()
models.ResetString.objects.create(code=code, user=user)
return code
def send_reset_password_email(email, code):
from django.core.mail import EmailMultiAlternatives
subject = "来自 www.LZLBlog.com 的修改密码邮件"
text_content = '''感谢来到 www.LZLBlog.com, 欢迎阅读作者的博客并发表评论与改进意见,
如果您看到这条信息,说明您的邮箱服务器不支持 HTML 链接功能,请检查或升级系统以解决问题!'''
html_content = '''
<p>感谢来到<a href="http://{}/index/index/" target=_blank> www.LZLBlog.com </a>,
欢迎阅读作者的博客并发表评论与改进意见!</p>
<h2>点击此链接以重置密码:<a href="http://{}/login/resetpassword/?code={}">重置密码链接</a></h2>
<p>此链接有效期为 {} 天!</p>
'''.format('127.0.0.1:8000', '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 reset(request):
message = ''
if request.method == 'POST':
email = conditional_escape(request.POST.get('email', ''))
message = '请检查填写的内容格式是否正确!'
if email:
if email_verification(email):
message = email_verification(email)
return render(request, 'login/reset.html', {'message':message})
try:
user = models.User.objects.get(email=email)
except:
message = '请检查填写的邮箱是否正确!'
return render(request, 'login/reset.html', {'message':message})
code = make_reset_password_confirm_string(user)
send_reset_password_email(email, code)
message = '邮件已发送,请查收邮件并通过邮件中的链接修改密码!'
return render(request, 'login/reset.html', {'message':message})
return render(request, 'login/reset.html', {'message':message})
return render(request, 'login/reset.html', {'message':message})
def resetpassword(request):
code = conditional_escape(request.GET.get('code', ''))
message = ''
if request.method == 'POST':
message = '请检查填写的内容是否符合格式!'
try:
confirm = models.ResetString.objects.get(code=code)
except:
message = '无效的修改密码链接!'
return render(request, 'login/resetpassword.html', {'message':message, 'code':''})
c_time = confirm.c_time
user = confirm.user
password = conditional_escape(request.POST.get('password', ''))
password_repeat = conditional_escape(request.POST.get('password_repeat', ''))
now = datetime.datetime.now()
now = now.replace(tzinfo=pytz.timezone('UTC'))
if now > c_time + datetime.timedelta(settings.CONFIRM_DAYS):
message = '邮件已过期,请重新重置密码!'
confirm.delete()
return render(request, 'login/resetpassword.html', {'message':message, 'code':code})
if password and password_repeat:
if password != password_repeat:
message = '两次输入的密码不同!'
return render(request, 'login/resetpassword.html', {'message':message, 'code':code})
if password_verification(password):
message = password_verification(password)
return render(request, 'login/resetpassword.html', {'message':message, 'code':code})
user.password = hashcode(password_repeat)
user.save()
confirm.delete()
response = redirect('/login/login/')
try:
response.delete_cookie(key=hashcode('LZLBlog'))
request.session.flush()
except:
request.session.flush()
return response
return render(request, 'login/resetpassword.html', {'message':message, 'code':code})
return render(request, 'login/resetpassword.html', {'message':message, 'code':code})
def index(request, name):
try:
user = models.User.objects.get(name=name)
username = user.name
except:
user = None
username = None
if not(user):
limits = 1
render(request, 'login/index.html', {'user':user, 'limits':limits, 'username':username, 'login':request.session.get('is_login', '')})
elif not(request.session.get('is_login', '')) or request.session.get('user_name','') != user.name:
limits = 1
return render(request, 'login/index.html', {'user':user, 'limits':limits, 'username':username, 'login':request.session.get('is_login', '')})
else:
limits = 0
if request.method == "POST":
big_detail = request.POST.get("big_detail", "")
if big_detail:
user.big_detail = big_detail
user.save()
small_description = conditional_escape(request.POST.get('small_description', ''))
if small_description:
user.small_description = small_description
user.save()
try:
avatar = request.FILES['avatar']
except:
avatar = None
if avatar:
user.avatar = avatar
user.save()
return render(request, 'login/index.html', {'user':user, "limits":limits, 'username':username, 'login':request.session.get('is_login', '')})
@csrf_exempt
def upload_image(request):
import os
if request.method == "POST":
file_obj = request.FILES['file']
file_name_suffix = file_obj.name.split(".")[-1]
if file_name_suffix not in ["jpg", "png", "gif", "jpeg"]:
return JsonResponse({"message": "错误的文件格式"})
upload_time = timezone.now()
path = os.path.join(
settings.MEDIA_ROOT,
'tinymce',
str(upload_time.year),
str(upload_time.month),
str(upload_time.day)
)
if not os.path.exists(path):
os.makedirs(path)
file_path = os.path.join(path, file_obj.name)
file_url = f'{settings.MEDIA_URL}tinymce/{upload_time.year}/{upload_time.month}/{upload_time.day}/{file_obj.name}'
if os.path.exists(file_path):
return JsonResponse({'message': '文件已存在', 'location': file_url})
with open(file_path, 'wb+') as f:
for chunk in file_obj.chunks():
f.write(chunk)
return JsonResponse({'message': '上传图片成功', 'location': file_url})
return JsonResponse({'detail': '错误的请求'})
@requires_csrf_token
def page_not_found(request, exception):
return render(request, 'login/404.html')
至此,登录视图函数的内容就完结啦~
下篇做前端模板 (HTML5 + CSS3 + JavaScript)~
最后在篇尾,附上登录视图函数的全部代码
from django.conf import settings
from django.shortcuts import render
from django.shortcuts import redirect
from django.utils.html import conditional_escape
from django.views.decorators.csrf import csrf_exempt, requires_csrf_token
from django.http import JsonResponse
from django.utils import timezone
from . import models
import hashlib, datetime, random, pytz
# Create your views here.
def hashcode(s, salt="LZLBlog"):
h = hashlib.sha256()
s += salt
h.update(s.encode())
return h.hexdigest()
def login(request):
if request.session.get("is_login", ""):
return redirect("/index/index/")
visitnum = int(conditional_escape(request.session.get('visit_num', 0)))
if visitnum <= 3:
request.session['visit_num'] = visitnum+1
else:
turn_visit_num = conditional_escape(request.POST.get('turn_visit_num',0))
if turn_visit_num:
request.session['visit_num'] = 1
try:
remember_signature = request.get_signed_cookie(key=hashcode('LZLBlog'), salt=hashcode('LZLBlog'), max_age=7*24*3600)
if remember_signature == hashcode(hashcode('LZLBlog')):
href = conditional_escape(request.COOKIES.get('redirect_href',None))
if href:
return redirect(href)
else:
username = conditional_escape(request.get_signed_cookie(key=hashcode('username'), salt=hashcode(hashcode('username')), max_age=7*24*3600))
return redirect('/index/index/')
except:
pass
if request.method == "POST":
username = conditional_escape(request.POST.get("username",''))
password = conditional_escape(request.POST.get("password",''))
message = '请检查填写的内容格式是否正确!'
if username.strip() and password:
try:
user = models.User.objects.get(name=username)
except:
try:
user = models.User.objects.get(email=username)
except:
message = '用户名或密码不正确!'
return render(request, 'login/login.html', {'message':message})
if user.password == hashcode(password):
if not(user.has_confirmed):
message = '用户未经过邮件确认!'
return render(request, 'login/login.html', {'message':message})
request.session['is_login'] = 1
request.session['user_id'] = user.id
request.session['user_name'] = user.name
response = redirect('/index/index/')
remember = request.POST.get('remember', '')
href = conditional_escape(request.COOKIES.get('redirect_href',''))
if remember:
response.set_signed_cookie(key=hashcode('LZLBlog'), value=hashcode(hashcode('LZLBlog')), salt=hashcode('LZLBlog'), max_age=7*24*3600)
response.set_signed_cookie(key=hashcode('username'), value=hashcode(user.name), salt=hashcode(hashcode('username')), max_age=7*24*3600)
if href:
return redirect(href)
else:
return response
else:
message = '用户名或密码不正确!'
return render(request, 'login/login.html', {'message':message})
else:
message = ''
return render(request, 'login/login.html', {'message':message})
def password_verification(password):
message = ''
if len(password) < 8:
message = '密码位数必须至少有 8 位!'
return message
for chars in password:
if '\u4e00' <= chars and chars <= '\u9fff':
message = '密码中不可以包含中文字符!'
return message
en = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']
capital_en = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
number = ['1','2','3','4','5','6','7','8','9']
flag = 0
for letter in en:
if letter in password:
flag = flag + 1
break
for letter in capital_en:
if letter in password:
flag = flag + 1
break
for num in number:
if num in password:
flag = flag+1
break
if flag < 2:
message = '密码必须至少包含小写字母、大写字母和数字中的两种!'
return message
return message
def email_verification(email):
message = ''
emaillist = list(email)
if emaillist.count('@') != 1:
message = '请检查邮箱格式是否正确!'
return message
if emaillist.index('@') == 0 or emaillist.index('@') == len(emaillist)-1:
message = '请检查邮箱格式是否正确!'
return message
return message
def make_confirm_string(user):
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
code = hashcode(user.name, now)
tag = hashcode(user.name, "tag")
get_str = ''
for x in range(6):
num = random.randint(0,len(code)-1)
get_str = get_str + code[num]
models.ConfirmString.objects.create(code=get_str, user=user, tag=tag)
return (get_str,tag)
def send_email(email, code):
from django.core.mail import EmailMultiAlternatives
subject = "来自 www.LZLBlog.com 的注册确认邮件"
text_content = '''感谢注册 www.LZLBlog.com, 欢迎阅读作者的博客并发表评论与改进意见,
如果您看到这条信息,说明您的邮箱服务器不支持 HTML 链接功能,请检查或升级系统以解决问题!'''
html_content = '''
<p>感谢注册<a href="http://{}/index/index/" target=_blank> www.LZLBlog.com </a>,
欢迎阅读作者的博客并发表评论与改进意见!</p>
<p>您的验证码是:</p><h1> {} </h1>
<p>此验证码有效期为 {} 天!</p>
'''.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 register(request):
if request.method == 'POST':
username = conditional_escape(request.POST.get('username',''))
password = conditional_escape(request.POST.get('password',''))
password_repeat = conditional_escape(request.POST.get('password_again',''))
email = conditional_escape(request.POST.get('email',''))
message = "请检查填写的内容格式是否正确!"
if username.strip() and password and password_repeat and email:
if password != password_repeat:
message = "两次输入的密码不同!"
return render(request, 'login/register.html', {'message':message})
else:
user_list = models.User.objects.filter(name=username)
if user_list:
message = "该用户名已经存在!"
return render(request, 'login/register.html', {'message':message})
email_list = models.User.objects.filter(email=email)
if email_list:
message = "该邮箱已经被注册了!"
return render(request, 'login/register.html', {'message':message})
if password_verification(password):
message = password_verification(password)
return render(request, 'login/register.html', {'message':message})
if email_verification(email):
message = email_verification(email)
return render(request, 'login/register.html', {'message':message})
new_user = models.User()
new_user.name = username
new_user.password = hashcode(password_repeat)
new_user.email = email
new_user.save()
code,tag = make_confirm_string(new_user)
send_email(email, code)
request.session['tag'] = tag
return redirect('/login/confirm/')
else:
return render(request, 'login/register.html', {'message':message})
return render(request, 'login/register.html')
def user_confirm(request):
message = ''
if request.method == "POST":
tag = conditional_escape(request.session.get('tag', ''))
email_password = conditional_escape(request.POST.get('email_password',''))
try:
confirm = models.ConfirmString.objects.get(tag=tag)
except:
return render(request, 'login/confirm.html', {'message':message})
c_time = confirm.c_time
now = datetime.datetime.now()
now = now.replace(tzinfo=pytz.timezone('UTC'))
if now > c_time + datetime.timedelta(settings.CONFIRM_DAYS):
confirm.user.delete()
del request.session['tag']
message = '您的邮件已经过期!请重新注册!'
return render(request, 'login/confirm.html', {'message':message})
if email_password == confirm.code:
confirm.user.has_confirmed = True
confirm.user.save()
confirm.delete()
del request.session['tag']
return redirect('/login/login/')
else:
message = '邮箱验证码不正确!'
return render(request, 'login/confirm.html', {'message':message})
return render(request, 'login/confirm.html', {'message':message})
def logout(request):
if not request.session.get('is_login', ''):
return redirect('/login/login/')
try:
response = redirect('/login/login/')
response.delete_cookie(key=hashcode('LZLBlog'))
request.session.flush()
redirect_href = conditional_escape(request.COOKIES.get('redirect_href',''))
if redirect_href:
return redirect(redirect_href)
else:
return response
except:
request.session.flush()
redirect_href = conditional_escape(request.COOKIES.get('redirect_href',''))
if redirect_href:
return redirect(redirect_href)
else:
return redirect('/login/login/')
def make_reset_password_confirm_string(user):
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
code = hashcode(user.name, now)
repeat_reset_list = models.ResetString.objects.filter(user=user)
if repeat_reset_list:
for repeat_reset in repeat_reset_list:
repeat_reset.delete()
models.ResetString.objects.create(code=code, user=user)
return code
def send_reset_password_email(email, code):
from django.core.mail import EmailMultiAlternatives
subject = "来自 www.LZLBlog.com 的修改密码邮件"
text_content = '''感谢来到 www.LZLBlog.com, 欢迎阅读作者的博客并发表评论与改进意见,
如果您看到这条信息,说明您的邮箱服务器不支持 HTML 链接功能,请检查或升级系统以解决问题!'''
html_content = '''
<p>感谢来到<a href="http://{}/index/index/" target=_blank> www.LZLBlog.com </a>,
欢迎阅读作者的博客并发表评论与改进意见!</p>
<h2>点击此链接以重置密码:<a href="http://{}/login/resetpassword/?code={}">重置密码链接</a></h2>
<p>此链接有效期为 {} 天!</p>
'''.format('127.0.0.1:8000', '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 reset(request):
message = ''
if request.method == 'POST':
email = conditional_escape(request.POST.get('email', ''))
message = '请检查填写的内容格式是否正确!'
if email:
if email_verification(email):
message = email_verification(email)
return render(request, 'login/reset.html', {'message':message})
try:
user = models.User.objects.get(email=email)
except:
message = '请检查填写的邮箱是否正确!'
return render(request, 'login/reset.html', {'message':message})
code = make_reset_password_confirm_string(user)
send_reset_password_email(email, code)
message = '邮件已发送,请查收邮件并通过邮件中的链接修改密码!'
return render(request, 'login/reset.html', {'message':message})
return render(request, 'login/reset.html', {'message':message})
return render(request, 'login/reset.html', {'message':message})
def resetpassword(request):
code = conditional_escape(request.GET.get('code', ''))
message = ''
if request.method == 'POST':
message = '请检查填写的内容是否符合格式!'
try:
confirm = models.ResetString.objects.get(code=code)
except:
message = '无效的修改密码链接!'
return render(request, 'login/resetpassword.html', {'message':message, 'code':''})
c_time = confirm.c_time
user = confirm.user
password = conditional_escape(request.POST.get('password', ''))
password_repeat = conditional_escape(request.POST.get('password_repeat', ''))
now = datetime.datetime.now()
now = now.replace(tzinfo=pytz.timezone('UTC'))
if now > c_time + datetime.timedelta(settings.CONFIRM_DAYS):
message = '邮件已过期,请重新重置密码!'
confirm.delete()
return render(request, 'login/resetpassword.html', {'message':message, 'code':code})
if password and password_repeat:
if password != password_repeat:
message = '两次输入的密码不同!'
return render(request, 'login/resetpassword.html', {'message':message, 'code':code})
if password_verification(password):
message = password_verification(password)
return render(request, 'login/resetpassword.html', {'message':message, 'code':code})
user.password = hashcode(password_repeat)
user.save()
confirm.delete()
response = redirect('/login/login/')
try:
response.delete_cookie(key=hashcode('LZLBlog'))
request.session.flush()
except:
request.session.flush()
return response
return render(request, 'login/resetpassword.html', {'message':message, 'code':code})
return render(request, 'login/resetpassword.html', {'message':message, 'code':code})
def index(request, name):
try:
user = models.User.objects.get(name=name)
username = user.name
except:
user = None
username = None
if not(user):
limits = 1
render(request, 'login/index.html', {'user':user, 'limits':limits, 'username':username, 'login':request.session.get('is_login', '')})
elif not(request.session.get('is_login', '')) or request.session.get('user_name','') != user.name:
limits = 1
return render(request, 'login/index.html', {'user':user, 'limits':limits, 'username':username, 'login':request.session.get('is_login', '')})
else:
limits = 0
if request.method == "POST":
big_detail = request.POST.get("big_detail", "")
if big_detail:
user.big_detail = big_detail
user.save()
small_description = conditional_escape(request.POST.get('small_description', ''))
if small_description:
user.small_description = small_description
user.save()
try:
avatar = request.FILES['avatar']
except:
avatar = None
if avatar:
user.avatar = avatar
user.save()
return render(request, 'login/index.html', {'user':user, "limits":limits, 'username':username, 'login':request.session.get('is_login', '')})
@csrf_exempt
def upload_image(request):
import os
if request.method == "POST":
file_obj = request.FILES['file']
file_name_suffix = file_obj.name.split(".")[-1]
if file_name_suffix not in ["jpg", "png", "gif", "jpeg"]:
return JsonResponse({"message": "错误的文件格式"})
upload_time = timezone.now()
path = os.path.join(
settings.MEDIA_ROOT,
'tinymce',
str(upload_time.year),
str(upload_time.month),
str(upload_time.day)
)
if not os.path.exists(path):
os.makedirs(path)
file_path = os.path.join(path, file_obj.name)
file_url = f'{settings.MEDIA_URL}tinymce/{upload_time.year}/{upload_time.month}/{upload_time.day}/{file_obj.name}'
if os.path.exists(file_path):
return JsonResponse({'message': '文件已存在', 'location': file_url})
with open(file_path, 'wb+') as f:
for chunk in file_obj.chunks():
f.write(chunk)
return JsonResponse({'message': '上传图片成功', 'location': file_url})
return JsonResponse({'detail': '错误的请求'})
@requires_csrf_token
def page_not_found(request, exception):
return render(request, 'login/404.html')
下篇再见~