6.7 KiB
6.7 KiB
新功能开发规范
一、命名规范
- APP 名称:
hertz_studio_django_xxx,全小写,用下划线分隔 - Python 包与模块:全小写,短名称,避免缩写不清晰
- URL 命名空间:
app_name = 'hertz_studio_django_xxx' - 数据库表名:
Meta.db_table = 'hertz_xxx_model',避免与其他库冲突 - 迁移文件命名:描述性动词+对象,如
0003_add_field_to_model
二、项目结构与约定
- 标准结构:
apps.py、models.py、serializers.py、views.py、urls.py、admin.py - 静态资源:
media/<app_name>/...放置同路径资源以覆盖库静态文件 - 配置集中:在
settings.py维护,使用前缀化大写变量(如YOLO_MODEL)
三、接口返回规范
- 统一使用
HertzResponse(路径:hertz_studio_django_utils/responses/HertzResponse.py) - 成功:
from hertz_studio_django_utils.responses.HertzResponse import HertzResponse return HertzResponse.success(data={'id': 1}, message='操作成功') - 失败:
return HertzResponse.fail(message='业务失败') - 错误:
return HertzResponse.error(message='系统错误', error=str(e)) - 验证失败:
return HertzResponse.validation_error(message='参数验证失败', errors=serializer.errors) - 统一键:
success | code | message | data,禁止返回非标准顶层结构
四、API 设计规范
- 路径语义化:
/models/、/detections/、/alerts/ - 方法约定:
GET查询、POST创建/动作、PUT/PATCH更新、DELETE删除 - 分页:请求参数
page, page_size;响应total, items - 过滤与排序:查询参数
q, order_by, filters;谨慎开放可排序字段
五、认证与授权
- 强制认证:业务敏感接口使用登录态(装饰器或 DRF 权限类)
- 权限控制:按用户/组/角色配置;避免在视图中硬编码权限
- 速率限制:对登录、验证码、检测等接口进行限流
六、日志与审计
- 请求审计:记录请求方法、路径、用户、响应码、耗时
- 业务事件:模型启用/删除、检测结果、告警变更记录
- 脱敏:对密码、令牌、隐私字段进行统一脱敏
七、配置约定
- 所有库配置集中在
settings.py,使用前缀化变量:- AI:
AI_MODEL_PROVIDER、AI_DEFAULT_MODEL、AI_TIMEOUT - Auth:
AUTH_LOGIN_REDIRECT_URL、AUTH_ENABLE_OAUTH - Captcha:
CAPTCHA_TYPE、CAPTCHA_EXPIRE_SECONDS - Log:
LOG_LEVEL、LOG_SINKS、LOG_REDACT_FIELDS - Notice:
NOTICE_CHANNELS、NOTICE_RETRY - Monitor:
MONITOR_PROBES、MONITOR_ALERTS - Wiki:
WIKI_MARKDOWN、WIKI_SEARCH_BACKEND - YOLO:
YOLO_MODEL、YOLO_DEVICE、YOLO_CONF_THRESHOLD - Codegen:
CODEGEN_TEMPLATES_DIR、CODEGEN_OUTPUT_DIR
- AI:
八、可扩展性(不改库源码)
- 视图子类化 + 路由覆盖:在项目中继承库视图并替换路由匹配
# urls.py from django.urls import path, include from your_app.views import MyDetectView urlpatterns = [ path('yolo/detect/', MyDetectView.as_view(), name='detect'), path('yolo/', include('hertz_studio_django_yolo.urls', namespace='hertz_studio_django_yolo')), ] - 猴子补丁:在
AppConfig.ready()将库函数替换为自定义函数# apps.py from django.apps import AppConfig class YourAppConfig(AppConfig): name = 'your_app' def ready(self): from hertz_studio_django_yolo import views as yviews from your_app.views import my_yolo_detection yviews.yolo_detection = my_yolo_detection - Admin 重注册:
unregister后register自定义ModelAdmin - 信号连接:在
ready()中连接库暴露的信号以扩展行为
九、示例:覆写 YOLO 检测返回值
- 目标位置:
hertz_studio_django_yolo/views.py:586-603 - 最小替换示例(路由覆盖):
from rest_framework.decorators import api_view, parser_classes from rest_framework.parsers import MultiPartParser, FormParser from django.contrib.auth.decorators import login_required from hertz_studio_django_utils.responses.HertzResponse import HertzResponse from hertz_studio_django_yolo.views import _perform_detection from hertz_studio_django_yolo.models import YoloModel, DetectionRecord import uuid, os, time, shutil @api_view(['POST']) @parser_classes([MultiPartParser, FormParser]) @login_required def my_yolo_detection(request): # 复用库的流程,省略若干步骤,仅演示返回体差异化 serializer = hertz_studio_django_yolo.serializers.DetectionRequestSerializer(data=request.data) if not serializer.is_valid(): return HertzResponse.validation_error(message='参数验证失败', errors=serializer.errors) uploaded_file = serializer.validated_data['file'] yolo_model = YoloModel.get_enabled_model() original_path = '...' # 省略:存储原始文件 result_path, object_count, detected_categories, confidence_scores, avg_confidence = _perform_detection('...', yolo_model.model_path, 0.5, 'image', yolo_model) processing_time = time.time() - time.time() detection_record = DetectionRecord.objects.create( original_file=original_path, result_file='...', detection_type='image', model_name=f"{yolo_model.name} {yolo_model.version}", model=yolo_model, user=request.user, user_name=request.user.username, object_count=object_count, detected_categories=detected_categories, confidence_threshold=0.5, confidence_scores=confidence_scores, avg_confidence=avg_confidence, processing_time=processing_time ) return HertzResponse.success( data={ 'id': detection_record.id, 'file': { 'result_url': detection_record.result_file.url, 'original_url': detection_record.original_file.url }, 'stats': { 'count': object_count, 'categories': detected_categories, 'scores': confidence_scores, 'avg_score': round(avg_confidence, 4) if avg_confidence is not None else None, 'time': round(processing_time, 2) }, 'model': { 'name': yolo_model.name, 'version': yolo_model.version, 'threshold': 0.5 }, 'user': { 'id': getattr(request.user, 'user_id', None), 'name': request.user.username } }, message='检测完成' )