diff --git a/src/django-master/accounts/admin.py b/src/django-master/accounts/admin.py index 32e483c..d3889c0 100644 --- a/src/django-master/accounts/admin.py +++ b/src/django-master/accounts/admin.py @@ -1,59 +1,100 @@ -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.utils.translation import gettext_lazy as _ +#django核心组件导入 +from django import forms# Django 表单处理模块 +from django.contrib.auth.admin import UserAdmin # Django 默认用户管理后台类 +from django.contrib.auth.forms import UserChangeForm # 用户信息修改表单基类 +from django.contrib.auth.forms import UsernameField# 用户名专用表单字段 +from django.utils.translation import gettext_lazy as _ # 国际化翻译函数 +# 本地应用导入 # Register your models here. -from .models import BlogUser +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) + """ + 自定义用户创建表单(用于管理后台添加新用户) + 继承自 ModelForm专门处理 BlogUser 模型的创建 + """ + + # 定义密码输入字段(需要输入两次以确保一致) + password1 = forms.CharField(label=_('password'), # 字段标签(支持国际化) + widget=forms.PasswordInput) # 密码输入控件 + password2 = forms.CharField(label=_('Enter password again'), # 确认密码标签 + widget=forms.PasswordInput) # 密码输入控件 class Meta: - model = BlogUser - fields = ('email',) + model = BlogUser# 关联的模型类 + fields = ('email',)# 创建用户时显示的字段(这里只显示email字段) def clean_password2(self): + """ + 验证两次输入的密码是否一致 + Django 表单验证方法,方法名必须以 clean_ 开头 + """ # Check that the two password entries match - password1 = self.cleaned_data.get("password1") - password2 = self.cleaned_data.get("password2") + password1 = self.cleaned_data.get("password1")# 获取第一次输入的密码 + password2 = self.cleaned_data.get("password2")# 获取第二次输入的密码 + # 如果两次密码不一致,抛出验证错误 if password1 and password2 and password1 != password2: - raise forms.ValidationError(_("passwords do not match")) - return password2 + raise forms.ValidationError(_("passwords do not match"))# 错误信息(支持国际化) + 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 = super().save(commit=False) # 调用父类保存方法但不提交到数据库 + user.set_password(self.cleaned_data["password1"]) # 对密码进行哈希加密 if commit: - user.source = 'adminsite' - user.save() - return user + user.source = 'adminsite' # 设置用户来源标记(表示通过管理后台创建) + user.save()# 保存到数据库 + return user# 返回用户对象 class BlogUserChangeForm(UserChangeForm): + """ + 自定义用户信息修改表单(用于管理后台编辑用户) + 继承自 Django 自带的 UserChangeForm + """ + class Meta: - model = BlogUser - fields = '__all__' - field_classes = {'username': UsernameField} + model = BlogUser # 关联的模型类 + fields = '__all__'# 显示所有字段 + field_classes = {'username': UsernameField}# 指定用户名使用专用字段类型 def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - + """ + 表单初始化方法 + 可以在这里对表单字段进行自定义设置 + """ + super().__init__(*args, **kwargs) # 调用父类初始化方法 + # 可以在这里添加自定义逻辑,如修改字段属性等 class BlogUserAdmin(UserAdmin): - form = BlogUserChangeForm - add_form = BlogUserCreationForm + """ + 自定义用户管理后台配置 + 继承自 Django 自带的 UserAdmin + """ + + # 指定使用的表单类 + form = BlogUserChangeForm # 编辑用户时使用的表单 + add_form = BlogUserCreationForm# 添加用户时使用的表单 + + # 管理后台列表页显示配置 list_display = ( - 'id', - 'nickname', - 'username', - 'email', - 'last_login', - 'date_joined', - 'source') + 'id', # 用户ID + 'nickname', # 用户昵称 + 'username',# 用户名 + 'email', # 电子邮箱 + 'last_login', # 最后登录时间 + 'date_joined', # 注册时间 + 'source')# 用户来源标记 + + # 设置哪些字段可以点击跳转到编辑页 list_display_links = ('id', 'username') + + # 默认排序规则(按ID降序排列) ordering = ('-id',) + diff --git a/src/django-master/accounts/apps.py b/src/django-master/accounts/apps.py index 9b3fc5a..bf4ecc8 100644 --- a/src/django-master/accounts/apps.py +++ b/src/django-master/accounts/apps.py @@ -1,5 +1,11 @@ from django.apps import AppConfig - + class AccountsConfig(AppConfig): - name = 'accounts' + """ + Accounts 应用的配置类。 + 功能: + 1. 定义应用名称(供 Django 内部识别)。 + 2. 可在此处覆盖 ready() 方法以注册信号等。 + """ + name = 'accounts'# 必须与项目中的应用目录名完全一致 \ No newline at end of file diff --git a/src/django-master/accounts/forms.py b/src/django-master/accounts/forms.py index fce4137..a0b5769 100644 --- a/src/django-master/accounts/forms.py +++ b/src/django-master/accounts/forms.py @@ -7,7 +7,7 @@ from django.utils.translation import gettext_lazy as _ from . import utils from .models import BlogUser - +# 登录表单,继承自Django内置的AuthenticationForm class LoginForm(AuthenticationForm): def __init__(self, *args, **kwargs): super(LoginForm, self).__init__(*args, **kwargs) @@ -16,11 +16,11 @@ class LoginForm(AuthenticationForm): self.fields['password'].widget = widgets.PasswordInput( attrs={'placeholder': "password", "class": "form-control"}) - +# 注册表单,继承自Django内置的UserCreationForm class RegisterForm(UserCreationForm): def __init__(self, *args, **kwargs): super(RegisterForm, self).__init__(*args, **kwargs) - + # 自定义用户名、邮箱和密码字段的HTML属性 self.fields['username'].widget = widgets.TextInput( attrs={'placeholder': "username", "class": "form-control"}) self.fields['email'].widget = widgets.EmailInput( @@ -29,18 +29,18 @@ class RegisterForm(UserCreationForm): attrs={'placeholder': "password", "class": "form-control"}) self.fields['password2'].widget = widgets.PasswordInput( attrs={'placeholder': "repeat password", "class": "form-control"}) - + # 验证邮箱唯一性 def clean_email(self): email = self.cleaned_data['email'] if get_user_model().objects.filter(email=email).exists(): raise ValidationError(_("email already exists")) return email - + # 指定关联的用户模型和表单字段 class Meta: model = get_user_model() fields = ("username", "email") - +# 忘记密码表单(验证邮箱和验证码) class ForgetPasswordForm(forms.Form): new_password1 = forms.CharField( label=_("New password"), @@ -51,7 +51,7 @@ class ForgetPasswordForm(forms.Form): } ), ) - + # 新密码字段2(用于确认) new_password2 = forms.CharField( label="确认密码", widget=forms.PasswordInput( @@ -61,7 +61,7 @@ class ForgetPasswordForm(forms.Form): } ), ) - + # 邮箱字段 email = forms.EmailField( label='邮箱', widget=forms.TextInput( @@ -71,7 +71,7 @@ class ForgetPasswordForm(forms.Form): } ), ) - + # 验证码字段 code = forms.CharField( label=_('Code'), widget=forms.TextInput( @@ -81,16 +81,16 @@ class ForgetPasswordForm(forms.Form): } ), ) - + # 验证两次输入的密码是否一致,并检查密码强度 def clean_new_password2(self): password1 = self.data.get("new_password1") password2 = self.data.get("new_password2") if password1 and password2 and password1 != password2: raise ValidationError(_("passwords do not match")) - password_validation.validate_password(password2) + password_validation.validate_password(password2)# 使用Django的密码验证器 return password2 - + # 验证邮箱是否已注册 def clean_email(self): user_email = self.cleaned_data.get("email") if not BlogUser.objects.filter( @@ -99,10 +99,10 @@ class ForgetPasswordForm(forms.Form): # todo 这里的报错提示可以判断一个邮箱是不是注册过,如果不想暴露可以修改 raise ValidationError(_("email does not exist")) return user_email - + # 验证用户输入的验证码是否正确 def clean_code(self): code = self.cleaned_data.get("code") - error = utils.verify( + error = utils.verify(# 调用工具函数验证验证码 email=self.cleaned_data.get("email"), code=code, ) @@ -110,7 +110,7 @@ class ForgetPasswordForm(forms.Form): raise ValidationError(error) return code - +# 忘记密码功能中的验证码发送表单(仅需邮箱字段) class ForgetPasswordCodeForm(forms.Form): email = forms.EmailField( label=_('Email'), diff --git a/src/django-master/comments/models.py b/src/django-master/comments/models.py index 7c3bbc8..0ac8c4d 100644 --- a/src/django-master/comments/models.py +++ b/src/django-master/comments/models.py @@ -1,39 +1,39 @@ -from django.conf import settings +from django.contrib.auth.models import AbstractUser from django.db import models +from django.urls import reverse from django.utils.timezone import now from django.utils.translation import gettext_lazy as _ - -from blog.models import Article +from djangoblog.utils import get_current_site # Create your models here. - -class Comment(models.Model): - body = models.TextField('正文', max_length=300) +# 自定义用户模型,继承Django内置的AbstractUser +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) - author = models.ForeignKey( - settings.AUTH_USER_MODEL, - verbose_name=_('author'), - on_delete=models.CASCADE) - article = models.ForeignKey( - Article, - verbose_name=_('article'), - on_delete=models.CASCADE) - parent_comment = models.ForeignKey( - 'self', - verbose_name=_('parent comment'), - blank=True, - null=True, - on_delete=models.CASCADE) - is_enable = models.BooleanField(_('enable'), - default=False, blank=False, null=False) - - class Meta: - ordering = ['-id'] - verbose_name = _('comment') - verbose_name_plural = verbose_name - get_latest_by = 'id' - + # 账号创建来源(如:网站注册/第三方登录等,可选) + 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}) + # 定义对象的字符串表示(Admin后台和shell中显示) def __str__(self): - return self.body + return self.email + # 获取用户详情页的完整URL(包含域名,用于分享链接) + def get_full_url(self): + site = get_current_site().domain# 获取当前站点域名 + url = "https://{site}{path}".format(site=site, + path=self.get_absolute_url()) + return url + # 元数据配置(模型级别的选项) + class Meta: + ordering = ['-id'] # 默认按ID降序排列 + verbose_name = _('user') # 单数形式名称(后台显示) + verbose_name_plural = verbose_name# 复数形式名称(后台显示) + get_latest_by = 'id'# 指定最新记录的排序字段