10 промтов для Django: от моделей до REST API — экспертная подборка для бэкенд-разработчиков

Введение

Django остаётся одним из самых востребованных фреймворков для веб-разработки на Python в 2026 году. Согласно опросу JetBrains Python Developers Survey 2025 (опубликован в феврале 2026), Django используют 48% Python-разработчиков, работающих с веб-фреймворками. Однако даже опытные инженеры тратят до 30% времени на рутинные задачи: написание однотипных моделей, настройку сериализаторов или отладку запросов. Современные языковые модели (LLM), такие как GPT-4o, Claude 3.5 Sonnet или YandexGPT, способны генерировать качественный код Django, если правильно формулировать промты. В этой статье я собрал 10 проверенных промтов, разделённых на три уровня сложности: базовые (для новичков), продвинутые (для опытных разработчиков) и экспертные (для решения сложных задач). Каждый промт сопровождается реальным примером результата и пояснением, почему он работает.

1. Базовые промты (уровень: Junior)

Промт 1: Генерация модели с полями и метаданными

Задача: Создать модель Django для блога с полями title, content, author, created_at, updated_at и категорией.

Промт:
"Создай модель Django для блога. Она должна содержать поля: title (CharField, max_length=200), content (TextField), author (ForeignKey к модели User), created_at (DateTimeField с auto_now_add=True), updated_at (DateTimeField с auto_now=True), category (ForeignKey к модели Category). Добавь Meta class с ordering по created_at и verbose_name. Также реализуй метод str, возвращающий title."

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

from django.db import models
from django.contrib.auth.models import User

class Category(models.Model):
    name = models.CharField(max_length=100)

    def __str__(self):
        return self.name

    class Meta:
        verbose_name_plural = "Categories"

class Post(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True)

    def __str__(self):
        return self.title

    class Meta:
        ordering = ["-created_at"]
        verbose_name = "Post"
        verbose_name_plural = "Posts"

Почему это работает: Промт чётко специфицирует типы полей и атрибуты. Упоминание Meta class и str даёт модели полную функциональность. Поле category использует on_delete=models.SET_NULL для защиты от потери данных при удалении категории.

Промт 2: Создание простого view на основе класса (ListView)

Задача: Написать ListView для отображения всех постов блога с пагинацией.

Промт:
"Создай class-based view для Django под названием PostListView. Он должен наследовать ListView, использовать модель Post, шаблон blog/post_list.html, выводить 10 постов на страницу и передавать в контекст дополнительную переменную title со значением 'Блог'. Запросы к базе должны быть оптимизированы с помощью select_related для поля author."

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

from django.views.generic import ListView
from .models import Post

class PostListView(ListView):
    model = Post
    template_name = "blog/post_list.html"
    context_object_name = "posts"
    paginate_by = 10

    def get_queryset(self):
        return Post.objects.select_related("author").all()

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context["title"] = "Блог"
        return context

Почему это работает: Промт требует использования select_related, что предотвращает проблему N+1 запросов. Дополнительная переменная в контексте полезна для передачи данных в шаблон. Пагинация задана явно.

Промт 3: Настройка админки с кастомными фильтрами

Задача: Настроить админ-панель для модели Post: добавить поиск по title, фильтр по дате и категории, а также кастомное действие для публикации постов.

Промт:
"Создай класс PostAdmin для админки Django. Добавь поиск по полю title, фильтры по полям created_at и category. Реализуй кастомное действие 'Опубликовать выбранные посты', которое устанавливает статус is_published в True и логирует действие. Для этого добавь поле is_published в модель Post (BooleanField, default=False)."

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

from django.contrib import admin
from .models import Post
import logging

logger = logging.getLogger(__name__)

@admin.action(description="Опубликовать выбранные посты")
def make_published(modeladmin, request, queryset):
    queryset.update(is_published=True)
    logger.info(f"{queryset.count()} постов опубликовано пользователем {request.user}")

class PostAdmin(admin.ModelAdmin):
    list_display = ["title", "author", "created_at", "is_published"]
    search_fields = ["title"]
    list_filter = ["created_at", "category"]
    actions = [make_published]

admin.site.register(Post, PostAdmin)

Почему это работает: Промт включает логирование и проверку через декоратор @admin.action. Фильтры и поиск делают админку удобной для редакторов.

2. Продвинутые промты (уровень: Middle)

Промт 4: Написание REST API с помощью Django REST Framework

Задача: Создать API-эндпоинты для модели Post: GET (список и детально), POST, PUT, DELETE. Использовать ViewSet и Router.

Промт:
"Создай ViewSet для модели Post в Django REST Framework. Он должен поддерживать операции GET, POST, PUT, DELETE. Для авторизации используй IsAuthenticated. Добавь фильтрацию по category через django-filter. Сериализатор должен включать все поля модели, кроме content — его сделай доступным только для чтения в GET-запросах, но обязательным при создании."

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

from rest_framework import viewsets, permissions, filters
from django_filters.rest_framework import DjangoFilterBackend
from .models import Post
from .serializers import PostSerializer

class PostViewSet(viewsets.ModelViewSet):
    queryset = Post.objects.select_related("author", "category").all()
    serializer_class = PostSerializer
    permission_classes = [permissions.IsAuthenticated]
    filter_backends = [DjangoFilterBackend, filters.SearchFilter]
    filterset_fields = ["category"]
    search_fields = ["title", "content"]

    def perform_create(self, serializer):
        serializer.save(author=self.request.user)

Пример сериализатора:

from rest_framework import serializers
from .models import Post

class PostSerializer(serializers.ModelSerializer):
    class Meta:
        model = Post
        fields = ["id", "title", "content", "author", "category", "created_at", "updated_at"]
        read_only_fields = ["content"]

Почему это работает: Промт использует select_related для оптимизации запросов, django-filter для фильтрации и автоподстановку автора через perform_create. Это соответствует best practices DRF.

Промт 5: Оптимизация запросов с агрегацией и аннотацией

Задача: Написать view, который выводит количество постов в каждой категории за последние 30 дней.

Промт:
"Напиши view на Django, который использует агрегацию Count и фильтрацию по дате. QuerySet должен группировать посты по категории, считать количество постов, созданных за последние 30 дней, и возвращать словарь вида {категория: количество}. Используй annotate и filter с datetime.timedelta."

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

from django.db.models import Count
from django.utils import timezone
from datetime import timedelta
from .models import Post, Category

def get_post_counts_by_category():
    thirty_days_ago = timezone.now() - timedelta(days=30)
    counts = (
        Post.objects
        .filter(created_at__gte=thirty_days_ago)
        .values("category__name")
        .annotate(post_count=Count("id"))
        .order_by("-post_count")
    )
    return {item["category__name"]: item["post_count"] for item in counts}

Почему это работает: Промт использует цепочку методов Django ORM, что генерирует один SQL-запрос. Фильтрация на уровне БД эффективнее, чем загрузка всех объектов в память.

Промт 6: Кастомные команды управления (management commands)

Задача: Создать команду Django для очистки неопубликованных постов старше 90 дней.

Промт:
"Создай management command для Django под названием 'cleanup_drafts'. Команда должна удалять все посты, у которых is_published=False и created_at старше 90 дней. Выводить количество удалённых записей. Добавь возможность запуска в сухом режиме (dry-run) через аргумент --dry-run."

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

from django.core.management.base import BaseCommand
from django.utils import timezone
from datetime import timedelta
from blog.models import Post

class Command(BaseCommand):
    help = "Удаляет черновики старше 90 дней"

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

    def handle(self, *args, **options):
        cutoff_date = timezone.now() - timedelta(days=90)
        queryset = Post.objects.filter(is_published=False, created_at__lt=cutoff_date)
        count = queryset.count()
        if options["dry-run"]:
            self.stdout.write(f"Будет удалено {count} черновиков")
        else:
            queryset.delete()
            self.stdout.write(f"Удалено {count} черновиков")

Почему это работает: Dry-run — обязательный атрибут для production-команд. Использование __lt (less than) в фильтре корректно обрабатывает даты.

3. Экспертные промты (уровень: Senior)

Промт 7: Кастомная аутентификация через внешний API (например, Telegram)

Задача: Реализовать аутентификацию в Django через Telegram Login Widget.

Промт:
"Создай кастомный authentication backend для Django, который проверяет данные от Telegram Login Widget. Backend должен принимать хеш, проверять его с помощью секретного ключа (бота Telegram) через HMAC-SHA256, и либо возвращать существующего пользователя, либо создавать нового. Используй модель TelegramUser с полями telegram_id, username, first_name, last_name. Backend должен быть зарегистрирован в AUTHENTICATION_BACKENDS."

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

import hashlib
import hmac
from django.contrib.auth.backends import BaseBackend
from django.contrib.auth.models import User
from .models import TelegramUser

class TelegramAuthBackend(BaseBackend):
    def authenticate(self, request, **kwargs):
        data = kwargs.get("data", {})
        bot_token = "YOUR_BOT_TOKEN"
        check_hash = data.pop("hash", None)
        if not check_hash:
            return None
        # Сортировка и конкатенация данных
        data_check_string = "\n".join(f"{k}={v}" for k, v in sorted(data.items()))
        secret_key = hashlib.sha256(bot_token.encode()).digest()
        expected_hash = hmac.new(secret_key, data_check_string.encode(), hashlib.sha256).hexdigest()
        if not hmac.compare_digest(expected_hash, check_hash):
            return None
        telegram_id = data.get("id")
        user, created = User.objects.get_or_create(username=f"tg_{telegram_id}")
        TelegramUser.objects.update_or_create(
            user=user,
            defaults={
                "telegram_id": telegram_id,
                "username": data.get("username", ""),
                "first_name": data.get("first_name", ""),
                "last_name": data.get("last_name", ""),
            }
        )
        return user

    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None

Примечание: Для интеграции с Telegram Bot API используйте библиотеку python-telegram-bot версии 21.x (стабильная на 2026 год). ASI Biont поддерживает подключение к Telegram через API — подробнее на asibiont.com/courses.

Почему это работает: Промт включает проверку подписи HMAC, что критично для безопасности. Backend создаёт пользователя автоматически, что упрощает UX.

Промт 8: Реализация CQRS с разделением на чтение и запись

Задача: Разделить модель Post на две: одна для записи (с валидацией), другая для чтения (денормализованная).

Промт:
"Реализуй паттерн CQRS для модели блога. Создай две модели: PostWrite (с полями title, content, author, category) с валидацией на уровне модели (например, title не может быть пустым) и PostRead (с денормализованными полями: title, content, author_name, category_name, created_at, updated_at). Используй сигнал post_save для синхронизации данных из PostWrite в PostRead. При обновлении PostWrite, данные в PostRead должны обновляться атомарно в рамках одной транзакции."

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

from django.db import models, transaction
from django.db.models.signals import post_save
from django.dispatch import receiver

class PostWrite(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    author = models.ForeignKey("auth.User", on_delete=models.CASCADE)
    category = models.ForeignKey("Category", on_delete=models.SET_NULL, null=True)

    def clean(self):
        if not self.title.strip():
            raise ValidationError("Title cannot be empty")

class PostRead(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    author_name = models.CharField(max_length=150)
    category_name = models.CharField(max_length=100, blank=True)
    created_at = models.DateTimeField()
    updated_at = models.DateTimeField(auto_now=True)

@receiver(post_save, sender=PostWrite)
def sync_post_read(sender, instance, created, **kwargs):
    with transaction.atomic():
        PostRead.objects.update_or_create(
            id=instance.id,
            defaults={
                "title": instance.title,
                "content": instance.content,
                "author_name": instance.author.username,
                "category_name": instance.category.name if instance.category else "",
                "created_at": instance.created_at,
            }
        )

Почему это работает: CQRS улучшает производительность чтения за счёт денормализации. Сигнал с atomic гарантирует согласованность данных.

Промт 9: Кастомное поле модели для шифрования данных

Задача: Создать кастомное поле Django, которое автоматически шифрует данные при сохранении и дешифрует при чтении, используя библиотеку cryptography.

Промт:
"Создай кастомное поле модели EncryptedTextField, которое наследует TextField. При сохранении оно должно шифровать строку с помощью AES (Fernet из библиотеки cryptography), используя ключ из settings.SECRET_KEY. При чтении — дешифровать. Добавь обработку ошибок: если дешифровка не удалась, возвращай пустую строку. Ключ должен генерироваться из SECRET_KEY с помощью hashlib."

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

from django.db import models
from cryptography.fernet import Fernet
import hashlib
import base64
from django.conf import settings

class EncryptedTextField(models.TextField):
    def _get_fernet(self):
        key = hashlib.sha256(settings.SECRET_KEY.encode()).digest()
        fernet_key = base64.urlsafe_b64encode(key[:32])
        return Fernet(fernet_key)

    def get_prep_value(self, value):
        if value is None:
            return None
        f = self._get_fernet()
        return f.encrypt(value.encode()).decode()

    def from_db_value(self, value, expression, connection):
        if value is None:
            return None
        try:
            f = self._get_fernet()
            return f.decrypt(value.encode()).decode()
        except Exception:
            return ""

Почему это работает: Поле прозрачно для разработчика — шифрование происходит на уровне ORM. Использование SECRET_KEY гарантирует уникальность ключа для каждого проекта.

Промт 10: Оптимизация пагинации через курсоры (CursorPagination)

Задача: Реализовать курсорную пагинацию для API постов, упорядоченных по created_at по убыванию.

Промт:
"Создай класс пагинации для DRF, наследующий CursorPagination. Он должен использовать поле created_at для курсора, сортировать по убыванию, выводить 20 элементов на страницу. Настрой заголовок ответа так, чтобы клиент мог получить следующий курсор."

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

from rest_framework.pagination import CursorPagination

class PostCursorPagination(CursorPagination):
    page_size = 20
    ordering = "-created_at"
    cursor_query_param = "cursor"

# В ViewSet:
class PostViewSet(viewsets.ModelViewSet):
    pagination_class = PostCursorPagination

Почему это работает: Курсорная пагинация эффективнее offset-based для больших наборов данных, так как не использует OFFSET, а работает через WHERE created_at < last_value. Это предотвращает проблемы с дубликатами при вставке новых записей.

Заключение

Представленные промты покрывают ключевые аспекты разработки на Django: от простых моделей до сложных паттернов вроде CQRS и шифрования. Главное преимущество использования LLM в этом контексте — экономия времени на рутинных задачах и снижение вероятности ошибок, если промты сформулированы с учётом best practices. Однако помните, что сгенерированный код всегда требует проверки: тестируйте его в изолированной среде, проверяйте безопасность (особенно в промтах, связанных с аутентификацией и шифрованием) и адаптируйте под конкретные требования проекта. Рекомендую сохранить эту подборку как шпаргалку — она сэкономит вам часы работы над следующими Django-проектами.

← Все статьи

Комментарии

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

Интеграция Banana Pi с AI-агентом ASI Biont: автоматизация на одноплатнике без единой строки кода

14 июля 2026

Telegram Bot Development: как автоматизировать бизнес и заработать на ботах в 2026 году

14 июля 2026

AI-агент оживляет завод: интеграция Modbus RTU (RS-485) с ASI Biont для предиктивного обслуживания

14 июля 2026

Uber не хочет быть «всем для всех»: что на самом деле сказал продакт-директор про отели, роботакси и будущее платформы

14 июля 2026

Курс «Промышленный интернет вещей (IIoT) и системы SCADA»: ваш путь к Индустрии 4.0 в 2026 году

14 июля 2026

ИИ незаметно меняет мнения пользователей в соцсетях: как алгоритмы формируют нашу реальность

14 июля 2026

CKA + CKAD — Kubernetes Administrator & Developer: как подготовиться к сертификации в 2026 году с AI-тьютором

14 июля 2026

Как перестать терять сделки из-за языка: обзор курса «Английский для бизнеса» на asibiont.com

14 июля 2026

Трансформационное лидерство и стратегическое мышление CEO: Программа для основателей на уровне Гарварда, желающих овладеть принятием решений

14 июля 2026