autosnippet
Version:
Extract code patterns into a knowledge base for AI coding assistants
216 lines (215 loc) • 8.65 kB
JavaScript
/**
* 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();