Files
server/server/urls.py
T
ngfchl 777ca50328 update. 完成前端页面展示、列表和详情页
update. 调整融合主菜单与板块
update. 分离新闻模块
2026-04-01 14:17:03 +08:00

164 lines
6.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
URL configuration for server project.
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/6.0/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.conf.urls.static import static
from django.contrib import admin
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
from django.urls import path, include, re_path
import logging
import os
import pkgutil
import traceback
import importlib
import jwt
from django.contrib.auth.models import User
from django.http import JsonResponse
from jwt import exceptions
from ninja import NinjaAPI
from ninja.errors import ValidationError
from ninja.security import HttpBearer
from base.views import custom_upload_file
from common.common_response import CommonResponse
from .settings import SECRET_KEY
logger = logging.getLogger('ptools')
class GlobalAuth(HttpBearer):
def authenticate(self, request, token):
try:
logger.debug('用户认证中')
logger.debug(f'解析 Auth Token{token}')
res = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
user = User.objects.filter(id=res.get('id'), username=res.get('username')).first()
logger.debug(user)
if not user:
raise exceptions.PyJWKError('用户不存在')
request.user = user
return token
except exceptions.PyJWKError:
msg = 'Token 认证失败,请重新登陆!'
logger.error(msg)
raise
except exceptions.ExpiredSignatureError:
msg = '认证令牌已过期,请重新登陆!'
logger.error(msg)
raise
except Exception as e:
msg = '认证失败,请检查用户是否存在'
logger.error(msg)
raise
# 2. 获取当前文件所在的目录路径 (假设此文件与各个 app 文件夹同级,或者在特定配置目录下)
# 如果你的此文件在项目根目录,而 app 文件夹也在根目录:
from django.conf import settings
project_root = settings.BASE_DIR
# 如果 app 文件夹是 Django 的已安装应用,可能需要通过 settings.INSTALLED_APPS 获取,
# 但通常直接扫描物理目录更灵活。这里假设扫描当前目录下的所有子文件夹。
# 3. 自动发现并注册路由
def auto_load_routers(base_path, package_name_prefix=None):
"""
base_path: 物理路径,例如 /path/to/project
package_name_prefix: 包名前缀,例如 'myproject.' (如果这些文件夹是包的一部分)
"""
# 获取该路径下所有子模块/包
# 注意:这需要这些文件夹是合法的 Python 包 (即包含 __init__.py),或者在 Python 路径中
for importer, modname, ispkg in pkgutil.iter_modules([base_path]):
# 过滤条件:
# 1. 必须是包 (文件夹)
# 2. 不以 '_' 开头 (排除 __pycache__, _private 等)
# 3. 排除当前文件所在的脚本名 (防止递归或错误)
if ispkg and not modname.startswith('_'):
# 构造完整的模块路径:例如 "authorize.views"
# 如果这些文件夹直接位于根路径且不是大包的一部分,package_name_prefix 可能为空
if package_name_prefix:
full_module_path = f"{package_name_prefix}{modname}.views"
else:
full_module_path = f"{modname}.views"
try:
# 动态导入 views 模块
module = importlib.import_module(full_module_path)
# 检查是否存在 'router' 变量
if hasattr(module, 'router'):
router = getattr(module, 'router')
# 使用文件夹名称 (modname) 作为 URL 前缀
# 例如: 文件夹 'authorize' -> 前缀 '/authorize'
url_prefix = f"/{modname}"
api_v1.add_router(url_prefix, router)
print(f"✅ 自动注册: {url_prefix} (来自 {full_module_path})")
else:
print(f"⚠️ 跳过: {modname} (在 {full_module_path} 中未找到 'router' 变量)")
except ImportError as e:
# 如果文件夹里没有 views.py,会报 ImportError,这是正常的,跳过即可
if "No module named" in str(e) and "views" in str(e):
print(f"️ 跳过: {modname} (没有 views.py 模块)")
else:
print(f"❌ 导入错误 {modname}: {e}")
except Exception as e:
print(f"❌ 注册失败 {modname}: {e}")
api_v1 = NinjaAPI(version='1.0.0', auth=GlobalAuth())
auto_load_routers(project_root)
@api_v1.exception_handler(ValidationError)
def validation_errors(request, exc):
logger.error(request.body)
logger.error(exc)
logger.debug(traceback.format_exc())
return JsonResponse(data=CommonResponse.error(msg=f"输入参数验证失败!").to_dict(), status=422, safe=False)
@api_v1.exception_handler(exceptions.PyJWKError) # 捕获 HttpBearer 认证异常
def custom_http_bearer_exception_handler(request, exc):
logger.error(exc)
return JsonResponse(data=CommonResponse.error(msg=f"用户Token认证失败:{exc}").to_dict(), status=401)
@api_v1.exception_handler(exceptions.ExpiredSignatureError) # 捕获 HttpBearer 认证异常
def custom_http_bearer_exception_handler(request, exc):
logger.error(exc)
return JsonResponse(data=CommonResponse.error(msg=f"用户登录信息已过期,请重新登录!!").to_dict(), status=401)
urlpatterns = [
path('', include("front.urls")),
path('admin/', admin.site.urls),
path("api/", api_v1.urls),
path("ckeditor5/", include('django_ckeditor_5.urls')),
path("upload/", custom_upload_file, name="custom_upload_file"),
]
urlpatterns += staticfiles_urlpatterns()
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)