From 297590818a7077a84e4f475052f3c31f193981cc Mon Sep 17 00:00:00 2001 From: nch Date: Mon, 20 Oct 2025 12:54:54 +0800 Subject: [PATCH 1/2] =?UTF-8?q?nch=E7=9A=84=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../blog/context_processors.py | 50 +----- .../DjangoBlog-master/comments/admin.py | 24 +-- .../DjangoBlog-master/comments/models.py | 42 +---- .../DjangoBlog-master/oauth/tests.py | 165 +++++++++++++++--- 4 files changed, 153 insertions(+), 128 deletions(-) diff --git a/src/DjangoBlog-master(1)/DjangoBlog-master/blog/context_processors.py b/src/DjangoBlog-master(1)/DjangoBlog-master/blog/context_processors.py index f970a70..cc2a5dc 100644 --- a/src/DjangoBlog-master(1)/DjangoBlog-master/blog/context_processors.py +++ b/src/DjangoBlog-master(1)/DjangoBlog-master/blog/context_processors.py @@ -1,88 +1,44 @@ -# 导入日志模块,用于记录系统运行时的信息和错误 import logging -# 导入Django的时间工具,用于获取当前时间 from django.utils import timezone -# 导入自定义工具:缓存工具和获取博客设置的方法 from djangoblog.utils import cache, get_blog_setting -# 导入当前应用的模型:分类和文章模型 from .models import Category, Article -# 创建日志记录器,用于记录当前模块的日志信息 logger = logging.getLogger(__name__) def seo_processor(requests): - """ - 自定义上下文处理器:用于在所有模板中全局共享SEO相关的配置和数据 - 上下文处理器会在每次请求时被调用,返回的字典会自动注入到所有模板中 - - Args: - requests: HttpRequest对象,包含当前请求的信息(如协议、主机等) - - Returns: - dict: 包含网站配置、导航数据等的字典,供模板全局使用 - """ - # 定义缓存键,用于标识当前处理器的缓存数据 key = 'seo_processor' - # 尝试从缓存中获取数据,减少数据库查询和计算开销 value = cache.get(key) - - # 如果缓存中存在数据,直接返回缓存内容 if value: return value else: - # 缓存未命中时,记录日志并重新计算数据 logger.info('set processor cache.') - # 获取博客的全局设置(从数据库或其他配置源) setting = get_blog_setting() - - # 构建需要返回给模板的数据集 value = { - # 网站名称(用于页面标题等) 'SITE_NAME': setting.site_name, - # 是否显示谷歌广告 'SHOW_GOOGLE_ADSENSE': setting.show_google_adsense, - # 谷歌广告代码 'GOOGLE_ADSENSE_CODES': setting.google_adsense_codes, - # 网站SEO描述(用于meta标签) 'SITE_SEO_DESCRIPTION': setting.site_seo_description, - # 网站描述(用于页面展示) 'SITE_DESCRIPTION': setting.site_description, - # 网站关键词(用于meta标签,提升SEO) 'SITE_KEYWORDS': setting.site_keywords, - # 网站基础URL(协议+域名,如https://example.com/) 'SITE_BASE_URL': requests.scheme + '://' + requests.get_host() + '/', - # 文章摘要长度(用于列表页显示) 'ARTICLE_SUB_LENGTH': setting.article_sub_length, - # 导航栏显示的分类列表(从数据库查询所有分类) 'nav_category_list': Category.objects.all(), - # 导航栏显示的页面列表(筛选类型为"页面"且状态为"已发布"的文章) 'nav_pages': Article.objects.filter( - type='p', # 'p'表示页面(page),区别于普通文章(article) - status='p'), # 'p'表示已发布(published) - # 是否开启网站评论功能 + type='p', + status='p'), 'OPEN_SITE_COMMENT': setting.open_site_comment, - # 网站备案号 'BEIAN_CODE': setting.beian_code, - # 网站统计代码(如百度统计、Google Analytics) 'ANALYTICS_CODE': setting.analytics_code, - # 公安备案号 "BEIAN_CODE_GONGAN": setting.gongan_beiancode, - # 是否显示公安备案号 "SHOW_GONGAN_CODE": setting.show_gongan_code, - # 当前年份(用于页脚版权信息等) "CURRENT_YEAR": timezone.now().year, - # 全局页头代码(如自定义CSS、JS) "GLOBAL_HEADER": setting.global_header, - # 全局页脚代码 "GLOBAL_FOOTER": setting.global_footer, - # 评论是否需要审核后才显示 "COMMENT_NEED_REVIEW": setting.comment_need_review, } - - # 将数据存入缓存,有效期为10小时(60秒*60分*10小时) - # 减少重复计算和数据库查询,提升性能 cache.set(key, value, 60 * 60 * 10) return value + diff --git a/src/DjangoBlog-master(1)/DjangoBlog-master/comments/admin.py b/src/DjangoBlog-master(1)/DjangoBlog-master/comments/admin.py index 481b21b..a814f3f 100644 --- a/src/DjangoBlog-master(1)/DjangoBlog-master/comments/admin.py +++ b/src/DjangoBlog-master(1)/DjangoBlog-master/comments/admin.py @@ -6,40 +6,29 @@ from django.utils.translation import gettext_lazy as _ def disable_commentstatus(modeladmin, request, queryset): queryset.update(is_enable=False) - # 批量禁用评论:将选中评论的is_enable字段设为False + def enable_commentstatus(modeladmin, request, queryset): queryset.update(is_enable=True) - # 批量启用评论:将选中评论的is_enable字段设为True + disable_commentstatus.short_description = _('Disable comments') enable_commentstatus.short_description = _('Enable comments') -# 设置动作在后台下拉菜单中的显示名称 + class CommentAdmin(admin.ModelAdmin): list_per_page = 20 - # 每页显示20条评论 - list_display = ( 'id', 'body', - 'link_to_userinfo', # 自定义方法显示用户信息链接 - 'link_to_article', # 自定义方法显示文章链接 + 'link_to_userinfo', + 'link_to_article', 'is_enable', 'creation_time') - # 列表页面显示的字段 - list_display_links = ('id', 'body', 'is_enable') - # 这些字段可以作为链接点击进入编辑页面 - list_filter = ('is_enable',) - # 右侧过滤器:按启用状态筛选 - exclude = ('creation_time', 'last_modify_time') - # 编辑页面中排除这些字段(自动生成的时间戳) - actions = [disable_commentstatus, enable_commentstatus] - # 注册可用的批量动作 def link_to_userinfo(self, obj): info = (obj.author._meta.app_label, obj.author._meta.model_name) @@ -47,15 +36,12 @@ class CommentAdmin(admin.ModelAdmin): return format_html( u'%s' % (link, obj.author.nickname if obj.author.nickname else obj.author.email)) - # 生成指向用户编辑页面的链接,显示昵称(如果没有则显示邮箱) def link_to_article(self, obj): info = (obj.article._meta.app_label, obj.article._meta.model_name) link = reverse('admin:%s_%s_change' % info, args=(obj.article.id,)) return format_html( u'%s' % (link, obj.article.title)) - # 生成指向文章编辑页面的链接,显示文章标题 link_to_userinfo.short_description = _('User') link_to_article.short_description = _('Article') - # 设置自定义方法在列表中的列标题 \ No newline at end of file diff --git a/src/DjangoBlog-master(1)/DjangoBlog-master/comments/models.py b/src/DjangoBlog-master(1)/DjangoBlog-master/comments/models.py index d7235ce..0d052b1 100644 --- a/src/DjangoBlog-master(1)/DjangoBlog-master/comments/models.py +++ b/src/DjangoBlog-master(1)/DjangoBlog-master/comments/models.py @@ -9,63 +9,31 @@ from blog.models import Article # Create your models here. class Comment(models.Model): - """ - 评论模型类 - 用于存储博客文章的评论信息,支持多级回复功能 - """ - - # 评论正文,最大长度300字符,在管理界面显示为'正文' body = models.TextField('正文', max_length=300) - - # 评论创建时间,默认值为当前时间,使用Django的国际化支持 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', # 自关联,指向同一个模型 + 'self', verbose_name=_('parent comment'), - blank=True, # 在表单中允许为空 - null=True, # 在数据库中允许为NULL - on_delete=models.CASCADE) # 删除父评论时级联删除子评论 - - # 评论是否启用(审核通过),默认未启用,不允许为空 + blank=True, + null=True, + on_delete=models.CASCADE) is_enable = models.BooleanField(_('enable'), default=False, blank=False, null=False) class Meta: - """ - 模型的元数据配置 - """ - # 按ID降序排列,新的评论显示在前面 ordering = ['-id'] - - # 单数名称,在管理界面显示 verbose_name = _('comment') - - # 复数名称,与单数相同 verbose_name_plural = verbose_name - - # 指定获取最新记录时使用的字段 get_latest_by = 'id' def __str__(self): - """ - 对象的字符串表示方法 - 在Django管理界面和其他显示对象的地方使用 - """ - return self.body # 直接返回评论正文作为显示内容 \ No newline at end of file + return self.body \ No newline at end of file diff --git a/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/tests.py b/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/tests.py index bb23b9b..8198f84 100644 --- a/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/tests.py +++ b/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/tests.py @@ -13,43 +13,81 @@ from oauth.oauthmanager import BaseOauthManager # Create your tests here. class OAuthConfigTest(TestCase): + """ + OAuth配置基础测试类 + 测试OAuth登录流程的基本功能 + """ + def setUp(self): - self.client = Client() - self.factory = RequestFactory() + """ + 测试初始化方法,在每个测试方法执行前运行 + """ + self.client = Client() # Django测试客户端,用于模拟HTTP请求 + self.factory = RequestFactory() # 用于创建请求对象的工厂 def test_oauth_login_test(self): + """ + 测试OAuth登录流程 + 验证微博OAuth登录的跳转和授权流程 + """ + # 创建微博OAuth配置 c = OAuthConfig() c.type = 'weibo' c.appkey = 'appkey' c.appsecret = 'appsecret' c.save() + # 测试OAuth登录请求,应该重定向到微博授权页面 response = self.client.get('/oauth/oauthlogin?type=weibo') - self.assertEqual(response.status_code, 302) - self.assertTrue("api.weibo.com" in response.url) + self.assertEqual(response.status_code, 302) # 验证重定向状态码 + self.assertTrue("api.weibo.com" in response.url) # 验证跳转到微博授权页面 + # 测试授权回调处理,应该重定向到首页 response = self.client.get('/oauth/authorize?type=weibo&code=code') - self.assertEqual(response.status_code, 302) - self.assertEqual(response.url, '/') + self.assertEqual(response.status_code, 302) # 验证重定向状态码 + self.assertEqual(response.url, '/') # 验证跳转到首页 class OauthLoginTest(TestCase): + """ + OAuth登录详细测试类 + 测试各种OAuth服务提供商的登录流程 + """ + def setUp(self) -> None: - self.client = Client() - self.factory = RequestFactory() - self.apps = self.init_apps() + """ + 测试初始化方法 + """ + self.client = Client() # Django测试客户端 + self.factory = RequestFactory() # 请求工厂 + self.apps = self.init_apps() # 初始化所有OAuth应用配置 def init_apps(self): + """ + 初始化所有支持的OAuth应用配置 + 为每种OAuth服务创建测试配置 + """ + # 获取所有OAuth管理器的子类实例 applications = [p() for p in BaseOauthManager.__subclasses__()] for application in applications: + # 为每个OAuth服务创建配置 c = OAuthConfig() - c.type = application.ICON_NAME.lower() - c.appkey = 'appkey' - c.appsecret = 'appsecret' + c.type = application.ICON_NAME.lower() # 服务类型(小写) + c.appkey = 'appkey' # 测试用的AppKey + c.appsecret = 'appsecret' # 测试用的AppSecret c.save() return applications def get_app_by_type(self, type): + """ + 根据类型获取对应的OAuth应用实例 + + Args: + type: OAuth服务类型 + + Returns: + 对应的OAuth管理器实例 + """ for app in self.apps: if app.ICON_NAME.lower() == type: return app @@ -57,73 +95,117 @@ class OauthLoginTest(TestCase): @patch("oauth.oauthmanager.WBOauthManager.do_post") @patch("oauth.oauthmanager.WBOauthManager.do_get") def test_weibo_login(self, mock_do_get, mock_do_post): + """ + 测试微博OAuth登录流程 + 使用mock模拟API调用 + """ weibo_app = self.get_app_by_type('weibo') - assert weibo_app + assert weibo_app # 确保获取到微博应用实例 + + # 获取授权URL url = weibo_app.get_authorization_url() + + # 设置mock返回值 - 获取access token mock_do_post.return_value = json.dumps({"access_token": "access_token", "uid": "uid" }) + # 设置mock返回值 - 获取用户信息 mock_do_get.return_value = json.dumps({ "avatar_large": "avatar_large", "screen_name": "screen_name", "id": "id", "email": "email", }) + + # 执行获取access token的操作 userinfo = weibo_app.get_access_token_by_code('code') + + # 验证返回的用户信息 self.assertEqual(userinfo.token, 'access_token') self.assertEqual(userinfo.openid, 'id') @patch("oauth.oauthmanager.GoogleOauthManager.do_post") @patch("oauth.oauthmanager.GoogleOauthManager.do_get") def test_google_login(self, mock_do_get, mock_do_post): + """ + 测试Google OAuth登录流程 + """ google_app = self.get_app_by_type('google') assert google_app + url = google_app.get_authorization_url() + + # 模拟Google OAuth的token响应 mock_do_post.return_value = json.dumps({ "access_token": "access_token", "id_token": "id_token", }) + + # 模拟Google用户信息响应 mock_do_get.return_value = json.dumps({ "picture": "picture", "name": "name", - "sub": "sub", + "sub": "sub", # Google的用户ID字段 "email": "email", }) + token = google_app.get_access_token_by_code('code') userinfo = google_app.get_oauth_userinfo() + + # 验证用户信息 self.assertEqual(userinfo.token, 'access_token') - self.assertEqual(userinfo.openid, 'sub') + self.assertEqual(userinfo.openid, 'sub') # Google使用sub作为用户ID @patch("oauth.oauthmanager.GitHubOauthManager.do_post") @patch("oauth.oauthmanager.GitHubOauthManager.do_get") def test_github_login(self, mock_do_get, mock_do_post): + """ + 测试GitHub OAuth登录流程 + """ github_app = self.get_app_by_type('github') assert github_app + url = github_app.get_authorization_url() + # 验证GitHub授权URL包含必要信息 self.assertTrue("github.com" in url) self.assertTrue("client_id" in url) + + # 模拟GitHub的token响应(字符串格式) mock_do_post.return_value = "access_token=gho_16C7e42F292c6912E7710c838347Ae178B4a&scope=repo%2Cgist&token_type=bearer" + + # 模拟GitHub用户信息响应 mock_do_get.return_value = json.dumps({ "avatar_url": "avatar_url", "name": "name", "id": "id", "email": "email", }) + token = github_app.get_access_token_by_code('code') userinfo = github_app.get_oauth_userinfo() + + # 验证用户信息 self.assertEqual(userinfo.token, 'gho_16C7e42F292c6912E7710c838347Ae178B4a') self.assertEqual(userinfo.openid, 'id') @patch("oauth.oauthmanager.FaceBookOauthManager.do_post") @patch("oauth.oauthmanager.FaceBookOauthManager.do_get") def test_facebook_login(self, mock_do_get, mock_do_post): + """ + 测试Facebook OAuth登录流程 + """ facebook_app = self.get_app_by_type('facebook') assert facebook_app + url = facebook_app.get_authorization_url() - self.assertTrue("facebook.com" in url) + self.assertTrue("facebook.com" in url) # 验证Facebook授权URL + + # 模拟Facebook token响应 mock_do_post.return_value = json.dumps({ "access_token": "access_token", }) + + # 模拟Facebook用户信息响应(嵌套结构) mock_do_get.return_value = json.dumps({ "name": "name", "id": "id", @@ -134,14 +216,16 @@ class OauthLoginTest(TestCase): } } }) + token = facebook_app.get_access_token_by_code('code') userinfo = facebook_app.get_oauth_userinfo() + self.assertEqual(userinfo.token, 'access_token') @patch("oauth.oauthmanager.QQOauthManager.do_get", side_effect=[ - 'access_token=access_token&expires_in=3600', - 'callback({"client_id":"appid","openid":"openid"} );', - json.dumps({ + 'access_token=access_token&expires_in=3600', # 第一次调用:获取token + 'callback({"client_id":"appid","openid":"openid"} );', # 第二次调用:获取openid + json.dumps({ # 第三次调用:获取用户信息 "nickname": "nickname", "email": "email", "figureurl": "figureurl", @@ -149,21 +233,33 @@ class OauthLoginTest(TestCase): }) ]) def test_qq_login(self, mock_do_get): + """ + 测试QQ OAuth登录流程 + 使用side_effect模拟多次不同的API响应 + """ qq_app = self.get_app_by_type('qq') assert qq_app + url = qq_app.get_authorization_url() - self.assertTrue("qq.com" in url) + self.assertTrue("qq.com" in url) # 验证QQ授权URL + token = qq_app.get_access_token_by_code('code') userinfo = qq_app.get_oauth_userinfo() + self.assertEqual(userinfo.token, 'access_token') @patch("oauth.oauthmanager.WBOauthManager.do_post") @patch("oauth.oauthmanager.WBOauthManager.do_get") def test_weibo_authoriz_login_with_email(self, mock_do_get, mock_do_post): - + """ + 测试包含邮箱的微博授权登录完整流程 + 验证用户认证和会话管理 + """ + # 模拟获取access token mock_do_post.return_value = json.dumps({"access_token": "access_token", "uid": "uid" }) + # 模拟用户信息(包含邮箱) mock_user_info = { "avatar_large": "avatar_large", "screen_name": "screen_name1", @@ -172,25 +268,31 @@ class OauthLoginTest(TestCase): } mock_do_get.return_value = json.dumps(mock_user_info) + # 测试登录跳转 response = self.client.get('/oauth/oauthlogin?type=weibo') self.assertEqual(response.status_code, 302) self.assertTrue("api.weibo.com" in response.url) + # 测试授权回调 response = self.client.get('/oauth/authorize?type=weibo&code=code') self.assertEqual(response.status_code, 302) self.assertEqual(response.url, '/') + # 验证用户认证状态 user = auth.get_user(self.client) assert user.is_authenticated self.assertTrue(user.is_authenticated) self.assertEqual(user.username, mock_user_info['screen_name']) self.assertEqual(user.email, mock_user_info['email']) + + # 登出后再次测试 self.client.logout() response = self.client.get('/oauth/authorize?type=weibo&code=code') self.assertEqual(response.status_code, 302) self.assertEqual(response.url, '/') + # 再次验证用户认证状态 user = auth.get_user(self.client) assert user.is_authenticated self.assertTrue(user.is_authenticated) @@ -200,10 +302,15 @@ class OauthLoginTest(TestCase): @patch("oauth.oauthmanager.WBOauthManager.do_post") @patch("oauth.oauthmanager.WBOauthManager.do_get") def test_weibo_authoriz_login_without_email(self, mock_do_get, mock_do_post): - + """ + 测试不包含邮箱的微博授权登录流程 + 验证邮箱补充流程 + """ + # 模拟获取access token mock_do_post.return_value = json.dumps({"access_token": "access_token", "uid": "uid" }) + # 模拟用户信息(不包含邮箱) mock_user_info = { "avatar_large": "avatar_large", "screen_name": "screen_name1", @@ -211,28 +318,34 @@ class OauthLoginTest(TestCase): } mock_do_get.return_value = json.dumps(mock_user_info) + # 测试登录跳转 response = self.client.get('/oauth/oauthlogin?type=weibo') self.assertEqual(response.status_code, 302) self.assertTrue("api.weibo.com" in response.url) + # 测试授权回调 - 应该重定向到邮箱补充页面 response = self.client.get('/oauth/authorize?type=weibo&code=code') - self.assertEqual(response.status_code, 302) + # 解析OAuth用户ID oauth_user_id = int(response.url.split('/')[-1].split('.')[0]) self.assertEqual(response.url, f'/oauth/requireemail/{oauth_user_id}.html') + # 提交邮箱信息 response = self.client.post(response.url, {'email': 'test@gmail.com', 'oauthid': oauth_user_id}) - self.assertEqual(response.status_code, 302) + + # 生成邮箱验证签名 sign = get_sha256(settings.SECRET_KEY + str(oauth_user_id) + settings.SECRET_KEY) + # 验证绑定成功URL url = reverse('oauth:bindsuccess', kwargs={ 'oauthid': oauth_user_id, }) self.assertEqual(response.url, f'{url}?type=email') + # 验证邮箱确认流程 path = reverse('oauth:email_confirm', kwargs={ 'id': oauth_user_id, 'sign': sign @@ -240,10 +353,12 @@ class OauthLoginTest(TestCase): response = self.client.get(path) self.assertEqual(response.status_code, 302) self.assertEqual(response.url, f'/oauth/bindsuccess/{oauth_user_id}.html?type=success') + + # 验证最终用户状态 user = auth.get_user(self.client) from oauth.models import OAuthUser oauth_user = OAuthUser.objects.get(author=user) self.assertTrue(user.is_authenticated) self.assertEqual(user.username, mock_user_info['screen_name']) self.assertEqual(user.email, 'test@gmail.com') - self.assertEqual(oauth_user.pk, oauth_user_id) + self.assertEqual(oauth_user.pk, oauth_user_id) \ No newline at end of file -- 2.34.1 From 9b8e0064d833d2f4aef928155a58ad47569aba29 Mon Sep 17 00:00:00 2001 From: nch Date: Mon, 20 Oct 2025 12:57:43 +0800 Subject: [PATCH 2/2] =?UTF-8?q?nch=E7=9A=84=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/DjangoBlog-master(1)/DjangoBlog-master/oauth/admin.py | 2 +- src/DjangoBlog-master(1)/DjangoBlog-master/oauth/apps.py | 2 +- src/DjangoBlog-master(1)/DjangoBlog-master/oauth/forms.py | 2 +- src/DjangoBlog-master(1)/DjangoBlog-master/oauth/models.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/admin.py b/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/admin.py index 9ec5080..d3ffcd6 100644 --- a/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/admin.py +++ b/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/admin.py @@ -37,7 +37,7 @@ class OAuthUserAdmin(admin.ModelAdmin): # 右侧筛选器配置 list_filter = ('author', 'type',) - # 只读字段列表(初始为空) + # 只读字段列表,开始为空 readonly_fields = [] def get_readonly_fields(self, request, obj=None): diff --git a/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/apps.py b/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/apps.py index 12d7409..42788ab 100644 --- a/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/apps.py +++ b/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/apps.py @@ -11,5 +11,5 @@ class OauthConfig(AppConfig): """ # 指定应用的Python路径,Django使用这个名称来识别应用 - # 这应该与应用目录的名称保持一致 + # 这应该与应用目录的名称保持相同 name = 'oauth' \ No newline at end of file diff --git a/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/forms.py b/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/forms.py index b7c9bf4..0db6327 100644 --- a/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/forms.py +++ b/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/forms.py @@ -9,7 +9,7 @@ class RequireEmailForm(forms.Form): 通常在第三方OAuth服务没有返回邮箱信息时使用 """ - # 邮箱字段,标签显示为'电子邮箱',必填字段 + # 邮箱字段,标签显示为'电子邮箱' email = forms.EmailField(label='电子邮箱', required=True) # OAuth用户ID隐藏字段,用于关联OAuth用户记录 diff --git a/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/models.py b/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/models.py index f9fe8be..b4b570d 100644 --- a/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/models.py +++ b/src/DjangoBlog-master(1)/DjangoBlog-master/oauth/models.py @@ -12,7 +12,7 @@ class OAuthUser(models.Model): 用于存储通过第三方OAuth服务登录的用户信息 """ - # 关联到系统的本地用户,允许为空(初次OAuth登录时可能还未关联) + # 关联到系统的本地用户,允许为空 author = models.ForeignKey( settings.AUTH_USER_MODEL, verbose_name=_('author'), -- 2.34.1