15 промтов для Django: от моделей до REST API — ускорьте разработку бэкенда

Django остаётся одним из самых популярных фреймворков для бэкенд-разработки на Python. По данным опроса JetBrains Developer Ecosystem Survey 2025, Django используют 48% Python-разработчиков, работающих с веб-фреймворками. Но даже опытные разработчики тратят до 30% времени на написание шаблонного кода: сериализаторов, представлений, тестов и конфигураций. Эта подборка промтов — не магическая таблетка, а инструмент, который помогает быстрее генерировать качественные заготовки. Каждый промт спроектирован так, чтобы вы получали не просто код, а готовый к интеграции модуль с учётом лучших практик Django (DRY, Fat Models, Thin Views).

1. Модель с кастомными методами и менеджером

Задача: Создать модель Order с полями (customer, total, status, created_at), кастомным менеджером для фильтрации активных заказов и методом для расчёта налога.

Промт:

Создай модель Django для заказа (Order) с полями: customer (ForeignKey на User), total (DecimalField), status (CharField с выбором из 'pending', 'paid', 'cancelled'), created_at (DateTimeField auto_now_add). Добавь кастомный менеджер ActiveOrdersManager, который фильтрует заказы со статусом 'paid'. Реализуй метод calculate_tax(self, rate=0.2), который возвращает сумму налога. Используй Python 3.11+, Django 5.0, типизованные аннотации.

Пример результата (фрагмент):

from django.db import models
from django.conf import settings
from typing import Literal

class ActiveOrdersManager(models.Manager):
    def get_queryset(self) -> models.QuerySet:
        return super().get_queryset().filter(status='paid')

class Order(models.Model):
    class Status(models.TextChoices):
        PENDING = 'pending', 'Ожидает'
        PAID = 'paid', 'Оплачен'
        CANCELLED = 'cancelled', 'Отменён'

    customer = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name='orders'
    )
    total = models.DecimalField(max_digits=10, decimal_places=2)
    status = models.CharField(
        max_length=10,
        choices=Status.choices,
        default=Status.PENDING
    )
    created_at = models.DateTimeField(auto_now_add=True)

    objects = models.Manager()
    active_objects = ActiveOrdersManager()

    def calculate_tax(self, rate: float = 0.2) -> float:
        return float(self.total) * rate

    def __str__(self) -> str:
        return f'Order #{self.pk} by {self.customer.username}'

Пояснение: Такой промт даёт модель с разделением ответственности: бизнес-логика в методах (calculate_tax), кастомные выборки через менеджеры. Это соответствует принципу Fat Models, рекомендованному в документации Django (https://docs.djangoproject.com/en/5.0/topics/db/managers/). Не забудьте заменить settings.AUTH_USER_MODEL на свою модель пользователя.

2. CBV для CRUD с пагинацией и поиском

Задача: Написать Class-Based View для списка товаров с пагинацией (20 элементов на страницу), поиском по названию и фильтрацией по категории.

Промт:

Создай Django ListView для модели Product. Включи пагинацию на 20 элементов, добавь поиск по полю 'name' через GET-параметр 'q', и фильтрацию по внешнему ключу 'category' через параметр 'category_id'. Используй generic-класс ListView и миксины. Выведи результат с контекстом: page_obj, search_query, selected_category.

Пример результата:

from django.views.generic import ListView
from django.db.models import Q
from .models import Product, Category

class ProductListView(ListView):
    model = Product
    template_name = 'catalog/product_list.html'
    context_object_name = 'products'
    paginate_by = 20

    def get_queryset(self):
        queryset = super().get_queryset()
        search_query = self.request.GET.get('q', '').strip()
        category_id = self.request.GET.get('category_id')

        if search_query:
            queryset = queryset.filter(name__icontains=search_query)
        if category_id:
            queryset = queryset.filter(category_id=category_id)

        return queryset.select_related('category').only(
            'name', 'price', 'category__name'
        )

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['search_query'] = self.request.GET.get('q', '')
        context['selected_category'] = self.request.GET.get('category_id')
        context['categories'] = Category.objects.all()
        return context

Пояснение: Использование select_related и only уменьшает количество запросов к БД. Это особенно важно для страниц каталога. DTL-шаблон может использовать page_obj для навигации. Подход соответствует DRY: вы не пишете пагинацию вручную.

3. DRF ViewSet с фильтрацией и сортировкой

Задача: Создать ViewSet для модели Article с полями title, content, author, created_at. Реализовать фильтрацию по автору (через django-filter), сортировку по дате и поиск по заголовку.

Промт:

Напиши DRF ViewSet для модели Article. Используй ModelViewSet, подключи django-filter для фильтрации по полю author (email), добавь возможность сортировки по created_at через OrderingFilter, и поиск по title через SearchFilter. Укажи permission_classes = [IsAuthenticatedOrReadOnly].

Пример результата:

from rest_framework import viewsets, filters
from django_filters.rest_framework import DjangoFilterBackend
from .models import Article
from .serializers import ArticleSerializer

class ArticleViewSet(viewsets.ModelViewSet):
    queryset = Article.objects.select_related('author').all()
    serializer_class = ArticleSerializer
    permission_classes = [IsAuthenticatedOrReadOnly]
    filter_backends = [
        DjangoFilterBackend,
        filters.SearchFilter,
        filters.OrderingFilter
    ]
    filterset_fields = ['author__email']
    search_fields = ['title']
    ordering_fields = ['created_at', 'title']
    ordering = ['-created_at']

Пояснение: DRF ViewSet с бэкендами фильтрации — стандарт в индустрии. Согласно документации DRF (https://www.django-rest-framework.org/api-guide/filtering/), такой подход сокращает код на 40% по сравнению с ручной реализацией. select_related предотвращает N+1 проблему.

4. Кастомный middleware для логирования запросов

Задача: Написать middleware, который логирует метод, путь и время выполнения каждого HTTP-запроса.

Промт:

Создай Django middleware, который для каждого входящего запроса записывает в лог (logging.info) метод, путь и время обработки в миллисекундах. Используй process_view или __call__ для совместимости с Django 5.0. Лог должен быть структурированным: 'METHOD PATH - Xms'.

Пример результата:

import time
import logging
from django.utils.deprecation import MiddlewareMixin

logger = logging.getLogger(__name__)

class RequestLoggingMiddleware(MiddlewareMixin):
    def process_view(self, request, view_func, view_args, view_kwargs):
        request._start_time = time.time()
        return None

    def process_response(self, request, response):
        if hasattr(request, '_start_time'):
            duration = (time.time() - request._start_time) * 1000
            logger.info(
                f'{request.method} {request.get_full_path()} - {duration:.0f}ms'
            )
        return response

Пояснение: Middleware — мощный механизм Django. Этот пример использует MiddlewareMixin для обратной совместимости. Логирование времени помогает выявлять медленные эндпоинты. Настройте уровень логирования в settings.py.

5. Кастомный менеджер с агрегацией

Задача: Создать менеджер для модели Product, который возвращает топ-10 самых продаваемых товаров за последние 30 дней.

Промт:

Добавь в модель Product кастомный менеджер TopSalesManager с методом top_selling(days=30, limit=10), который через related_name 'order_items' (модель OrderItem с полем quantity) агрегирует сумму quantity, группирует по product_id, сортирует по убыванию и возвращает limit записей. Используй annotate и Sum.

Пример результата:

from django.db import models
from django.db.models import Sum
from django.utils import timezone
from datetime import timedelta

class TopSalesManager(models.Manager):
    def top_selling(self, days: int = 30, limit: int = 10):
        cutoff_date = timezone.now() - timedelta(days=days)
        return self.get_queryset().filter(
            order_items__created_at__gte=cutoff_date
        ).annotate(
            total_sold=Sum('order_items__quantity')
        ).order_by('-total_sold')[:limit]

Пояснение: Агрегация на уровне менеджера — пример паттерна QuerySet reuse. Вызов Product.objects.top_selling() возвращает готовый QuerySet. Обратите внимание: предполагается, что модель OrderItem имеет поле created_at и product как ForeignKey с related_name='order_items'.

6. Сериализатор с вложенными объектами и валидацией

Задача: Написать DRF-сериализатор для заказа, включающий вложенные позиции и кастомную валидацию минимальной суммы.

Промт:

Создай сериализатор OrderSerializer для модели Order с полями id, customer (email), total, items (вложенный список OrderItemSerializer). OrderItemSerializer должен содержать product (name, price), quantity, subtotal (calculated field). Добавь валидацию: total не может быть меньше 10. Используя SerializerMethodField для subtotal и PrimaryKeyRelatedField для customer.

Пример результата:

from rest_framework import serializers
from .models import Order, OrderItem

class OrderItemSerializer(serializers.ModelSerializer):
    product_name = serializers.CharField(source='product.name', read_only=True)
    product_price = serializers.DecimalField(
        source='product.price', max_digits=10, decimal_places=2, read_only=True
    )
    subtotal = serializers.SerializerMethodField()

    class Meta:
        model = OrderItem
        fields = ['id', 'product', 'product_name', 'product_price', 
                  'quantity', 'subtotal']

    def get_subtotal(self, obj):
        return float(obj.product.price) * obj.quantity

class OrderSerializer(serializers.ModelSerializer):
    items = OrderItemSerializer(many=True, read_only=True)
    customer_email = serializers.EmailField(source='customer.email', read_only=True)

    class Meta:
        model = Order
        fields = ['id', 'customer', 'customer_email', 'total', 'items', 'created_at']

    def validate_total(self, value):
        if value < 10:
            raise serializers.ValidationError('Сумма заказа не может быть менее 10')
        return value

Пояснение: Вложенные сериализаторы — стандарт для REST API. source позволяет извлекать данные из связанных моделей без дополнительных запросов. Валидация на уровне сериализатора гарантирует целостность данных.

7. Сигнал для создания профиля при регистрации

Задача: Автоматически создавать профиль пользователя при создании экземпляра User.

Промт:

Напиши Django сигнал post_save для модели User, который при создании нового пользователя (created=True) создаёт связанную модель Profile с полями bio (TextField, blank=True) и avatar (ImageField, upload_to='avatars/'). Используй @receiver декоратор. Обработай случай, если Profile уже существует (update_or_create).

Пример результата:

from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib.auth.models import User
from .models import Profile

@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(user=instance)
    else:
        instance.profile.save()

Пояснение: Сигналы — ключевой паттерн для поддержания согласованности данных. Альтернатива — переопределение save() модели User, но сигналы менее инвазивны. Подробнее в документации: https://docs.djangoproject.com/en/5.0/topics/signals/.

8. Кастомная команда управления для очистки старых записей

Задача: Создать management command, которая удаляет неоплаченные заказы старше 7 дней.

Промт:

Напиши Django management command 'cleanup_orders', которая удаляет все заказы со статусом 'pending', созданные более 7 дней назад. Используй BaseCommand, добавь аргумент --dry-run для вывода количества заказов без удаления. Логируй результат через self.stdout.

Пример результата:

from django.core.management.base import BaseCommand
from django.utils import timezone
from datetime import timedelta
from orders.models import Order

class Command(BaseCommand):
    help = 'Удаляет неоплаченные заказы старше 7 дней'

    def add_arguments(self, parser):
        parser.add_argument(
            '--dry-run',
            action='store_true',
            help='Показать количество заказов без удаления'
        )

    def handle(self, *args, **options):
        cutoff = timezone.now() - timedelta(days=7)
        orders = Order.objects.filter(
            status='pending',
            created_at__lt=cutoff
        )
        count = orders.count()

        if options['dry_run']:
            self.stdout.write(f'Будет удалено {count} заказов')
            return

        orders.delete()
        self.stdout.write(self.style.SUCCESS(f'Удалено {count} заказов'))

Пояснение: Management commands — стандартный способ автоматизации задач в Django. --dry-run — хорошая практика для опасных операций. Запуск через python manage.py cleanup_orders.

9. Пагинация в DRF с кастомным ответом

Задача: Настроить пагинацию для API так, чтобы ответ содержал next, previous, count и results, но с добавлением поля total_pages.

Промт:

Создай кастомный класс пагинации для DRF, наследующий PageNumberPagination. Переопредели get_paginated_response, чтобы включить поле total_pages. Установи page_size = 10.

Пример результата:

from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response
from math import ceil

class CustomPagination(PageNumberPagination):
    page_size = 10
    page_size_query_param = 'page_size'
    max_page_size = 100

    def get_paginated_response(self, data):
        total_pages = ceil(self.page.paginator.count / self.page_size)
        return Response({
            'count': self.page.paginator.count,
            'total_pages': total_pages,
            'next': self.get_next_link(),
            'previous': self.get_previous_link(),
            'results': data
        })

Пояснение: Кастомная пагинация улучшает UX для клиентов API. Поле total_pages упрощает построение интерфейса пагинации на фронтенде. Подключите через DEFAULT_PAGINATION_CLASS в settings.

10. Тесты для модели и API

Задача: Написать тесты для модели Order и её методов, а также для эндпоинта списка заказов.

Промт:

Создай тестовый класс для модели Order: проверь создание заказа, работу метода calculate_tax и кастомного менеджера active_objects. Затем напиши тест для API (APITestCase) — проверь, что GET /api/orders/ возвращает 200 и содержит только активные заказы для аутентифицированного пользователя.

Пример результата:

from django.test import TestCase
from django.contrib.auth.models import User
from .models import Order
from decimal import Decimal

class OrderModelTest(TestCase):
    def setUp(self):
        self.user = User.objects.create_user(username='testuser', password='12345')
        self.order = Order.objects.create(
            customer=self.user,
            total=Decimal('100.00'),
            status='paid'
        )

    def test_calculate_tax(self):
        self.assertEqual(self.order.calculate_tax(0.2), 20.0)

    def test_active_manager(self):
        Order.objects.create(customer=self.user, total=50, status='pending')
        self.assertEqual(Order.active_objects.count(), 1)

Пояснение: Тесты — основа надёжности. Встроенный TestCase Django покрывает базу данных. Для API используйте rest_framework.test.APITestCase. Подробнее: https://docs.djangoproject.com/en/5.0/topics/testing/.

11. Админка с InlineModelAdmin и кастомными действиями

Задача: Настроить админку для модели Order, добавив inline для OrderItem и действие для массовой смены статуса на 'cancelled'.

Промт:

Создай ModelAdmin для Order: отобрази поля id, customer, total, status, created_at. Добавь TabularInline для OrderItem. Реализуй action 'mark_as_cancelled', который меняет статус выбранных заказов на 'cancelled' и выводит сообщение об успехе.

Пример результата:

from django.contrib import admin
from .models import Order, OrderItem

class OrderItemInline(admin.TabularInline):
    model = OrderItem
    extra = 1

@admin.action(description='Отметить как отменённые')
def mark_as_cancelled(modeladmin, request, queryset):
    queryset.update(status='cancelled')

@admin.register(Order)
class OrderAdmin(admin.ModelAdmin):
    list_display = ['id', 'customer', 'total', 'status', 'created_at']
    list_filter = ['status', 'created_at']
    search_fields = ['customer__username', 'id']
    inlines = [OrderItemInline]
    actions = [mark_as_cancelled]

Пояснение: Inline-редактирование ускоряет работу с заказами. Кастомные действия — мощный инструмент для массовых операций. Документация: https://docs.djangoproject.com/en/5.0/ref/contrib/admin/actions/.

12. Миграция данных с помощью RunPython

Задача: Написать миграцию, которая заполняет поле slug для всех существующих статей на основе заголовка.

Промт:

Создай пустую миграцию Django, которая использует RunPython для генерации slug для всех статей, у которых slug пустой. Используй функцию slugify из django.utils.text. Обработай дубликаты, добавляя суффикс '-1', '-2' и т.д.

Пример результата:

from django.db import migrations
from django.utils.text import slugify

def generate_slugs(apps, schema_editor):
    Article = apps.get_model('blog', 'Article')
    for article in Article.objects.filter(slug__isnull=True):
        base_slug = slugify(article.title)[:50]
        slug = base_slug
        counter = 1
        while Article.objects.filter(slug=slug).exclude(pk=article.pk).exists():
            slug = f'{base_slug}-{counter}'
            counter += 1
        article.slug = slug
        article.save(update_fields=['slug'])

class Migration(migrations.Migration):
    dependencies = [
        ('blog', '0001_initial'),
    ]
    operations = [
        migrations.RunPython(generate_slugs),
    ]

Пояснение: Data migrations безопаснее, чем скрипты, так как выполняются в транзакции. Используйте apps.get_model, а не прямой импорт — это гарантирует корректную работу с историческими состояниями моделей.

13. Настройка CORS в DRF

Задача: Разрешить кросс-доменные запросы для API, ограничив список разрешённых источников.

Промт:

Настрой CORS для Django-приложения, используя django-cors-headers. Разреши запросы только с доменов https://frontend.example.com и http://localhost:3000. Разреши все методы и заголовки для CORS-запросов.

Пример результата (в settings.py):

INSTALLED_APPS = [
    ...
    'corsheaders',
]

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    ...
]

CORS_ALLOWED_ORIGINS = [
    'https://frontend.example.com',
    'http://localhost:3000',
]

CORS_ALLOW_METHODS = [
    'DELETE',
    'GET',
    'OPTIONS',
    'PATCH',
    'POST',
    'PUT',
]

CORS_ALLOW_HEADERS = [
    'accept',
    'authorization',
    'content-type',
    'x-csrftoken',
]

Пояснение: Без настройки CORS фронтенд на другом домене не сможет делать запросы к API. django-cors-headers — стандартное решение. Всегда ограничивайте origins в продакшене.

14. Оптимизация запросов с select_related и prefetch_related

Задача: Оптимизировать запрос списка заказов с N+1 проблемой.

Промт:

Напиши queryset для получения всех заказов за последний месяц, включая данные о покупателе и все позиции заказа (OrderItem с продуктами). Используй select_related для ForeignKey customer и prefetch_related для обратной связи items__product. Выведи результат в виде списка словарей.

Пример результата:

from django.utils import timezone
from datetime import timedelta
from .models import Order

cutoff = timezone.now() - timedelta(days=30)
orders = Order.objects.filter(
    created_at__gte=cutoff
).select_related(
    'customer'
).prefetch_related(
    'items__product'
)

result = []
for order in orders:
    result.append({
        'id': order.id,
        'customer_email': order.customer.email,
        'items': [
            {
                'product_name': item.product.name,
                'quantity': item.quantity
            }
            for item in order.items.all()
        ]
    })

Пояснение: N+1 проблема — одна из частых причин тормозов. select_related работает для ForeignKey (JOIN), prefetch_related — для ManyToMany и обратных связей (отдельный запрос). Это сокращает количество запросов с 1+N до 3.

15. Кастомный TemplateTag для форматирования дат

Задача: Создать template tag, который выводит дату в формате 'день месяц год' на русском языке.

Промт:

Создай inclusion tag или simple tag под названием 'ru_date', который принимает дату (datetime) и возвращает строку вида '23 июля 2026'. Используй библиотеку pytz или django.utils.timezone для локализации. Зарегистрируй в библиотеке тегов.

Пример результата:

from django import template
from django.utils import timezone
from datetime import datetime

register = template.Library()

MONTHS = {
    1: 'января', 2: 'февраля', 3: 'марта', 4: 'апреля',
    5: 'мая', 6: 'июня', 7: 'июля', 8: 'августа',
    9: 'сентября', 10: 'октября', 11: 'ноября', 12: 'декабря'
}

@register.simple_tag
def ru_date(value):
    if isinstance(value, datetime):
        local_dt = timezone.localtime(value)
        return f'{local_dt.day} {MONTHS[local_dt.month]} {local_dt.year}'
    return ''

Пояснение: Кастомные template tags расширяют возможности шаблонизатора. Используйте timezone.localtime для корректного учёта часового пояса. Подключите в шаблоне: {% load ru_date_tags %}.

Заключение

Эти 15 промтов покрывают ключевые аспекты разработки на Django: от моделей и запросов до REST API и админки. Каждый промт — не просто шаблон, а пример, который можно адаптировать под свой проект. Помните: промты экономят время на рутине, но не заменяют понимания архитектуры Django. Регулярно просматривайте официальную документацию (https://docs.djangoproject.com/en/5.0/) и следите за нововведениями в DRF (https://www.django-rest-framework.org/). Начните с малого: возьмите один промт, примените в своём проекте и увидите разницу в скорости разработки. Успешного кодинга!

← Все статьи

Комментарии

Читайте также

Как сдать CISA за 4 месяца: практический опыт IT-аудитора и обзор курса на Asibiont.com

23 июля 2026

Интеграция Docker Compose с AI-агентом ASI Biont: автоматизация DevOps без кода

23 июля 2026

System Design Interview: Как пройти FAANG-собеседование и не сойти с ума

23 июля 2026

Как ASI Biont автоматизирует Google Ads через AI-агента: экономия времени и бюджета без кода

23 июля 2026

Git-флаг `--end-of-options`: как защитить скрипты от «отравленных» аргументов в 2026 году

23 июля 2026

Книга «Системная инженерия: современные методы проектирования для создания сложных информационных систем. 2-е изд.» — обзор обновлённого издания

23 июля 2026

Docker и Kubernetes: как DevOps-навыки 2026 меняют продакшн и почему обучение на AI — это новый стандарт

23 июля 2026

Как AI-агент ASI Biont превращает SQLite в движок аналитики без кода: интеграция, которая экономит 20 часов в неделю

23 июля 2026

Azure Solutions Architect — Expert (AZ-305): Почему этот курс станет вашим катализатором карьеры в облаке в 2026 году

23 июля 2026