account包下代码注释

cxy_branch
cxy 4 months ago
parent 574b9ce1f6
commit 07b27f00d6

3
.idea/.gitignore vendored

@ -0,0 +1,3 @@
# 默认忽略的文件
/shelf/
/workspace.xml

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PyDocumentationSettings">
<option name="format" value="PLAIN" />
<option name="myDocStringFormat" value="Plain" />
</component>
</module>

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Black">
<option name="sdkName" value="Python 3.12" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.12" project-jdk-type="Python SDK" />
</project>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/djangoBlogStudy.iml" filepath="$PROJECT_DIR$/.idea/djangoBlogStudy.iml" />
</modules>
</component>
</project>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

@ -7,33 +7,34 @@ 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',)
def clean_password2(self):
def clean_password2(self):# 密码验证方法 - 检查两次输入的密码是否一致
# Check that the two password entries match
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:
raise forms.ValidationError(_("passwords do not match"))
raise forms.ValidationError(_("passwords do not match"))# 密码一致性检查 - 如果两次输入不一致则抛出验证错误
return password2
def save(self, commit=True):
def save(self, commit=True):# 用户保存方法 - 处理密码哈希化和用户来源记录
# Save the provided password in hashed format
user = super().save(commit=False)
user.set_password(self.cleaned_data["password1"])
# 提交保存 - 设置用户来源为管理后台并保存到数据库
if commit:
user.source = 'adminsite'
user.save()
return user
# 用户修改表单 - 继承Django默认用户修改表单
class BlogUserChangeForm(UserChangeForm):
class Meta:
model = BlogUser
@ -43,7 +44,7 @@ class BlogUserChangeForm(UserChangeForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 用户管理类 - 自定义用户模型在Django后台的显示和管理方式
class BlogUserAdmin(UserAdmin):
form = BlogUserChangeForm
add_form = BlogUserCreationForm

@ -1,5 +1,5 @@
from django.apps import AppConfig
# 账户应用配置类
class AccountsConfig(AppConfig):
name = 'accounts'

@ -7,7 +7,7 @@ from django.utils.translation import gettext_lazy as _
from . import utils
from .models import BlogUser
# 用户登录表单 - 处理用户登录认证
class LoginForm(AuthenticationForm):
def __init__(self, *args, **kwargs):
super(LoginForm, self).__init__(*args, **kwargs)
@ -16,7 +16,7 @@ class LoginForm(AuthenticationForm):
self.fields['password'].widget = widgets.PasswordInput(
attrs={'placeholder': "password", "class": "form-control"})
# 用户注册表单 - 处理新用户注册流程
class RegisterForm(UserCreationForm):
def __init__(self, *args, **kwargs):
super(RegisterForm, self).__init__(*args, **kwargs)
@ -40,8 +40,9 @@ class RegisterForm(UserCreationForm):
model = get_user_model()
fields = ("username", "email")
# 密码重置表单 - 处理用户忘记密码时的重置流程
class ForgetPasswordForm(forms.Form):
# 新密码字段 - 用户设置的新密码
new_password1 = forms.CharField(
label=_("New password"),
widget=forms.PasswordInput(
@ -51,7 +52,7 @@ class ForgetPasswordForm(forms.Form):
}
),
)
# 确认密码字段 - 再次输入新密码用于验证
new_password2 = forms.CharField(
label="确认密码",
widget=forms.PasswordInput(
@ -61,7 +62,7 @@ class ForgetPasswordForm(forms.Form):
}
),
)
# 邮箱字段 - 用户注册时使用的邮箱地址
email = forms.EmailField(
label='邮箱',
widget=forms.TextInput(
@ -71,7 +72,7 @@ class ForgetPasswordForm(forms.Form):
}
),
)
# 验证码字段 - 邮箱接收的验证码
code = forms.CharField(
label=_('Code'),
widget=forms.TextInput(
@ -82,6 +83,7 @@ class ForgetPasswordForm(forms.Form):
),
)
# 密码确认验证 - 检查两次输入的密码是否一致
def clean_new_password2(self):
password1 = self.data.get("new_password1")
password2 = self.data.get("new_password2")
@ -91,6 +93,7 @@ class ForgetPasswordForm(forms.Form):
return password2
# 邮箱验证 - 检查邮箱是否在系统中注册
def clean_email(self):
user_email = self.cleaned_data.get("email")
if not BlogUser.objects.filter(
@ -100,6 +103,7 @@ class ForgetPasswordForm(forms.Form):
raise ValidationError(_("email does not exist"))
return user_email
# 验证码验证 - 检查邮箱验证码是否正确
def clean_code(self):
code = self.cleaned_data.get("code")
error = utils.verify(
@ -110,7 +114,7 @@ class ForgetPasswordForm(forms.Form):
raise ValidationError(error)
return code
# 验证码请求表单 - 用于请求发送密码重置验证码
class ForgetPasswordCodeForm(forms.Form):
email = forms.EmailField(
label=_('Email'),

@ -18,28 +18,28 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='BlogUser',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('password', models.CharField(max_length=128, verbose_name='password')),
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),# 主键字段,唯一标识用户
('password', models.CharField(max_length=128, verbose_name='password')),# 认证字段,用户密码哈希值
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),# 登录信息字段
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), # 权限字段(超级用户状态标识)
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),# 个人信息字段:用户姓氏
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),# 个人信息字段:用户名字
('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),# 联系字段 - 用户邮箱地址
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),# 权限字段 - 后台管理权限标识
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),# 状态字段 - 用户账户激活状态
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),# 时间字段 - 用户注册时间
('nickname', models.CharField(blank=True, max_length=100, verbose_name='昵称')),
('created_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='创建时间')),
('last_mod_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='修改时间')),
('source', models.CharField(blank=True, max_length=100, verbose_name='创建来源')),
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),# 权限关联字段 - 用户所属权限组
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')), # 权限关联字段 - 用户特定权限
],
options={
'verbose_name': '用户',
'verbose_name_plural': '用户',
'ordering': ['-id'],
'ordering': ['-id'],#按ID降序排列
'get_latest_by': 'id',
},
managers=[

@ -11,33 +11,40 @@ class Migration(migrations.Migration):
]
operations = [
# 模型选项调整 - 更新用户模型的元数据配置
migrations.AlterModelOptions(
name='bloguser',
options={'get_latest_by': 'id', 'ordering': ['-id'], 'verbose_name': 'user', 'verbose_name_plural': 'user'},
),
# 字段删除操作 - 移除旧的创建时间字段
migrations.RemoveField(
model_name='bloguser',
name='created_time',
),
# 字段删除操作 - 移除旧的最后修改时间字段
migrations.RemoveField(
model_name='bloguser',
name='last_mod_time',
),
# 字段添加操作 - 新增标准化的创建时间字段
migrations.AddField(
model_name='bloguser',
name='creation_time',
field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='creation time'),
),
# 字段添加操作 - 新增标准化的最后修改时间字段
migrations.AddField(
model_name='bloguser',
name='last_modify_time',
field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='last modify time'),
),
# 字段调整操作 - 更新昵称字段的显示名称
migrations.AlterField(
model_name='bloguser',
name='nickname',
field=models.CharField(blank=True, max_length=100, verbose_name='nick name'),
),
# 字段调整操作 - 更新来源字段的显示名称
migrations.AlterField(
model_name='bloguser',
name='source',

@ -7,21 +7,24 @@ from djangoblog.utils import get_current_site
# Create your models here.
# 博客用户模型类 - 继承Django抽象用户基类
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)
# URL方法 - 获取用户详情页的相对URL路径
def get_absolute_url(self):
return reverse(
'blog:author_detail', kwargs={
'author_name': self.username})
# 字符串表示 - 定义对象的字符串显示格式
def __str__(self):
return self.email
# 完整URL方法 - 生成包含域名的用户完整详情页URL
def get_full_url(self):
site = get_current_site().domain
url = "https://{site}{path}".format(site=site,

@ -10,7 +10,7 @@ from . import utils
# Create your tests here.
# 账户功能测试类 - 继承Django测试基类
class AccountTest(TestCase):
def setUp(self):
self.client = Client()
@ -22,6 +22,7 @@ class AccountTest(TestCase):
)
self.new_test = "xxx123--="
# 账户验证测试 - 测试超级用户登录和管理权限
def test_validate_account(self):
site = get_current_site().domain
user = BlogUser.objects.create_superuser(
@ -36,13 +37,13 @@ class AccountTest(TestCase):
self.assertEqual(loginresult, True)
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"
@ -55,6 +56,7 @@ class AccountTest(TestCase):
response = self.client.get(article.get_admin_url())
self.assertEqual(response.status_code, 200)
# 注册流程测试 - 测试用户完整注册流程
def test_validate_register(self):
self.assertEquals(
0, len(
@ -118,6 +120,7 @@ class AccountTest(TestCase):
response = self.client.get(article.get_admin_url())
self.assertIn(response.status_code, [301, 302, 200])
# 邮箱验证码测试 - 测试邮箱验证码的生成和验证
def test_verify_email_code(self):
to_email = "admin@admin.com"
code = generate_code()
@ -130,6 +133,7 @@ class AccountTest(TestCase):
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"),
@ -139,6 +143,7 @@ class AccountTest(TestCase):
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"),
@ -152,6 +157,7 @@ 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)
@ -174,6 +180,7 @@ class AccountTest(TestCase):
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,
@ -188,7 +195,7 @@ class AccountTest(TestCase):
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)

@ -5,24 +5,24 @@ from . import views
from .forms import LoginForm
app_name = "accounts"
urlpatterns = [re_path(r'^login/$',
# URL路由配置 - 定义URL路径与视图函数的映射关系
urlpatterns = [re_path(r'^login/$', # 用户登录路由 - 处理用户登录认证
views.LoginView.as_view(success_url='/'),
name='login',
kwargs={'authentication_form': LoginForm}),
re_path(r'^register/$',
re_path(r'^register/$', # 用户注册路由 - 处理新用户注册
views.RegisterView.as_view(success_url="/"),
name='register'),
re_path(r'^logout/$',
re_path(r'^logout/$',# 用户退出路由 - 处理用户登出操作
views.LogoutView.as_view(),
name='logout'),
path(r'account/result.html',
path(r'account/result.html',# 账户结果页面路由 - 显示操作结果信息(如验证结果)
views.account_result,
name='result'),
re_path(r'^forget_password/$',
re_path(r'^forget_password/$',# 密码重置路由 - 处理忘记密码重置请求
views.ForgetPasswordView.as_view(),
name='forget_password'),
re_path(r'^forget_password_code/$',
re_path(r'^forget_password_code/$',# 密码重置验证码路由 - 处理密码重置验证码发送
views.ForgetPasswordEmailCode.as_view(),
name='forget_password_code'),
]

@ -2,11 +2,13 @@ from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend
# 用户认证方法 - 验证用户凭据并返回用户对象
class EmailOrUsernameModelBackend(ModelBackend):
"""
允许使用用户名或邮箱登录
"""
# 用户认证方法 - 验证用户凭据并返回用户对象
def authenticate(self, request, username=None, password=None, **kwargs):
if '@' in username:
kwargs = {'email': username}
@ -19,6 +21,7 @@ class EmailOrUsernameModelBackend(ModelBackend):
except get_user_model().DoesNotExist:
return None
# 用户获取方法 - 根据用户ID获取用户对象
def get_user(self, username):
try:
return get_user_model().objects.get(pk=username)

@ -9,7 +9,7 @@ from djangoblog.utils import send_email
_code_ttl = timedelta(minutes=5)
# 验证邮件发送函数 - 向指定邮箱发送验证码邮件
def send_verify_email(to_mail: str, code: str, subject: str = _("Verify Email")):
"""发送重设密码验证码
Args:
@ -22,7 +22,7 @@ def send_verify_email(to_mail: str, code: str, subject: str = _("Verify Email"))
"properly") % {'code': code}
send_email([to_mail], subject, html_content)
# 验证码验证函数 - 检查用户输入的验证码是否正确
def verify(email: str, code: str) -> typing.Optional[str]:
"""验证code是否有效
Args:
@ -38,12 +38,12 @@ def verify(email: str, code: str) -> typing.Optional[str]:
if cache_code != code:
return gettext("Verification code error")
# 验证码存储函数 - 将验证码保存到缓存系统
def set_code(email: str, code: str):
"""设置code"""
cache.set(email, code, _code_ttl.seconds)
# 验证码获取函数 - 从缓存系统中获取验证码
def get_code(email: str) -> typing.Optional[str]:
"""获取code"""
return cache.get(email)

@ -30,30 +30,33 @@ logger = logging.getLogger(__name__)
# Create your views here.
# 用户注册视图 - 处理新用户注册流程
class RegisterView(FormView):
form_class = RegisterForm
template_name = 'account/registration_form.html'
# 请求分发 - 添加CSRF保护装饰器
@method_decorator(csrf_protect)
def dispatch(self, *args, **kwargs):
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'
path = reverse('account:result')
url = "http://{site}{path}?type=validation&id={id}&sign={sign}".format(
site=site, path=path, id=user.id, sign=sign)
# 邮件内容构建 - 创建验证邮件的HTML内容
content = """
<p>请点击下面链接验证您的邮箱</p>
@ -64,6 +67,7 @@ class RegisterView(FormView):
如果上面链接无法打开请将此链接复制至浏览器
{url}
""".format(url=url)
# 邮件发送 - 发送验证邮件到用户邮箱
send_email(
emailto=[
user.email,
@ -79,7 +83,7 @@ class RegisterView(FormView):
'form': form
})
# 用户退出视图 - 处理用户登出操作
class LogoutView(RedirectView):
url = '/login/'
@ -92,7 +96,7 @@ class LogoutView(RedirectView):
delete_sidebar_cache()
return super(LogoutView, self).get(request, *args, **kwargs)
# 用户登录视图 - 处理用户登录认证
class LoginView(FormView):
form_class = LoginForm
template_name = 'account/login.html'
@ -107,6 +111,7 @@ class LoginView(FormView):
return super(LoginView, self).dispatch(request, *args, **kwargs)
# 上下文数据 - 获取重定向目标并添加到上下文
def get_context_data(self, **kwargs):
redirect_to = self.request.GET.get(self.redirect_field_name)
if redirect_to is None:
@ -115,6 +120,7 @@ class LoginView(FormView):
return super(LoginView, self).get_context_data(**kwargs)
# 表单验证成功处理 - 执行用户登录操作
def form_valid(self, form):
form = AuthenticationForm(data=self.request.POST, request=self.request)
@ -132,6 +138,7 @@ class LoginView(FormView):
'form': form
})
# 成功URL获取 - 处理登录后的重定向逻辑
def get_success_url(self):
redirect_to = self.request.POST.get(self.redirect_field_name)
@ -141,7 +148,7 @@ class LoginView(FormView):
redirect_to = self.success_url
return redirect_to
# 账户结果页面视图 - 显示注册或验证结果
def account_result(request):
type = request.GET.get('type')
id = request.GET.get('id')
@ -174,7 +181,7 @@ def account_result(request):
else:
return HttpResponseRedirect('/')
# 密码重置视图 - 处理用户忘记密码重置
class ForgetPasswordView(FormView):
form_class = ForgetPasswordForm
template_name = 'account/forget_password.html'
@ -188,7 +195,7 @@ class ForgetPasswordView(FormView):
else:
return self.render_to_response({'form': form})
# 密码重置验证码发送视图 - 处理验证码邮件发送
class ForgetPasswordEmailCode(View):
def post(self, request: HttpRequest):

Loading…
Cancel
Save