merge develop &account加注释2&生成模型字段表

pull/9/head
lunhun 4 months ago
parent 8dd82320ff
commit e1d0e5ee1a

@ -1,23 +1,34 @@
from django import forms
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import UserChangeForm
from django.contrib.auth.forms import UsernameField
from django.contrib.auth.forms import UserChangeForm, UsernameField
from django.utils.translation import gettext_lazy as _
# Register your models here.
# 引入自定义用户模型
from .models import BlogUser
class BlogUserCreationForm(forms.ModelForm):
password1 = forms.CharField(label=_('password'), widget=forms.PasswordInput)
password2 = forms.CharField(label=_('Enter password again'), widget=forms.PasswordInput)
"""
后台创建用户表单
提供两个密码输入框确保管理员在后台创建用户时输入的密码一致
"""
password1 = forms.CharField(
label=_('password'), # 字段显示名,可翻译
widget=forms.PasswordInput # 密码输入框,输入时隐藏内容
)
password2 = forms.CharField(
label=_('Enter password again'), # 再次输入密码
widget=forms.PasswordInput
)
class Meta:
model = BlogUser
fields = ('email',)
fields = ('email',) # 后台创建用户表单只要求输入 email
def clean_password2(self):
# Check that the two password entries match
"""
验证两次输入的密码是否一致
"""
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
@ -25,28 +36,41 @@ class BlogUserCreationForm(forms.ModelForm):
return password2
def save(self, commit=True):
# Save the provided password in hashed format
"""
保存用户并将密码以哈希形式存储
"""
user = super().save(commit=False)
user.set_password(self.cleaned_data["password1"])
user.set_password(self.cleaned_data["password1"]) # 设置哈希密码
if commit:
user.source = 'adminsite'
user.source = 'adminsite' # 标记用户来源为后台
user.save()
return user
class BlogUserChangeForm(UserChangeForm):
"""
后台修改用户表单继承 Django 自带 UserChangeForm
"""
class Meta:
model = BlogUser
fields = '__all__'
field_classes = {'username': UsernameField}
fields = '__all__' # 显示模型的所有字段
field_classes = {'username': UsernameField} # 指定 username 字段类型
def __init__(self, *args, **kwargs):
"""
可以在此处扩展初始化逻辑目前直接调用父类初始化
"""
super().__init__(*args, **kwargs)
class BlogUserAdmin(UserAdmin):
form = BlogUserChangeForm
add_form = BlogUserCreationForm
"""
自定义后台管理 BlogUser 的显示和表单配置
"""
form = BlogUserChangeForm # 修改用户时使用的表单
add_form = BlogUserCreationForm # 创建用户时使用的表单
# 在列表页显示的字段
list_display = (
'id',
'nickname',
@ -54,6 +78,7 @@ class BlogUserAdmin(UserAdmin):
'email',
'last_login',
'date_joined',
'source')
list_display_links = ('id', 'username')
ordering = ('-id',)
'source'
)
list_display_links = ('id', 'username') # 哪些字段可以点击进入编辑页面
ordering = ('-id',) # 默认按 ID 降序排列

@ -9,27 +9,64 @@ from djangoblog.utils import get_current_site
# Create your models here.
class BlogUser(AbstractUser):
nickname = models.CharField(_('nick name'), max_length=100, blank=True)
creation_time = models.DateTimeField(_('creation time'), default=now)
last_modify_time = models.DateTimeField(_('last modify time'), default=now)
source = models.CharField(_('create source'), max_length=100, blank=True)
"""
博客用户模型继承 Django AbstractUser
添加了博客系统需要的额外字段如昵称创建时间修改时间和来源
"""
nickname = models.CharField(
_('nick name'), # 字段在 admin 或表单中的显示名称(可翻译)
max_length=100, # 昵称最大长度为 100
blank=True # 可以为空
)
creation_time = models.DateTimeField(
_('creation time'), # 创建时间字段
default=now # 默认值为当前时间
)
last_modify_time = models.DateTimeField(
_('last modify time'), # 最近修改时间
default=now
)
source = models.CharField(
_('create source'), # 用户来源字段,例如“注册、后台添加等”
max_length=100,
blank=True
)
def get_absolute_url(self):
"""
返回用户详情页的 URL用于在模板或视图中直接获取用户个人主页链接
这里使用 username 作为参数
"""
return reverse(
'blog:author_detail', kwargs={
'author_name': self.username})
'author_name': self.username
}
)
def __str__(self):
"""
返回对象的字符串表示这里使用 email方便在 admin 或调试时查看
"""
return self.email
def get_full_url(self):
site = get_current_site().domain
url = "https://{site}{path}".format(site=site,
path=self.get_absolute_url())
"""
返回带域名的完整用户详情页 URL
例如https://example.com/blog/author/username
"""
site = get_current_site().domain # 获取当前站点域名
url = "https://{site}{path}".format(
site=site,
path=self.get_absolute_url()
)
return url
class Meta:
ordering = ['-id']
verbose_name = _('user')
verbose_name_plural = verbose_name
get_latest_by = 'id'
ordering = ['-id'] # 默认按 ID 降序排列
verbose_name = _('user') # 在 admin 中显示的名称
verbose_name_plural = verbose_name # 复数形式
get_latest_by = 'id' # get_latest 方法默认按 ID 获取最新对象

@ -12,37 +12,59 @@ from . import utils
# Create your tests here.
class AccountTest(TestCase):
"""
针对账户注册登录密码找回邮箱验证等功能的测试类
使用 Django TestCase 提供的测试客户端和工厂方法进行测试
"""
def setUp(self):
self.client = Client()
self.factory = RequestFactory()
"""
初始化测试所需的对象
每个测试方法运行前都会执行
"""
self.client = Client() # Django 测试客户端,用于模拟请求
self.factory = RequestFactory() # 用于构造请求对象
# 创建一个普通测试用户
self.blog_user = BlogUser.objects.create_user(
username="test",
email="admin@admin.com",
password="12345678"
)
self.new_test = "xxx123--="
self.new_test = "xxx123--=" # 用于密码重置测试的新密码
def test_validate_account(self):
site = get_current_site().domain
"""
测试账户验证登录以及文章管理功能
"""
site = get_current_site().domain # 获取当前站点域名
# 创建超级管理员账户
user = BlogUser.objects.create_superuser(
email="liangliangyy1@gmail.com",
username="liangliangyy1",
password="qwer!@#$ggg")
password="qwer!@#$ggg"
)
testuser = BlogUser.objects.get(username='liangliangyy1')
# 测试登录功能
loginresult = self.client.login(
username='liangliangyy1',
password='qwer!@#$ggg')
self.assertEqual(loginresult, True)
password='qwer!@#$ggg'
)
self.assertEqual(loginresult, True) # 登录应成功
# 测试访问 Django admin
response = self.client.get('/admin/')
self.assertEqual(response.status_code, 200)
# 创建一个文章分类
category = Category()
category.name = "categoryaaa"
category.creation_time = timezone.now()
category.last_modify_time = timezone.now()
category.save()
# 创建一篇文章
article = Article()
article.title = "nicetitleaaa"
article.body = "nicecontentaaa"
@ -52,38 +74,52 @@ class AccountTest(TestCase):
article.status = 'p'
article.save()
# 测试访问文章的后台管理页面
response = self.client.get(article.get_admin_url())
self.assertEqual(response.status_code, 200)
def test_validate_register(self):
"""
测试用户注册激活登录及文章管理流程
"""
# 验证注册前用户不存在
self.assertEquals(
0, len(
BlogUser.objects.filter(
email='user123@user.com')))
0, len(BlogUser.objects.filter(email='user123@user.com'))
)
# 通过客户端 POST 请求模拟用户注册
response = self.client.post(reverse('account:register'), {
'username': 'user1233',
'email': 'user123@user.com',
'password1': 'password123!q@wE#R$T',
'password2': 'password123!q@wE#R$T',
})
# 验证注册后用户已创建
self.assertEquals(
1, len(
BlogUser.objects.filter(
email='user123@user.com')))
1, len(BlogUser.objects.filter(email='user123@user.com'))
)
user = BlogUser.objects.filter(email='user123@user.com')[0]
# 生成邮箱验证签名
sign = get_sha256(get_sha256(settings.SECRET_KEY + str(user.id)))
path = reverse('accounts:result')
url = '{path}?type=validation&id={id}&sign={sign}'.format(
path=path, id=user.id, sign=sign)
path=path, id=user.id, sign=sign
)
# 测试访问邮箱验证链接
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
# 登录用户
self.client.login(username='user1233', password='password123!q@wE#R$T')
user = BlogUser.objects.filter(email='user123@user.com')[0]
user.is_superuser = True
user.is_staff = True
user.save()
delete_sidebar_cache()
delete_sidebar_cache() # 清理缓存,避免后台界面异常
# 创建分类与文章
category = Category()
category.name = "categoryaaa"
category.creation_time = timezone.now()
@ -95,20 +131,23 @@ class AccountTest(TestCase):
article.title = "nicetitle333"
article.body = "nicecontentttt"
article.author = user
article.type = 'a'
article.status = 'p'
article.save()
# 测试访问文章后台管理页面
response = self.client.get(article.get_admin_url())
self.assertEqual(response.status_code, 200)
# 测试注销
response = self.client.get(reverse('account:logout'))
self.assertIn(response.status_code, [301, 302, 200])
# 注销后访问后台页面可能重定向
response = self.client.get(article.get_admin_url())
self.assertIn(response.status_code, [301, 302, 200])
# 测试错误密码登录
response = self.client.post(reverse('account:login'), {
'username': 'user1233',
'password': 'password123'
@ -119,27 +158,37 @@ class AccountTest(TestCase):
self.assertIn(response.status_code, [301, 302, 200])
def test_verify_email_code(self):
"""
测试邮箱验证码生成发送与验证
"""
to_email = "admin@admin.com"
code = generate_code()
utils.set_code(to_email, code)
utils.send_verify_email(to_email, code)
code = generate_code() # 生成验证码
utils.set_code(to_email, code) # 设置验证码缓存
utils.send_verify_email(to_email, code) # 发送验证码邮件
# 验证正确邮箱与验证码
err = utils.verify("admin@admin.com", code)
self.assertEqual(err, None)
# 验证错误邮箱
err = utils.verify("admin@123.com", code)
self.assertEqual(type(err), str)
def test_forget_password_email_code_success(self):
"""
测试发送忘记密码验证码成功
"""
resp = self.client.post(
path=reverse("account:forget_password_code"),
data=dict(email="admin@admin.com")
)
self.assertEqual(resp.status_code, 200)
self.assertEqual(resp.content.decode("utf-8"), "ok")
def test_forget_password_email_code_fail(self):
"""
测试发送忘记密码验证码失败
"""
resp = self.client.post(
path=reverse("account:forget_password_code"),
data=dict()
@ -153,6 +202,9 @@ class AccountTest(TestCase):
self.assertEqual(resp.content.decode("utf-8"), "错误的邮箱")
def test_forget_password_email_success(self):
"""
测试通过邮箱验证码重置密码成功
"""
code = generate_code()
utils.set_code(self.blog_user.email, code)
data = dict(
@ -168,13 +220,14 @@ class AccountTest(TestCase):
self.assertEqual(resp.status_code, 302)
# 验证用户密码是否修改成功
blog_user = BlogUser.objects.filter(
email=self.blog_user.email,
).first() # type: BlogUser
blog_user = BlogUser.objects.filter(email=self.blog_user.email).first()
self.assertNotEqual(blog_user, None)
self.assertEqual(blog_user.check_password(data["new_password1"]), True)
def test_forget_password_email_not_user(self):
"""
测试不存在的用户尝试重置密码
"""
data = dict(
new_password1=self.new_test,
new_password2=self.new_test,
@ -185,23 +238,22 @@ class AccountTest(TestCase):
path=reverse("account:forget_password"),
data=data
)
self.assertEqual(resp.status_code, 200)
def test_forget_password_email_code_error(self):
"""
测试密码重置时使用错误验证码
"""
code = generate_code()
utils.set_code(self.blog_user.email, code)
data = dict(
new_password1=self.new_test,
new_password2=self.new_test,
email=self.blog_user.email,
code="111111",
code="111111", # 错误验证码
)
resp = self.client.post(
path=reverse("account:forget_password"),
data=data
)
self.assertEqual(resp.status_code, 200)

@ -111,7 +111,7 @@ DATABASES = {
'ENGINE': 'django.db.backends.mysql',
'NAME': os.environ.get('DJANGO_MYSQL_DATABASE') or 'djangoblog',
'USER': os.environ.get('DJANGO_MYSQL_USER') or 'root',
'PASSWORD': os.environ.get('DJANGO_MYSQL_PASSWORD') or '2315304109',
'PASSWORD': os.environ.get('DJANGO_MYSQL_PASSWORD') or '123456',
'HOST': os.environ.get('DJANGO_MYSQL_HOST') or '127.0.0.1',
'PORT': int(
os.environ.get('DJANGO_MYSQL_PORT') or 3306),

Binary file not shown.
Loading…
Cancel
Save