⚖️ Старый vs Новый подход
Устаревшие паттерны из лекции — современные аналоги на DRF 3.15+ / Django 5.x
⚡ Основные изменения
- drf-yasg (OpenAPI 2.0) → drf-spectacular (OpenAPI 3.0) — современный стандарт
- Ручная проверка user в view → BasePermission с has_object_permission — DRF-способ
- dumpdata без флагов → dumpdata --exclude contenttypes --exclude auth.permission — безопаснее для восстановления
- router.register + as_view() → зависит от типа ViewSet: ModelViewSet регистрируется только через router
1. Документация API: drf-yasg vs drf-spectacular
Из лекции (drf-yasg)
# pip install drf-yasg
# OpenAPI 2.0 (Swagger)
INSTALLED_APPS = ['drf_yasg']
from drf_yasg.views import get_schema_view
from drf_yasg import openapi
schema_view = get_schema_view(
openapi.Info(title="API", default_version='v1'),
public=True,
)
# /swagger/ и /redoc/
Современный (drf-spectacular)
# pip install drf-spectacular
# OpenAPI 3.0 (актуальный стандарт)
INSTALLED_APPS = ['drf_spectacular']
REST_FRAMEWORK = {
'DEFAULT_SCHEMA_CLASS':
'drf_spectacular.openapi.AutoSchema',
}
# urls.py
from drf_spectacular.views import (
SpectacularAPIView,
SpectacularSwaggerView,
)
urlpatterns += [
path('api/schema/', SpectacularAPIView.as_view()),
path('api/docs/', SpectacularSwaggerView.as_view()),
]
Рекомендация: В данном практикуме используется
drf-yasg согласно источнику лекции. Для новых проектов предпочтительнее drf-spectacular с поддержкой OpenAPI 3.0.
⚠️ Проверить по документации: совместимость зависит от версии DRF и Django.
2. Проверка прав: ручная vs BasePermission
Устаревший (ручная проверка в view)
# Антипаттерн: логика прав в самом view
def update(self, request, pk=None):
order = Order.objects.get(pk=pk)
if order.customer != request.user:
return Response(
{'error': 'Forbidden'},
status=403
)
# ... логика обновления
Современный (BasePermission)
# permissions.py — переиспользуемо
class IsCustomerOrReadOnly(BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in ['GET', 'HEAD', 'OPTIONS']:
return True
return obj.customer == request.user
# view: чистая логика
class OrderDetailView(RetrieveUpdateDestroyAPIView):
permission_classes = [IsCustomerOrReadOnly]
queryset = Order.objects.all()
serializer_class = OrderSerializer
3. dumpdata: простой vs безопасный
Из лекции (базовый)
# Дамп всего
python manage.py dumpdata \
--indent=4 > db_backup.json
# Восстановление
python manage.py migrate
python manage.py loaddata db_backup.json
Современный (безопаснее для loaddata)
# Исключить проблемные таблицы
python manage.py dumpdata \
--exclude auth.permission \
--exclude contenttypes \
--indent=4 > db_backup.json
# Восстановление без конфликтов
python manage.py migrate
python manage.py loaddata db_backup.json
ContentType-конфликты возникают при восстановлении на другой БД или при изменении структуры приложений. Флаг
--exclude contenttypes помогает избежать этой проблемы.
⚠️ Проверить по документации: поведение зависит от структуры проекта и версии Django.
4. ModelViewSet: router vs as_view()
Из лекции (ModelViewSet с path)
# В лекции ModelViewSet
# регистрируется через path с as_view():
path('orders/', OrderListCreateView.as_view(),
name='orders'),
# Это работает только если OrderListCreateView
# НЕ является ModelViewSet
Правильно для ModelViewSet
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'orders', OrderListCreateView,
basename='order')
urlpatterns = [
path('', include(router.urls)),
]
# Или через as_view() с маппингом:
path('orders/', OrderListCreateView.as_view({
'get': 'list',
'post': 'create'
}), name='orders'),