Compare commits

...

16 Commits

@ -0,0 +1,132 @@
"""
DjangoBlog 站点地图配置模块
功能为搜索引擎提供网站结构地图支持文章分类标签等内容的自动索引
"""
from django.contrib.sitemaps import Sitemap
from django.urls import reverse
from blog.models import Article, Category, Tag
class StaticViewSitemap(Sitemap):
"""
静态页面站点地图
用于生成固定页面的站点地图如首页等
"""
# 优先级0.5中等优先级首页等重要页面可以设为1.0
priority = 0.5
# 更新频率:每天检查
changefreq = 'daily'
def items(self):
"""
返回包含在站点地图中的静态页面名称
这些名称需要与 urls.py 中的 URL 名称对应
"""
return ['blog:index', ] # 博客首页
def location(self, item):
"""
根据页面名称生成完整的 URL 地址
"""
return reverse(item)
class ArticleSiteMap(Sitemap):
"""
文章站点地图
自动生成所有已发布文章的站点地图
"""
# 更新频率:每月检查(文章内容相对稳定)
changefreq = "monthly"
# 优先级0.6(文章是核心内容,优先级较高)
priority = "0.6"
def items(self):
"""
返回所有已发布的文章对象
status='p' 表示已发布状态
"""
return Article.objects.filter(status='p')
def lastmod(self, obj):
"""
返回文章的最后修改时间
帮助搜索引擎了解内容更新情况
"""
return obj.last_modify_time
class CategorySiteMap(Sitemap):
"""
分类站点地图
生成文章分类页面的站点地图
"""
# 更新频率:每周检查(分类结构相对稳定)
changefreq = "Weekly"
# 优先级0.6(分类页面重要程度较高)
priority = "0.6"
def items(self):
"""
返回所有分类对象
"""
return Category.objects.all()
def lastmod(self, obj):
"""
返回分类的最后修改时间
当分类下的文章更新时分类页面也需要更新
"""
return obj.last_modify_time
class TagSiteMap(Sitemap):
"""
标签站点地图
生成标签页面的站点地图
"""
# 更新频率:每周检查
changefreq = "Weekly"
# 优先级0.3(标签页面重要性相对较低)
priority = "0.3"
def items(self):
"""
返回所有标签对象
"""
return Tag.objects.all()
def lastmod(self, obj):
"""
返回标签的最后修改时间
当标签关联的文章更新时标签页面也需要更新
"""
return obj.last_modify_time
class UserSiteMap(Sitemap):
"""
用户站点地图
生成用户主页的站点地图
"""
# 更新频率:每周检查
changefreq = "Weekly"
# 优先级0.3(用户页面重要性相对较低)
priority = "0.3"
def items(self):
"""
返回所有发表过文章的用户作者
使用 set 去重确保每个用户只出现一次
"""
return list(set(map(lambda x: x.author, Article.objects.all())))
def lastmod(self, obj):
"""
返回用户的注册时间
这里使用用户注册时间作为最后修改时间
实际可以根据用户最后活动时间优化
"""
return obj.date_joined

@ -1,14 +1,38 @@
from django import forms from django import forms
from django.contrib.auth.admin import UserAdmin from django.contrib.auth.admin import UserAdmin # Django 自带的用户管理后台基类
from django.contrib.auth.forms import UserChangeForm from django.contrib.auth.forms import UserChangeForm # Django 默认的用户信息修改表单
from django.contrib.auth.forms import UsernameField from django.contrib.auth.forms import UsernameField # Django 用于用户名字段的专用表单字段
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _ # 用于支持多语言翻译的辅助函数
# Register your models here. # 从当前 app 的 models 导入自定义的用户模型 BlogUser
from .models import BlogUser from .models import BlogUser
# ======================
# 自定义用户创建表单(用于后台添加用户时使用)
# ======================
class BlogUserCreationForm(forms.ModelForm): class BlogUserCreationForm(forms.ModelForm):
<<<<<<< HEAD
# 添加两个密码字段,用于用户注册时输入和确认密码
password1 = forms.CharField(
label=_('password'), # 字段显示名称可翻译这里是“password”
widget=forms.PasswordInput # 使用密码输入框,输入内容会被隐藏
)
password2 = forms.CharField(
label=_('Enter password again'), # 确认密码的标签
widget=forms.PasswordInput # 同样是密码输入框
)
class Meta:
model = BlogUser # 指定该表单关联的模型是 BlogUser
fields = ('email',) # 在创建用户时,只显示 email 字段(可以从后台选择的字段)
def clean_password2(self):
"""
校验两次输入的密码是否一致
"""
# 从 cleaned_data 中获取用户输入的两个密码
=======
""" """
自定义用户创建表单用于在Admin后台添加新用户 自定义用户创建表单用于在Admin后台添加新用户
继承自ModelForm提供密码验证和哈希处理功能 继承自ModelForm提供密码验证和哈希处理功能
@ -25,14 +49,36 @@ class BlogUserCreationForm(forms.ModelForm):
验证两次输入的密码是否一致 验证两次输入的密码是否一致
如果密码不匹配抛出验证错误 如果密码不匹配抛出验证错误
""" """
>>>>>>> master
password1 = self.cleaned_data.get("password1") password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2") password2 = self.cleaned_data.get("password2")
# 如果两个密码都有值,但它们不相等,则抛出验证错误
if password1 and password2 and password1 != password2: if password1 and password2 and password1 != password2:
raise forms.ValidationError(_("passwords do not match")) raise forms.ValidationError(_("passwords do not match")) # 提示“密码不匹配”
# 验证通过,返回 password2通常返回确认密码字段的值
return password2 return password2
def save(self, commit=True): def save(self, commit=True):
""" """
<<<<<<< HEAD
保存用户对象并对密码进行哈希处理
"""
# 调用父类的 save 方法但不立即提交到数据库commit=False
user = super().save(commit=False)
# 对用户输入的密码password1进行哈希处理并设置到 user 对象上
user.set_password(self.cleaned_data["password1"])
if commit:
# 如果 commit=True默认则保存到数据库
# 同时,给用户添加一个来源标识 source = 'adminsite',表示是通过后台添加的
user.source = 'adminsite'
user.save()
# 返回保存后的用户对象
=======
保存用户信息对密码进行哈希处理 保存用户信息对密码进行哈希处理
commit参数控制是否立即保存到数据库 commit参数控制是否立即保存到数据库
""" """
@ -41,15 +87,31 @@ class BlogUserCreationForm(forms.ModelForm):
if commit: if commit:
user.source = 'adminsite' # 标记用户来源为管理员后台 user.source = 'adminsite' # 标记用户来源为管理员后台
user.save() # 保存到数据库 user.save() # 保存到数据库
>>>>>>> master
return user return user
# ======================
# 自定义用户修改表单(用于后台编辑用户信息时使用)
# ======================
class BlogUserChangeForm(UserChangeForm): class BlogUserChangeForm(UserChangeForm):
""" """
自定义用户信息修改表单 自定义用户信息修改表单
继承自Django内置的UserChangeForm用于在Admin后台编辑用户信息 继承自Django内置的UserChangeForm用于在Admin后台编辑用户信息
""" """
class Meta: class Meta:
<<<<<<< HEAD
model = BlogUser # 指定关联的模型是 BlogUser
fields = '__all__' # 表单中包含模型的所有字段
# 指定 username 字段使用 Django 提供的 UsernameField它对用户名有特殊处理如唯一性等
field_classes = {'username': UsernameField}
def __init__(self, *args, **kwargs):
"""
初始化方法这里暂时没有额外逻辑只是调用了父类的初始化
"""
super().__init__(*args, **kwargs)
=======
model = BlogUser model = BlogUser
fields = '__all__' # 包含所有字段 fields = '__all__' # 包含所有字段
field_classes = {'username': UsernameField} # 指定用户名字段的类型 field_classes = {'username': UsernameField} # 指定用户名字段的类型
@ -57,9 +119,38 @@ class BlogUserChangeForm(UserChangeForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
"""初始化方法,可以在这里添加自定义的表单逻辑""" """初始化方法,可以在这里添加自定义的表单逻辑"""
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
>>>>>>> master
# ======================
# 自定义用户管理后台类(用于在 Django Admin 中管理 BlogUser 模型)
# ======================
class BlogUserAdmin(UserAdmin): class BlogUserAdmin(UserAdmin):
<<<<<<< HEAD
# 指定用户修改时使用的表单类(编辑用户信息时)
form = BlogUserChangeForm
# 指定用户创建时使用的表单类(添加新用户时)
add_form = BlogUserCreationForm
# 定义在用户列表页显示哪些字段
list_display = (
'id', # 用户 ID
'nickname', # 昵称(假设你的 BlogUser 模型中有这个字段)
'username', # 用户名
'email', # 邮箱
'last_login', # 上次登录时间
'date_joined', # 注册时间
'source' # 用户来源(比如 adminsite 表示后台添加)
)
# 定义哪些字段可以作为链接,点击后可以进入编辑页面
# 这里 id 和 username 都可以作为链接
list_display_links = ('id', 'username')
# 定义默认排序方式,这里是按照 id 降序(最新的用户在前面)
ordering = ('-id',)
=======
""" """
自定义用户管理类配置Admin后台的用户管理界面 自定义用户管理类配置Admin后台的用户管理界面
继承自Django内置的UserAdmin类 继承自Django内置的UserAdmin类
@ -79,4 +170,5 @@ class BlogUserAdmin(UserAdmin):
) )
list_display_links = ('id', 'username') # 可点击跳转到编辑页面的字段 list_display_links = ('id', 'username') # 可点击跳转到编辑页面的字段
ordering = ('-id',) # 按ID倒序排列最新的用户显示在最前面 ordering = ('-id',) # 按ID倒序排列最新的用户显示在最前面
>>>>>>> master

@ -1,31 +1,50 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# 指定脚本解释器为bash
# 定义应用名称为djangoblog
NAME="djangoblog" NAME="djangoblog"
# 定义Django项目根目录路径
DJANGODIR=/code/djangoblog DJANGODIR=/code/djangoblog
# 定义运行应用的用户
USER=root USER=root
# 定义运行应用的用户组
GROUP=root GROUP=root
# 定义Gunicorn工作进程数量
NUM_WORKERS=1 NUM_WORKERS=1
# 定义Django的WSGI模块路径
DJANGO_WSGI_MODULE=djangoblog.wsgi DJANGO_WSGI_MODULE=djangoblog.wsgi
# 输出启动信息,显示当前启动的应用名称和执行用户
echo "Starting $NAME as `whoami`" echo "Starting $NAME as `whoami`"
# 进入Django项目根目录
cd $DJANGODIR cd $DJANGODIR
# 将项目目录添加到Python路径中确保Python能正确导入项目模块
export PYTHONPATH=$DJANGODIR:$PYTHONPATH export PYTHONPATH=$DJANGODIR:$PYTHONPATH
# 执行Django项目初始化命令序列若任何一步失败则退出脚本
# 1. 生成数据库迁移文件
python manage.py makemigrations && \ python manage.py makemigrations && \
# 2. 应用数据库迁移
python manage.py migrate && \ python manage.py migrate && \
# 3. 收集静态文件(无交互模式)
python manage.py collectstatic --noinput && \ python manage.py collectstatic --noinput && \
# 4. 强制压缩静态文件通常用于CSS/JS压缩
python manage.py compress --force && \ python manage.py compress --force && \
# 5. 构建搜索索引(如果项目使用了全文搜索功能)
python manage.py build_index && \ python manage.py build_index && \
# 6. 编译翻译文件(用于国际化支持)
python manage.py compilemessages || exit 1 python manage.py compilemessages || exit 1
# 启动Gunicorn作为WSGI服务器替换当前进程exec命令特性
exec gunicorn ${DJANGO_WSGI_MODULE}:application \ exec gunicorn ${DJANGO_WSGI_MODULE}:application \
--name $NAME \ --name $NAME \ # 指定应用名称
--workers $NUM_WORKERS \ --workers $NUM_WORKERS \ # 指定工作进程数量
--user=$USER --group=$GROUP \ --user=$USER --group=$GROUP \ # 指定运行的用户和用户组
--bind 0.0.0.0:8000 \ --bind 0.0.0.0:8000 \ # 绑定监听地址和端口0.0.0.0表示允许所有网络访问)
--log-level=debug \ --log-level=debug \ # 设置日志级别为debug
--log-file=- \ --log-file=- \ # 日志输出到标准输出(-表示stdout
--worker-class gevent \ --worker-class gevent \ # 使用gevent工作类支持异步IO提高并发性能
--threads 4 --threads 4 # 每个工作进程的线程数量

@ -1,34 +1,47 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<!-- 加载static静态文件标签用于后面引用静态资源 -->
{% load static %} {% load static %}
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags --> <!-- 以上3个meta标签必须放在head的最前面 -->
<meta name="description" content=""> <meta name="description" content="">
<meta name="author" content=""> <meta name="author" content="">
<link rel="icon" href="../../favicon.ico"> <link rel="icon" href="../../favicon.ico">
<!-- 禁止搜索引擎索引此页面 -->
<meta name="robots" content="noindex"> <meta name="robots" content="noindex">
<!-- 动态设置页面标题使用Django模板变量 -->
<title>{{ SITE_NAME }} | {{ SITE_DESCRIPTION }}</title> <title>{{ SITE_NAME }} | {{ SITE_DESCRIPTION }}</title>
<!-- 加载账户相关的CSS文件 -->
<link href="{% static 'account/css/account.css' %}" rel="stylesheet"> <link href="{% static 'account/css/account.css' %}" rel="stylesheet">
<!-- 使用Django压缩工具压缩CSS文件 -->
{% load compress %} {% load compress %}
{% compress css %} {% compress css %}
<!-- Bootstrap core CSS --> <!-- Bootstrap核心CSS文件 -->
<link href="{% static 'assets/css/bootstrap.min.css' %}" rel="stylesheet"> <link href="{% static 'assets/css/bootstrap.min.css' %}" rel="stylesheet">
<!-- OAuth认证样式 -->
<link href="{% static 'blog/css/oauth_style.css' %}" rel="stylesheet"> <link href="{% static 'blog/css/oauth_style.css' %}" rel="stylesheet">
<!-- IE10 viewport hack for Surface/desktop Windows 8 bug --> <!-- IE10视口bug修复 -->
<link href="{% static 'assets/css/ie10-viewport-bug-workaround.css' %}" rel="stylesheet"> <link href="{% static 'assets/css/ie10-viewport-bug-workaround.css' %}" rel="stylesheet">
<!-- TODC Bootstrap core CSS --> <!-- TODC Bootstrap样式 -->
<link href="{% static 'assets/css/todc-bootstrap.min.css' %}" rel="stylesheet"> <link href="{% static 'assets/css/todc-bootstrap.min.css' %}" rel="stylesheet">
<!-- Custom styles for this template --> <!-- 登录页面自定义样式 -->
<link href="{% static 'assets/css/signin.css' %}" rel="stylesheet"> <link href="{% static 'assets/css/signin.css' %}" rel="stylesheet">
{% endcompress %} {% endcompress %}
<!-- 压缩JavaScript文件 -->
{% compress js %} {% compress js %}
<!-- IE10视口bug修复脚本 -->
<script src="{% static 'assets/js/ie10-viewport-bug-workaround.js' %}"></script> <script src="{% static 'assets/js/ie10-viewport-bug-workaround.js' %}"></script>
<!-- IE浏览器仿真模式警告 -->
<script src="{% static 'assets/js/ie-emulation-modes-warning.js' %}"></script> <script src="{% static 'assets/js/ie-emulation-modes-warning.js' %}"></script>
{% endcompress %} {% endcompress %}
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- HTML5 shim和Respond.js用于IE8支持HTML5元素和媒体查询 -->
<!--[if lt IE 9]> <!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script> <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
@ -36,12 +49,15 @@
</head> </head>
<body> <body>
{% block content %} <!-- 定义内容块,子模板可以在此处插入具体内容 -->
{% endblock %} {% block content %}
{% endblock %}
<!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
<!-- IE10视口hack用于Surface/桌面Windows 8 bug -->
</body> </body>
<!-- 引入jQuery库 -->
<script type="text/javascript" src="{% static 'blog/js/jquery-3.6.0.min.js' %}"></script> <script type="text/javascript" src="{% static 'blog/js/jquery-3.6.0.min.js' %}"></script>
<!-- 引入账户相关的JavaScript文件 -->
<script src="{% static 'account/js/account.js' %}" type="text/javascript"></script> <script src="{% static 'account/js/account.js' %}" type="text/javascript"></script>
</html> </html>

@ -0,0 +1,132 @@
"""
DjangoBlog 站点地图配置模块
功能为搜索引擎提供网站结构地图支持文章分类标签等内容的自动索引
"""
from django.contrib.sitemaps import Sitemap
from django.urls import reverse
from blog.models import Article, Category, Tag
class StaticViewSitemap(Sitemap):
"""
静态页面站点地图
用于生成固定页面的站点地图如首页等
"""
# 优先级0.5中等优先级首页等重要页面可以设为1.0
priority = 0.5
# 更新频率:每天检查
changefreq = 'daily'
def items(self):
"""
返回包含在站点地图中的静态页面名称
这些名称需要与 urls.py 中的 URL 名称对应
"""
return ['blog:index', ] # 博客首页
def location(self, item):
"""
根据页面名称生成完整的 URL 地址
"""
return reverse(item)
class ArticleSiteMap(Sitemap):
"""
文章站点地图
自动生成所有已发布文章的站点地图
"""
# 更新频率:每月检查(文章内容相对稳定)
changefreq = "monthly"
# 优先级0.6(文章是核心内容,优先级较高)
priority = "0.6"
def items(self):
"""
返回所有已发布的文章对象
status='p' 表示已发布状态
"""
return Article.objects.filter(status='p')
def lastmod(self, obj):
"""
返回文章的最后修改时间
帮助搜索引擎了解内容更新情况
"""
return obj.last_modify_time
class CategorySiteMap(Sitemap):
"""
分类站点地图
生成文章分类页面的站点地图
"""
# 更新频率:每周检查(分类结构相对稳定)
changefreq = "Weekly"
# 优先级0.6(分类页面重要程度较高)
priority = "0.6"
def items(self):
"""
返回所有分类对象
"""
return Category.objects.all()
def lastmod(self, obj):
"""
返回分类的最后修改时间
当分类下的文章更新时分类页面也需要更新
"""
return obj.last_modify_time
class TagSiteMap(Sitemap):
"""
标签站点地图
生成标签页面的站点地图
"""
# 更新频率:每周检查
changefreq = "Weekly"
# 优先级0.3(标签页面重要性相对较低)
priority = "0.3"
def items(self):
"""
返回所有标签对象
"""
return Tag.objects.all()
def lastmod(self, obj):
"""
返回标签的最后修改时间
当标签关联的文章更新时标签页面也需要更新
"""
return obj.last_modify_time
class UserSiteMap(Sitemap):
"""
用户站点地图
生成用户主页的站点地图
"""
# 更新频率:每周检查
changefreq = "Weekly"
# 优先级0.3(用户页面重要性相对较低)
priority = "0.3"
def items(self):
"""
返回所有发表过文章的用户作者
使用 set 去重确保每个用户只出现一次
"""
return list(set(map(lambda x: x.author, Article.objects.all())))
def lastmod(self, obj):
"""
返回用户的注册时间
这里使用用户注册时间作为最后修改时间
实际可以根据用户最后活动时间优化
"""
return obj.date_joined

@ -0,0 +1,283 @@
import logging
from django.utils.translation import gettext_lazy as _
from django.conf import settings
from django.contrib import auth
from django.contrib.auth import REDIRECT_FIELD_NAME
from django.contrib.auth import get_user_model
from django.contrib.auth import logout
from django.contrib.auth.forms import AuthenticationForm
from django.contrib.auth.hashers import make_password
from django.http import HttpResponseRedirect, HttpResponseForbidden
from django.http.request import HttpRequest
from django.http.response import HttpResponse
from django.shortcuts import get_object_or_404
from django.shortcuts import render
from django.urls import reverse
from django.utils.decorators import method_decorator
from django.utils.http import url_has_allowed_host_and_scheme
from django.views import View
from django.views.decorators.cache import never_cache
from django.views.decorators.csrf import csrf_protect
from django.views.decorators.debug import sensitive_post_parameters
from django.views.generic import FormView, RedirectView
from djangoblog.utils import send_email, get_sha256, get_current_site, generate_code, delete_sidebar_cache
from . import utils
from .forms import RegisterForm, LoginForm, ForgetPasswordForm, ForgetPasswordCodeForm
from .models import BlogUser
logger = logging.getLogger(__name__)
class RegisterView(FormView):
"""
用户注册视图
处理用户注册流程包括表单验证用户创建和发送验证邮件
"""
form_class = RegisterForm
template_name = 'account/registration_form.html'
@method_decorator(csrf_protect)
def dispatch(self, *args, **kwargs):
"""确保视图受到CSRF保护"""
return super(RegisterView, self).dispatch(*args, **kwargs)
def form_valid(self, form):
"""
处理有效的注册表单
创建非活跃用户发送邮箱验证邮件
"""
if form.is_valid():
# 创建用户但不立即保存到数据库
user = form.save(False)
user.is_active = False # 邮箱验证前用户不可用
user.source = 'Register' # 标记用户来源
user.save(True) # 保存用户到数据库
# 获取当前站点信息
site = get_current_site().domain
# 生成验证签名,用于验证链接的安全性
sign = get_sha256(get_sha256(settings.SECRET_KEY + str(user.id)))
# 调试模式下使用本地地址
if settings.DEBUG:
site = '127.0.0.1:8000'
# 构建验证URL
path = reverse('account:result')
url = "http://{site}{path}?type=validation&id={id}&sign={sign}".format(
site=site, path=path, id=user.id, sign=sign)
# 构建邮件内容
content = """
<p>请点击下面链接验证您的邮箱</p>
<a href="{url}" rel="bookmark">{url}</a>
再次感谢您
<br />
如果上面链接无法打开请将此链接复制至浏览器
{url}
""".format(url=url)
# 发送验证邮件
send_email(
emailto=[
user.email,
],
title='验证您的电子邮箱',
content=content)
# 重定向到结果页面
url = reverse('accounts:result') + \
'?type=register&id=' + str(user.id)
return HttpResponseRedirect(url)
else:
# 表单无效,重新渲染表单页面
return self.render_to_response({
'form': form
})
class LogoutView(RedirectView):
"""
用户登出视图
处理用户登出操作并清理相关缓存
"""
url = '/login/' # 登出后重定向的URL
@method_decorator(never_cache)
def dispatch(self, request, *args, **kwargs):
"""确保登出页面不被缓存"""
return super(LogoutView, self).dispatch(request, *args, **kwargs)
def get(self, request, *args, **kwargs):
"""处理GET请求的登出操作"""
logout(request) # 执行登出操作
delete_sidebar_cache() # 清理侧边栏缓存
return super(LogoutView, self).get(request, *args, **kwargs)
class LoginView(FormView):
"""
用户登录视图
处理用户认证和登录会话管理
"""
form_class = LoginForm
template_name = 'account/login.html'
success_url = '/' # 登录成功后默认重定向的URL
redirect_field_name = REDIRECT_FIELD_NAME # 重定向字段名
login_ttl = 2626560 # 一个月的时间(秒),用于"记住我"功能
@method_decorator(sensitive_post_parameters('password')) # 保护密码参数
@method_decorator(csrf_protect) # CSRF保护
@method_decorator(never_cache) # 禁止缓存
def dispatch(self, request, *args, **kwargs):
"""应用装饰器到视图分发方法"""
return super(LoginView, self).dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs):
"""向模板上下文添加重定向URL"""
redirect_to = self.request.GET.get(self.redirect_field_name)
if redirect_to is None:
redirect_to = '/' # 默认重定向到首页
kwargs['redirect_to'] = redirect_to
return super(LoginView, self).get_context_data(**kwargs)
def form_valid(self, form):
"""处理有效的登录表单"""
# 使用Django的AuthenticationForm进行认证
form = AuthenticationForm(data=self.request.POST, request=self.request)
if form.is_valid():
# 认证成功,清理缓存并记录日志
delete_sidebar_cache()
logger.info(self.redirect_field_name)
# 登录用户
auth.login(self.request, form.get_user())
# 处理"记住我"功能
if self.request.POST.get("remember"):
self.request.session.set_expiry(self.login_ttl)
return super(LoginView, self).form_valid(form)
else:
# 认证失败,重新显示表单
return self.render_to_response({
'form': form
})
def get_success_url(self):
"""获取登录成功后重定向的URL"""
redirect_to = self.request.POST.get(self.redirect_field_name)
# 验证重定向URL的安全性
if not url_has_allowed_host_and_scheme(
url=redirect_to, allowed_hosts=[
self.request.get_host()]):
redirect_to = self.success_url # 不安全的URL使用默认URL
return redirect_to
def account_result(request):
"""
账户操作结果页面
处理注册结果和邮箱验证
"""
type = request.GET.get('type') # 操作类型register或validation
id = request.GET.get('id') # 用户ID
# 获取用户对象如果不存在返回404
user = get_object_or_404(get_user_model(), id=id)
logger.info(type)
# 如果用户已激活,直接重定向到首页
if user.is_active:
return HttpResponseRedirect('/')
# 处理注册和验证操作
if type and type in ['register', 'validation']:
if type == 'register':
# 注册成功页面
content = '''
恭喜您注册成功一封验证邮件已经发送到您的邮箱请验证您的邮箱后登录本站
'''
title = '注册成功'
else:
# 邮箱验证处理
c_sign = get_sha256(get_sha256(settings.SECRET_KEY + str(user.id)))
sign = request.GET.get('sign')
# 验证签名安全性
if sign != c_sign:
return HttpResponseForbidden() # 签名不匹配,禁止访问
# 激活用户账户
user.is_active = True
user.save()
content = '''
恭喜您已经成功的完成邮箱验证您现在可以使用您的账号来登录本站
'''
title = '验证成功'
# 渲染结果页面
return render(request, 'account/result.html', {
'title': title,
'content': content
})
else:
# 无效的操作类型,重定向到首页
return HttpResponseRedirect('/')
class ForgetPasswordView(FormView):
"""
忘记密码视图
处理密码重置请求
"""
form_class = ForgetPasswordForm
template_name = 'account/forget_password.html'
def form_valid(self, form):
"""处理有效的密码重置表单"""
if form.is_valid():
# 根据邮箱查找用户
blog_user = BlogUser.objects.filter(email=form.cleaned_data.get("email")).get()
# 使用Django的密码哈希器设置新密码
blog_user.password = make_password(form.cleaned_data["new_password2"])
blog_user.save() # 保存新密码
# 重定向到登录页面
return HttpResponseRedirect('/login/')
else:
# 表单无效,重新显示表单
return self.render_to_response({'form': form})
class ForgetPasswordEmailCode(View):
"""
发送忘记密码验证码视图
处理密码重置验证码的发送
"""
def post(self, request: HttpRequest):
"""处理POST请求发送密码重置验证码"""
form = ForgetPasswordCodeForm(request.POST)
# 验证表单数据
if not form.is_valid():
return HttpResponse("错误的邮箱")
to_email = form.cleaned_data["email"]
# 生成并发送验证码
code = generate_code()
utils.send_verify_email(to_email, code) # 发送验证邮件
utils.set_code(to_email, code) # 存储验证码(通常在缓存中)
return HttpResponse("ok") # 返回成功响应
Loading…
Cancel
Save