Где в Django следует размещать бизнес-логику

Ответ

В Django придерживаются принципа "Fat Models, Thin Views" (Толстые модели, Тонкие представления). Бизнес-логику следует распределять по нескольким слоям, чтобы избежать ее концентрации во views.

Основные места для размещения бизнес-логики:

  1. Модели (models.py) Для логики, которая неразрывно связана с конкретным объектом модели. Это могут быть вычисляемые свойства или методы, изменяющие состояние объекта.

    # models.py
    class Order(models.Model):
        total = models.DecimalField(max_digits=10, decimal_places=2)
        is_paid = models.BooleanField(default=False)
    
        def mark_as_paid(self):
            """Логика, связанная с одним заказом."""
            if not self.is_paid:
                self.is_paid = True
                self.save()
  2. Менеджеры моделей (models.py) Для логики, которая оперирует набором объектов (QuerySet), а не одним экземпляром. Идеально для создания объектов со сложной логикой или для кастомных запросов.

    # models.py
    class OrderManager(models.Manager):
        def get_paid_orders(self):
            """Логика, работающая с коллекцией заказов."""
            return self.filter(is_paid=True)
    
    class Order(models.Model):
        # ...
        objects = OrderManager()
  3. Сервисный слой (например, services.py) Для сложной бизнес-логики, которая затрагивает несколько моделей, работает с внешними API или выполняет комплексные операции. Это помогает отделить логику от Django ORM.

    # services.py
    from .models import Order, User
    from external_api import payment_gateway
    
    def process_payment(order: Order, user: User):
        """Комплексная логика, затрагивающая несколько моделей и API."""
        if not order.is_paid:
            payment_gateway.charge(user.credit_card, order.total)
            order.mark_as_paid()
            # send_receipt_email(user)
  4. Формы и Сериализаторы (forms.py, serializers.py) Для логики, связанной исключительно с валидацией и очисткой данных, поступающих от пользователя.

Ключевое правило: Views должны оставаться «тонкими». Их задача — обработать HTTP-запрос, вызвать нужную бизнес-логику из моделей или сервисов и вернуть HTTP-ответ.

Ответ 18+ 🔞

Слушай, а вот этот ваш Django, он же, блядь, не дурак, у него там принцип есть — «Толстые модели, Тонкие представления». Это типа как в жизни: мозги должны быть в одном месте, а ебальник — в другом, а не наоборот. А то смотришь на некоторые вьюхи — там пиздец, на триста строк, и хуй поймёшь, что они делают, кроме как в сраку тебе всё отдают.

Так вот, куда эту самую бизнес-логику, сука, пихать, чтобы не было мучительно больно потом?

1. Модели (models.py) Сюда — всё, что привязано к одному конкретному объекту, как жопа к унитазу. Вычисляешь что-то или меняешь его состояние — делай метод прямо в модели.

# models.py
class Order(models.Model):
    total = models.DecimalField(max_digits=10, decimal_places=2)
    is_paid = models.BooleanField(default=False)

    def mark_as_paid(self):
        """Вот это логика, которая с одним заказом работает."""
        if not self.is_paid:
            self.is_paid = True
            self.save()  # И всё, блядь, красота!

2. Менеджеры моделей (тоже в models.py) А это уже для коллективщины. Нужно отфильтровать, сгруппировать или создать кучу объектов по какому-то своему, ебучему, правилу? Вот тебе менеджер, хуле.

# models.py
class OrderManager(models.Manager):
    def get_paid_orders(self):
        """А это логика, которая уже по всему стаду заказов идёт."""
        return self.filter(is_paid=True)  # Всё оплаченное — на бочку!

class Order(models.Model):
    # ...
    objects = OrderManager()  # И пользуйся, как родной

3. Сервисный слой (типа services.py) А вот это, блядь, тяжёлая артиллерия! Когда твоя логика начинает шастать между несколькими моделями, лезть в сторонние API или делать такую хуйню, от которой у ORM глаза на лоб лезут. Выноси её в отдельный файл, чтобы вьюха не превратилась в помойку.

# services.py
from .models import Order, User
from external_api import payment_gateway  # Вот эта, нахуй, сторонняя штука

def process_payment(order: Order, user: User):
    """Ну тут уже полный разгул: и API, и модели, и чёрт в ступе."""
    if not order.is_paid:
        payment_gateway.charge(user.credit_card, order.total)  *Тыц деньгами*
        order.mark_as_paid()
        # send_receipt_email(user)  # И письмецо на почту, ебанашка

4. Формы и Сериализаторы (forms.py, serializers.py) Ну а сюда — всю валидацию и чистку данных, которые от пользователя прилетают. Чтобы не держать эту грязь в основном потоке мысли.

И главное правило, ёпта: Вьюхи (views.py) должны быть тоньше волоса с жопы верблюда. Их работа — принять запрос, позвать нужную логику из моделек или сервисов, и отправить ответ. Не больше! А то получится, как у того Герасима, — всё в одном месте, и нихуя не понятно.