UNPKG

autosnippet

Version:

Extract code patterns into a knowledge base for AI coding assistants

216 lines (215 loc) 8.65 kB
/** * Django Enhancement Pack * 条件: { languages: ['python'], frameworks: ['django'] } * * 覆盖 Django 全栈生态: * - Model 字段/关系/Manager/QuerySet * - DRF (Django REST Framework) Serializer/ViewSet * - URL 路由约定 * - Signal (pre_save/post_save) * - Middleware * - Management Command * - Celery Task 集成 */ import { EnhancementPack } from './EnhancementPack.js'; class DjangoEnhancement extends EnhancementPack { get id() { return 'django'; } get displayName() { return 'Django / DRF Enhancement'; } get conditions() { return { languages: ['python'], frameworks: ['django'] }; } getExtraDimensions() { return [ { id: 'django-model-scan', label: 'Django Model 扫描', guide: 'Model 字段与关系扫描(ForeignKey/ManyToMany/OneToOne)、Manager 自定义、QuerySet 链路、Meta 选项 (ordering/indexes/constraints)', tierHint: 2, knowledgeTypes: ['architecture', 'code-pattern'], skillWorthy: true, dualOutput: true, skillMeta: { name: 'project-django-models', description: 'Django Model definitions, field relationships and custom managers (auto-generated by enhancement)', }, }, { id: 'django-drf-scan', label: 'DRF API 分析', guide: 'Django REST Framework 分析 — Serializer/ModelSerializer 字段映射、ViewSet/GenericAPIView 层级、Router 注册、Permission/Throttle 策略、Pagination 配置', tierHint: 2, knowledgeTypes: ['architecture', 'code-pattern'], skillWorthy: true, dualOutput: true, skillMeta: { name: 'project-django-drf', description: 'DRF serializers, viewsets, permissions and router configuration (auto-generated by enhancement)', }, }, { id: 'django-signal-middleware-scan', label: 'Signal / Middleware 分析', guide: 'Signal 分析 (pre_save/post_save/pre_delete/post_delete/m2m_changed 等) 及 Middleware 链路 (MIDDLEWARE 顺序)、自定义 Middleware 实现', tierHint: 2, knowledgeTypes: ['architecture'], skillWorthy: true, dualOutput: true, skillMeta: { name: 'project-django-signals', description: 'Django signal handlers, middleware chain ordering and custom middleware (auto-generated by enhancement)', }, }, ]; } getGuardRules() { return [ { ruleId: 'django-n-plus-one', category: 'performance', dimension: 'file', severity: 'warning', languages: ['python'], pattern: /\.objects\.(?:all|filter)\([^)]*\)[\s\S]*?for\s+\w+\s+in/, message: 'QuerySet 在循环中可能触发 N+1 查询 — 使用 select_related() / prefetch_related() 优化', }, { ruleId: 'django-raw-sql', category: 'safety', dimension: 'file', severity: 'warning', languages: ['python'], pattern: /\.raw\s*\(|cursor\.execute\s*\(/, message: '使用 raw SQL 需确保参数化查询,防止 SQL 注入 — 优先使用 ORM QuerySet', }, { ruleId: 'django-no-null-charfield', category: 'correctness', dimension: 'file', severity: 'info', languages: ['python'], pattern: /(?:CharField|TextField|SlugField|URLField|EmailField)\s*\([^)]*null\s*=\s*True/, message: 'Django 约定: CharField/TextField 不应使用 null=True — 使用 blank=True + default="" 代替', }, { ruleId: 'django-model-str', category: 'style', dimension: 'file', severity: 'info', languages: ['python'], pattern: /class\s+\w+\((?:models\.)?Model\):\s*\n(?:(?!\s*def\s+__str__)[\s\S])*?(?=\nclass\s|Z)/, message: 'Django Model 建议实现 __str__ 方法 — 便于 admin 和 shell 调试', }, ]; } detectPatterns(astSummary) { const patterns = []; // ── Django Models ── for (const cls of astSummary.classes || []) { if (cls.superclass && /Model$/.test(cls.superclass)) { patterns.push({ type: 'django-model', className: cls.name, line: cls.line, confidence: 0.9, }); } } // ── Django Views / ViewSets ── for (const cls of astSummary.classes || []) { if (cls.superclass && /View$|ViewSet$|APIView$|GenericAPIView/.test(cls.superclass)) { patterns.push({ type: 'django-view', className: cls.name, line: cls.line, confidence: 0.85, }); } } // ── DRF Serializers ── for (const cls of astSummary.classes || []) { if (cls.superclass && /Serializer$|ModelSerializer|HyperlinkedModelSerializer/.test(cls.superclass)) { patterns.push({ type: 'drf-serializer', className: cls.name, line: cls.line, confidence: 0.9, }); } } // ── Django Management Commands ── for (const cls of astSummary.classes || []) { if (cls.superclass && /BaseCommand/.test(cls.superclass)) { patterns.push({ type: 'django-management-command', className: cls.name, line: cls.line, confidence: 0.9, }); } } // ── Django Middleware ── for (const cls of astSummary.classes || []) { const nameLower = cls.name?.toLowerCase() || ''; if (nameLower.includes('middleware')) { patterns.push({ type: 'django-middleware', className: cls.name, line: cls.line, confidence: 0.8, }); } } // ── Django Admin ── for (const cls of astSummary.classes || []) { if (cls.superclass && /ModelAdmin|TabularInline|StackedInline/.test(cls.superclass)) { patterns.push({ type: 'django-admin', className: cls.name, line: cls.line, confidence: 0.9, }); } } // ── Signal handler functions ── for (const m of astSummary.methods || []) { if (m.decorators?.some((d) => /receiver/.test(d))) { patterns.push({ type: 'django-signal-handler', methodName: m.name, line: m.line, confidence: 0.9, }); } } // ── Celery tasks ── for (const m of astSummary.methods || []) { if (m.decorators?.some((d) => /@(?:shared_task|app\.task|task)/.test(d))) { patterns.push({ type: 'django-celery-task', methodName: m.name, line: m.line, confidence: 0.9, }); } } // ── Django ecosystem imports ── const djangoImports = (astSummary.imports || []).filter((imp) => imp.includes('django') || imp.includes('rest_framework') || imp.includes('celery') || imp.includes('django_filters')); if (djangoImports.length > 0) { patterns.push({ type: 'django-ecosystem-usage', importCount: djangoImports.length, confidence: 0.85, }); } return patterns; } } export const pack = new DjangoEnhancement();