django-drf
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCritical Patterns
核心开发模式
- ALWAYS separate serializers by operation: Read / Create / Update / Include
- ALWAYS use for complex filtering (not
filterset_class)filterset_fields - ALWAYS validate unknown fields in write serializers (inherit )
BaseWriteSerializer - ALWAYS use /
select_relatedinprefetch_relatedto avoid N+1get_queryset() - ALWAYS handle in
swagger_fake_viewfor schema generationget_queryset() - ALWAYS use for OpenAPI docs on
@extend_schema_fieldSerializerMethodField - NEVER put business logic in serializers - use services/utils
- NEVER use auto-increment PKs - use UUIDv4 or UUIDv7
- NEVER use trailing slashes in URLs ()
trailing_slash=False
Note:is specific to drf-spectacular for OpenAPI schema generation.swagger_fake_view
- 始终按操作类型拆分序列化器:读取/创建/更新/包含
- 始终使用实现复杂过滤(不要使用
filterset_class)filterset_fields - 始终在写入型序列化器中验证未知字段(继承)
BaseWriteSerializer - 始终在中使用
get_queryset()/select_related避免N+1查询问题prefetch_related - 始终在中处理
get_queryset()以支持Schema生成swagger_fake_view - 始终为使用
SerializerMethodField生成OpenAPI文档@extend_schema_field - 绝对不要在序列化器中编写业务逻辑 - 应使用服务/工具类
- 绝对不要使用自增主键 - 使用UUIDv4或UUIDv7
- 绝对不要在URL中使用尾部斜杠(设置)
trailing_slash=False
注意:是drf-spectacular用于生成OpenAPI Schema的特定标识。swagger_fake_view
Implementation Checklist
实现检查清单
When implementing a new endpoint, review these patterns in order:
| # | Pattern | Reference | Key Points |
|---|---|---|---|
| 1 | Models | | UUID PK, |
| 2 | ViewSets | | Inherit |
| 3 | Serializers | | Separate Read/Create/Update/Include, inherit |
| 4 | Filters | | Use |
| 5 | Permissions | | |
| 6 | Pagination | | Custom pagination class if needed |
| 7 | URL Routing | | |
| 8 | OpenAPI Schema | | |
| 9 | Tests | | JSON:API content type, fixture patterns |
Full file paths: See references/file-locations.md
在实现新接口时,按以下顺序检查这些模式:
| 序号 | 模式 | 参考文件 | 核心要点 |
|---|---|---|---|
| 1 | 模型 | | UUID主键、 |
| 2 | ViewSets | | 继承 |
| 3 | 序列化器 | | 拆分读取/创建/更新/包含类型,继承 |
| 4 | 过滤器 | | 使用 |
| 5 | 权限控制 | | |
| 6 | 分页 | | 必要时使用自定义分页类 |
| 7 | URL路由 | | |
| 8 | OpenAPI Schema | | 结合drf-spectacular使用 |
| 9 | 测试 | | JSON:API内容类型、固定数据模式 |
完整文件路径:查看 references/file-locations.md
Decision Trees
决策树
Which Serializer?
如何选择序列化器?
GET list/retrieve → <Model>Serializer
POST create → <Model>CreateSerializer
PATCH update → <Model>UpdateSerializer
?include=... → <Model>IncludeSerializerGET list/retrieve → <Model>Serializer
POST create → <Model>CreateSerializer
PATCH update → <Model>UpdateSerializer
?include=... → <Model>IncludeSerializerWhich Base Serializer?
如何选择基础序列化器?
Read-only serializer → BaseModelSerializerV1
Create with tenant_id → RLSSerializer + BaseWriteSerializer (auto-injects tenant_id on create)
Update with validation → BaseWriteSerializer (tenant_id already exists on object)
Non-model data → BaseSerializerV1只读序列化器 → BaseModelSerializerV1
带tenant_id的创建操作 → RLSSerializer + BaseWriteSerializer(创建时自动注入tenant_id)
带验证的更新操作 → BaseWriteSerializer(对象已存在tenant_id)
非模型数据 → BaseSerializerV1Which Filter Base?
如何选择基础过滤器?
Direct FK to Provider → BaseProviderFilter
FK via Scan → BaseScanProviderFilter
No provider relation → FilterSet直接关联Provider外键 → BaseProviderFilter
通过Scan关联Provider外键 → BaseScanProviderFilter
无Provider关联 → FilterSetWhich Base ViewSet?
如何选择基础ViewSet?
RLS-protected model → BaseRLSViewSet (most common)
Tenant operations → BaseTenantViewset
User operations → BaseUserViewset
No RLS required → BaseViewSet (rare)受RLS保护的模型 → BaseRLSViewSet(最常用)
租户操作 → BaseTenantViewset
用户操作 → BaseUserViewset
无需RLS保护 → BaseViewSet(罕见)Resource Name Format?
资源名称格式?
Single word model → plural lowercase (Provider → providers)
Multi-word model → plural lowercase kebab (ProviderGroup → provider-groups)
Through/join model → parent-child pattern (UserRoleRelationship → user-roles)
Aggregation/overview → descriptive kebab plural (ComplianceOverview → compliance-overviews)单单词模型 → 复数小写形式 (Provider → providers)
多单词模型 → 复数小写短横线形式 (ProviderGroup → provider-groups)
关联模型 → 父子命名模式 (UserRoleRelationship → user-roles)
聚合/概览模型 → 描述性复数短横线形式 (ComplianceOverview → compliance-overviews)Serializer Patterns
序列化器模式
Base Class Hierarchy
基类层级结构
python
undefinedpython
undefinedRead serializer (most common)
Read serializer (most common)
class ProviderSerializer(RLSSerializer):
class Meta:
model = Provider
fields = ["id", "provider", "uid", "alias", "connected", "inserted_at"]
class ProviderSerializer(RLSSerializer):
class Meta:
model = Provider
fields = ["id", "provider", "uid", "alias", "connected", "inserted_at"]
Write serializer (validates unknown fields)
Write serializer (validates unknown fields)
class ProviderCreateSerializer(RLSSerializer, BaseWriteSerializer):
class Meta:
model = Provider
fields = ["provider", "uid", "alias"]
class ProviderCreateSerializer(RLSSerializer, BaseWriteSerializer):
class Meta:
model = Provider
fields = ["provider", "uid", "alias"]
Include serializer (sparse fields for ?include=)
Include serializer (sparse fields for ?include=)
class ProviderIncludeSerializer(RLSSerializer):
class Meta:
model = Provider
fields = ["id", "alias"] # Minimal fields
undefinedclass ProviderIncludeSerializer(RLSSerializer):
class Meta:
model = Provider
fields = ["id", "alias"] # Minimal fields
undefinedSerializerMethodField with OpenAPI
结合OpenAPI的SerializerMethodField
python
from drf_spectacular.utils import extend_schema_field
class ProviderSerializer(RLSSerializer):
connection = serializers.SerializerMethodField(read_only=True)
@extend_schema_field({
"type": "object",
"properties": {
"connected": {"type": "boolean"},
"last_checked_at": {"type": "string", "format": "date-time"},
},
})
def get_connection(self, obj):
return {
"connected": obj.connected,
"last_checked_at": obj.connection_last_checked_at,
}python
from drf_spectacular.utils import extend_schema_field
class ProviderSerializer(RLSSerializer):
connection = serializers.SerializerMethodField(read_only=True)
@extend_schema_field({
"type": "object",
"properties": {
"connected": {"type": "boolean"},
"last_checked_at": {"type": "string", "format": "date-time"},
},
})
def get_connection(self, obj):
return {
"connected": obj.connected,
"last_checked_at": obj.connection_last_checked_at,
}Included Serializers (JSON:API)
包含式序列化器(JSON:API)
python
class ScanSerializer(RLSSerializer):
included_serializers = {
"provider": "api.v1.serializers.ProviderIncludeSerializer",
}python
class ScanSerializer(RLSSerializer):
included_serializers = {
"provider": "api.v1.serializers.ProviderIncludeSerializer",
}Sensitive Data Masking
敏感数据掩码
python
def to_representation(self, instance):
data = super().to_representation(instance)
# Mask by default, expose only on explicit request
fields_param = self.context.get("request").query_params.get("fields[my-model]", "")
if "api_key" in fields_param:
data["api_key"] = instance.api_key_decoded
else:
data["api_key"] = "****" if instance.api_key else None
return datapython
def to_representation(self, instance):
data = super().to_representation(instance)
# Mask by default, expose only on explicit request
fields_param = self.context.get("request").query_params.get("fields[my-model]", "")
if "api_key" in fields_param:
data["api_key"] = instance.api_key_decoded
else:
data["api_key"] = "****" if instance.api_key else None
return dataViewSet Patterns
ViewSet模式
get_queryset() with N+1 Prevention
避免N+1查询的get_queryset()
Always combine check with /:
swagger_fake_viewselect_relatedprefetch_relatedpython
def get_queryset(self):
# REQUIRED: Return empty queryset for OpenAPI schema generation
if getattr(self, "swagger_fake_view", False):
return Provider.objects.none()
# N+1 prevention: eager load relationships
return Provider.objects.select_related(
"tenant",
).prefetch_related(
"provider_groups",
Prefetch("tags", queryset=ProviderTag.objects.filter(tenant_id=self.request.tenant_id)),
)Why swagger_fake_view? drf-spectacular introspects ViewSets to generate OpenAPI schemas. Without this check, it executes real queries and can fail without request context.
务必同时结合检查与/:
swagger_fake_viewselect_relatedprefetch_relatedpython
def get_queryset(self):
# REQUIRED: Return empty queryset for OpenAPI schema generation
if getattr(self, "swagger_fake_view", False):
return Provider.objects.none()
# N+1 prevention: eager load relationships
return Provider.objects.select_related(
"tenant",
).prefetch_related(
"provider_groups",
Prefetch("tags", queryset=ProviderTag.objects.filter(tenant_id=self.request.tenant_id)),
)为什么需要swagger_fake_view? drf-spectacular会通过解析ViewSet生成OpenAPI Schema。如果没有此检查,它会执行真实查询,在缺少请求上下文时可能失败。
Action-Specific Serializers
按操作选择序列化器
python
def get_serializer_class(self):
if self.action == "create":
return ProviderCreateSerializer
elif self.action == "partial_update":
return ProviderUpdateSerializer
elif self.action in ["connection", "destroy"]:
return TaskSerializer
return ProviderSerializerpython
def get_serializer_class(self):
if self.action == "create":
return ProviderCreateSerializer
elif self.action == "partial_update":
return ProviderUpdateSerializer
elif self.action in ["connection", "destroy"]:
return TaskSerializer
return ProviderSerializerDynamic Permissions per Action
按操作动态配置权限
python
class ProviderViewSet(BaseRLSViewSet):
required_permissions = [Permissions.MANAGE_PROVIDERS]
def set_required_permissions(self):
if self.action in ["list", "retrieve"]:
self.required_permissions = [] # Read-only = no permission
else:
self.required_permissions = [Permissions.MANAGE_PROVIDERS]python
class ProviderViewSet(BaseRLSViewSet):
required_permissions = [Permissions.MANAGE_PROVIDERS]
def set_required_permissions(self):
if self.action in ["list", "retrieve"]:
self.required_permissions = [] # Read-only = no permission
else:
self.required_permissions = [Permissions.MANAGE_PROVIDERS]Cache Decorator
缓存装饰器
python
from django.utils.decorators import method_decorator
from django.views.decorators.cache import cache_control
CACHE_DECORATOR = cache_control(
max_age=django_settings.CACHE_MAX_AGE,
stale_while_revalidate=django_settings.CACHE_STALE_WHILE_REVALIDATE,
)
@method_decorator(CACHE_DECORATOR, name="list")
@method_decorator(CACHE_DECORATOR, name="retrieve")
class ProviderViewSet(BaseRLSViewSet):
passpython
from django.utils.decorators import method_decorator
from django.views.decorators.cache import cache_control
CACHE_DECORATOR = cache_control(
max_age=django_settings.CACHE_MAX_AGE,
stale_while_revalidate=django_settings.CACHE_STALE_WHILE_REVALIDATE,
)
@method_decorator(CACHE_DECORATOR, name="list")
@method_decorator(CACHE_DECORATOR, name="retrieve")
class ProviderViewSet(BaseRLSViewSet):
passCustom Actions
自定义操作
python
undefinedpython
undefinedDetail action (operates on single object)
Detail action (operates on single object)
@action(detail=True, methods=["post"], url_name="connection")
def connection(self, request, pk=None):
instance = self.get_object()
# Process instance...
@action(detail=True, methods=["post"], url_name="connection")
def connection(self, request, pk=None):
instance = self.get_object()
# Process instance...
List action (operates on collection)
List action (operates on collection)
@action(detail=False, methods=["get"], url_name="metadata")
def metadata(self, request):
queryset = self.filter_queryset(self.get_queryset())
# Aggregate over queryset...
---@action(detail=False, methods=["get"], url_name="metadata")
def metadata(self, request):
queryset = self.filter_queryset(self.get_queryset())
# Aggregate over queryset...
---Filter Patterns
过滤器模式
Base Filter Classes
基础过滤器类
python
class BaseProviderFilter(FilterSet):
"""For models with direct FK to Provider"""
provider_id = UUIDFilter(field_name="provider__id", lookup_expr="exact")
provider_id__in = UUIDInFilter(field_name="provider__id", lookup_expr="in")
provider_type = ChoiceFilter(field_name="provider__provider", choices=Provider.ProviderChoices.choices)
class BaseScanProviderFilter(FilterSet):
"""For models with FK to Scan (Scan has FK to Provider)"""
provider_id = UUIDFilter(field_name="scan__provider__id", lookup_expr="exact")python
class BaseProviderFilter(FilterSet):
"""For models with direct FK to Provider"""
provider_id = UUIDFilter(field_name="provider__id", lookup_expr="exact")
provider_id__in = UUIDInFilter(field_name="provider__id", lookup_expr="in")
provider_type = ChoiceFilter(field_name="provider__provider", choices=Provider.ProviderChoices.choices)
class BaseScanProviderFilter(FilterSet):
"""For models with FK to Scan (Scan has FK to Provider)"""
provider_id = UUIDFilter(field_name="scan__provider__id", lookup_expr="exact")Custom Multi-Value Filters
自定义多值过滤器
python
class UUIDInFilter(BaseInFilter, UUIDFilter):
pass
class CharInFilter(BaseInFilter, CharFilter):
pass
class ChoiceInFilter(BaseInFilter, ChoiceFilter):
passpython
class UUIDInFilter(BaseInFilter, UUIDFilter):
pass
class CharInFilter(BaseInFilter, CharFilter):
pass
class ChoiceInFilter(BaseInFilter, ChoiceFilter):
passArrayField Filtering
ArrayField过滤
python
undefinedpython
undefinedSingle value contains
Single value contains
region = CharFilter(method="filter_region")
def filter_region(self, queryset, name, value):
return queryset.filter(resource_regions__contains=[value])
region = CharFilter(method="filter_region")
def filter_region(self, queryset, name, value):
return queryset.filter(resource_regions__contains=[value])
Multi-value overlap
Multi-value overlap
region__in = CharInFilter(field_name="resource_regions", lookup_expr="overlap")
undefinedregion__in = CharInFilter(field_name="resource_regions", lookup_expr="overlap")
undefinedDate Range Validation
日期范围验证
python
def filter_queryset(self, queryset):
# Require date filter for performance
if not (date_filters_provided):
raise ValidationError([{
"detail": "At least one date filter is required",
"status": 400,
"source": {"pointer": "/data/attributes/inserted_at"},
"code": "required",
}])
# Validate max range
if date_range > settings.FINDINGS_MAX_DAYS_IN_RANGE:
raise ValidationError(...)
return super().filter_queryset(queryset)python
def filter_queryset(self, queryset):
# Require date filter for performance
if not (date_filters_provided):
raise ValidationError([{
"detail": "At least one date filter is required",
"status": 400,
"source": {"pointer": "/data/attributes/inserted_at"},
"code": "required",
}])
# Validate max range
if date_range > settings.FINDINGS_MAX_DAYS_IN_RANGE:
raise ValidationError(...)
return super().filter_queryset(queryset)Dynamic FilterSet Selection
动态选择FilterSet
python
def get_filterset_class(self):
if self.action in ["latest", "metadata_latest"]:
return LatestFindingFilter
return FindingFilterpython
def get_filterset_class(self):
if self.action in ["latest", "metadata_latest"]:
return LatestFindingFilter
return FindingFilterEnum Field Override
枚举字段覆盖
python
class Meta:
model = Finding
filter_overrides = {
FindingDeltaEnumField: {"filter_class": CharFilter},
StatusEnumField: {"filter_class": CharFilter},
SeverityEnumField: {"filter_class": CharFilter},
}python
class Meta:
model = Finding
filter_overrides = {
FindingDeltaEnumField: {"filter_class": CharFilter},
StatusEnumField: {"filter_class": CharFilter},
SeverityEnumField: {"filter_class": CharFilter},
}Performance Patterns
性能优化模式
PaginateByPkMixin
PaginateByPkMixin
For large querysets with expensive joins:
python
class PaginateByPkMixin:
def paginate_by_pk(self, request, base_queryset, manager,
select_related=None, prefetch_related=None):
# 1. Get PKs only (cheap)
pk_list = base_queryset.values_list("id", flat=True)
page = self.paginate_queryset(pk_list)
# 2. Fetch full objects for just the page
queryset = manager.filter(id__in=page)
if select_related:
queryset = queryset.select_related(*select_related)
if prefetch_related:
queryset = queryset.prefetch_related(*prefetch_related)
# 3. Re-sort to preserve DB ordering
queryset = sorted(queryset, key=lambda obj: page.index(obj.id))
return self.get_paginated_response(self.get_serializer(queryset, many=True).data)针对包含复杂关联的大型数据集:
python
class PaginateByPkMixin:
def paginate_by_pk(self, request, base_queryset, manager,
select_related=None, prefetch_related=None):
# 1. Get PKs only (cheap)
pk_list = base_queryset.values_list("id", flat=True)
page = self.paginate_queryset(pk_list)
# 2. Fetch full objects for just the page
queryset = manager.filter(id__in=page)
if select_related:
queryset = queryset.select_related(*select_related)
if prefetch_related:
queryset = queryset.prefetch_related(*prefetch_related)
# 3. Re-sort to preserve DB ordering
queryset = sorted(queryset, key=lambda obj: page.index(obj.id))
return self.get_paginated_response(self.get_serializer(queryset, many=True).data)Prefetch in Serializers
序列化器中的预加载优化
python
def get_tags(self, obj):
# Use prefetched tags if available
if hasattr(obj, "prefetched_tags"):
return {tag.key: tag.value for tag in obj.prefetched_tags}
# Fallback (causes N+1 if not prefetched)
return obj.get_tags(self.context.get("tenant_id"))python
def get_tags(self, obj):
# Use prefetched tags if available
if hasattr(obj, "prefetched_tags"):
return {tag.key: tag.value for tag in obj.prefetched_tags}
# Fallback (causes N+1 if not prefetched)
return obj.get_tags(self.context.get("tenant_id"))Naming Conventions
命名规范
| Entity | Pattern | Example |
|---|---|---|
| Serializer (read) | | |
| Serializer (create) | | |
| Serializer (update) | | |
| Serializer (include) | | |
| Filter | | |
| ViewSet | | |
| 实体 | 命名模式 | 示例 |
|---|---|---|
| 读取型序列化器 | | |
| 创建型序列化器 | | |
| 更新型序列化器 | | |
| 包含型序列化器 | | |
| 过滤器 | | |
| ViewSet | | |
OpenAPI Documentation
OpenAPI文档
python
from drf_spectacular.utils import extend_schema, extend_schema_view
@extend_schema_view(
list=extend_schema(tags=["Provider"], summary="List all providers"),
retrieve=extend_schema(tags=["Provider"], summary="Retrieve provider"),
create=extend_schema(tags=["Provider"], summary="Create provider"),
)
@extend_schema(tags=["Provider"])
class ProviderViewSet(BaseRLSViewSet):
passpython
from drf_spectacular.utils import extend_schema, extend_schema_view
@extend_schema_view(
list=extend_schema(tags=["Provider"], summary="List all providers"),
retrieve=extend_schema(tags=["Provider"], summary="Retrieve provider"),
create=extend_schema(tags=["Provider"], summary="Create provider"),
)
@extend_schema(tags=["Provider"])
class ProviderViewSet(BaseRLSViewSet):
passAPI Security Patterns
API安全模式
Full examples: See assets/security_patterns.py
| Pattern | Key Points |
|---|---|
| Input Validation | Use |
| Prevent Mass Assignment | ALWAYS use explicit |
| Object-Level Permissions | Implement |
| Rate Limiting | Configure |
| Prevent Info Disclosure | Generic error messages, return 404 not 403 for unauthorized (prevents enumeration) |
| SQL Injection | ALWAYS use ORM parameterization, NEVER string interpolation in raw SQL |
完整示例:查看 assets/security_patterns.py
| 模式 | 核心要点 |
|---|---|
| 输入验证 | 使用 |
| 防止批量赋值 | 始终使用显式的 |
| 对象级权限控制 | 实现 |
| 请求频率限制 | 配置 |
| 防止信息泄露 | 使用通用错误提示,未授权时返回404而非403(防止枚举攻击) |
| SQL注入防护 | 始终使用ORM参数化查询,绝对不要在原生SQL中使用字符串拼接 |
Quick Reference
快速参考
python
undefinedpython
undefinedInput validation in serializer
Input validation in serializer
def validate_uid(self, value):
value = value.strip().lower()
if not re.match(r'^[a-z0-9-]+$', value):
raise serializers.ValidationError("Invalid format")
return value
def validate_uid(self, value):
value = value.strip().lower()
if not re.match(r'^[a-z0-9-]+$', value):
raise serializers.ValidationError("Invalid format")
return value
Explicit fields (prevent mass assignment)
Explicit fields (prevent mass assignment)
class Meta:
fields = ["name", "email"] # GOOD: whitelist
read_only_fields = ["id", "inserted_at"] # System fields
class Meta:
fields = ["name", "email"] # GOOD: whitelist
read_only_fields = ["id", "inserted_at"] # System fields
Object permission
Object permission
class IsOwnerOrReadOnly(BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in SAFE_METHODS:
return True
return obj.owner == request.user
class IsOwnerOrReadOnly(BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in SAFE_METHODS:
return True
return obj.owner == request.user
Throttling for sensitive endpoints
Throttling for sensitive endpoints
class BurstRateThrottle(UserRateThrottle):
rate = "10/minute"
class BurstRateThrottle(UserRateThrottle):
rate = "10/minute"
Safe error messages (prevent enumeration)
Safe error messages (prevent enumeration)
def get_object(self):
try:
return super().get_object()
except Http404:
raise NotFound("Resource not found") # Generic, no internal IDs
---def get_object(self):
try:
return super().get_object()
except Http404:
raise NotFound("Resource not found") # Generic, no internal IDs
---Commands
命令
bash
undefinedbash
undefinedDevelopment
Development
cd api && poetry run python src/backend/manage.py runserver
cd api && poetry run python src/backend/manage.py shell
cd api && poetry run python src/backend/manage.py runserver
cd api && poetry run python src/backend/manage.py shell
Database
Database
cd api && poetry run python src/backend/manage.py makemigrations
cd api && poetry run python src/backend/manage.py migrate
cd api && poetry run python src/backend/manage.py makemigrations
cd api && poetry run python src/backend/manage.py migrate
Testing
Testing
cd api && poetry run pytest -x --tb=short
cd api && poetry run make lint
---cd api && poetry run pytest -x --tb=short
cd api && poetry run make lint
---Resources
参考资源
Local References
本地参考
- File Locations: See references/file-locations.md
- JSON:API Conventions: See references/json-api-conventions.md
- Security Patterns: See assets/security_patterns.py
- 文件位置:查看 references/file-locations.md
- JSON:API规范:查看 references/json-api-conventions.md
- 安全模式:查看 assets/security_patterns.py
Context7 MCP (Recommended)
Context7 MCP(推荐)
Prerequisite: Install Context7 MCP server for up-to-date documentation lookup.
When implementing or debugging, query these libraries via :
mcp_context7_query-docs| Library | Context7 ID | Use For |
|---|---|---|
| Django | | Models, ORM, migrations |
| DRF | | ViewSets, serializers, permissions |
| drf-spectacular | | OpenAPI schema, |
Example queries:
mcp_context7_query-docs(libraryId="/websites/django-rest-framework", query="ViewSet get_queryset best practices")
mcp_context7_query-docs(libraryId="/tfranzel/drf-spectacular", query="extend_schema examples for custom actions")
mcp_context7_query-docs(libraryId="/websites/djangoproject_en_5_2", query="model constraints and indexes")Note: Usefirst if you need to find the correct library ID.mcp_context7_resolve-library-id
前置条件:安装Context7 MCP服务器以获取最新文档查询能力。
在实现或调试时,可通过查询以下库:
mcp_context7_query-docs| 库 | Context7 ID | 适用场景 |
|---|---|---|
| Django | | 模型、ORM、迁移 |
| DRF | | ViewSets、序列化器、权限 |
| drf-spectacular | | OpenAPI Schema、 |
查询示例:
mcp_context7_query-docs(libraryId="/websites/django-rest-framework", query="ViewSet get_queryset best practices")
mcp_context7_query-docs(libraryId="/tfranzel/drf-spectacular", query="extend_schema examples for custom actions")
mcp_context7_query-docs(libraryId="/websites/djangoproject_en_5_2", query="model constraints and indexes")注意:如果需要查找正确的库ID,请先使用。mcp_context7_resolve-library-id
External Docs
外部文档
- DRF Docs: https://www.django-rest-framework.org/
- DRF JSON:API: https://django-rest-framework-json-api.readthedocs.io/
- drf-spectacular: https://drf-spectacular.readthedocs.io/
- django-filter: https://django-filter.readthedocs.io/
- DRF官方文档:https://www.django-rest-framework.org/
- DRF JSON:API:https://django-rest-framework-json-api.readthedocs.io/
- drf-spectacular:https://drf-spectacular.readthedocs.io/
- django-filter:https://django-filter.readthedocs.io/