Разделение бизнес-логики и доступа к данным в Django

279

Я пишу проект в Django, и я вижу, что 80% кода находится в файле models.py. Этот код запутан, и через некоторое время я перестаю понимать, что на самом деле происходит.

Вот что меня беспокоит:

  • Я считаю уродливым, что мой уровень модели (который должен был быть ответственный только за работу с данными из базы данных) также отправка электронной почты, переход по API на другие службы и т.д.
  • Кроме того, я считаю неприемлемым размещать бизнес-логику в представлении, потому что таким образом становится трудно контролировать. Например, в моем приложения существует как минимум три способа создания новых экземпляры User, но технически они должны создавать их равномерно.
  • Я не всегда замечаю, когда методы и свойства моих моделей становятся недетерминированными и когда они развиваются побочные эффекты.

Вот простой пример. Сначала модель User была такой:

class User(db.Models):

    def get_present_name(self):
        return self.name or 'Anonymous'

    def activate(self):
        self.status = 'activated'
        self.save()

Со временем это превратилось в это:

class User(db.Models):

    def get_present_name(self): 
        # property became non-deterministic in terms of database
        # data is taken from another service by api
        return remote_api.request_user_name(self.uid) or 'Anonymous' 

    def activate(self):
        # method now has a side effect (send message to user)
        self.status = 'activated'
        self.save()
        send_mail('Your account is activated!', '…', [self.email])

Я хочу отделить объекты в моем коде:

  • Объекты моей базы данных, уровень базы данных: что содержит мое приложение?
  • Объекты моего приложения, уровень бизнес-логики: что может сделать мое приложение?

Каковы наилучшие методы реализации такого подхода, который может быть применен в Django?

  • 10
    Читайте о сигналах
  • 1
    ну, вы удалили тег, но вы могли бы использовать DCI, чтобы увидеть разделение того, что делает система (функциональность) и что такое система (модель данных / предметной области)
Показать ещё 3 комментария
Теги:
model-view-controller
data-access-layer
business-logic-layer

8 ответов

400
Лучший ответ

Похоже, вы спрашиваете о различии между моделью данных и моделью домена - последняя - это то, где вы можете найти бизнес-логику и сущности, воспринимаемые вашим конечным пользователем, первая - это то место, где вы фактически храните свои данные.

Кроме того, я интерпретировал третью часть вашего вопроса как: как заметить отказ в том, чтобы держать эти модели в отдельности.

Это две совершенно разные концепции, и всегда трудно их разделить. Однако существуют некоторые общие шаблоны и инструменты, которые можно использовать для этой цели.

О модели домена

Первое, что вам нужно признать, это то, что ваша модель домена не имеет отношения к данным; речь идет о действиях и таких вопросах, как "активировать этого пользователя", "деактивировать этого пользователя", "какие пользователи в настоящее время активированы?" и "что это за имя пользователя?". В классических терминах: это о запросах и командах.

Мышление в командах

Давайте начнем с рассмотрения команд в вашем примере: "активировать этого пользователя" и "деактивировать этого пользователя". Самое приятное в командах состоит в том, что они легко могут быть выражены небольшим сценарием "когда-то":

данный неактивный пользователь
, когда администратор активирует этого пользователя
, затем пользователь становится активным
и отправляется подтверждение электронной почты пользователю
и в системный журнал добавляется запись
 (и т.д.).

Такой сценарий полезен для того, чтобы увидеть, как разные части вашей инфраструктуры могут быть затронуты одной командой - в этом случае ваша база данных (какой-то "активный" флаг), ваш почтовый сервер, системный журнал и т.д.

Такой сценарий также действительно поможет вам в создании тестовой среды разработки.

И, наконец, мышление в командах действительно помогает вам создать ориентированное на задачи приложение. Ваши пользователи оценят это: -)

Выражение команд

Django предоставляет два простых способа выражения команд; они оба являются действительными вариантами, и нет ничего необычного в смешивании двух подходов.

Сервисный уровень

Сервисный модуль уже был описанный @Hedde. Здесь вы определяете отдельный модуль, и каждая команда представляется как функция.

services.py

def activate_user(user_id):
    user = User.objects.get(pk=user_id)

    # set active flag
    user.active = True
    user.save()

    # mail user
    send_mail(...)

    # etc etc

Использование форм

Другой способ - использовать Django Form для каждой команды. Я предпочитаю этот подход, потому что он сочетает в себе множество тесно связанных аспектов:

  • выполнение команды (что она делает?)
  • проверка параметров команды (может ли это сделать?)
  • представление команды (как я могу это сделать?)

forms.py

class ActivateUserForm(forms.Form):

    user_id = IntegerField(widget = UsernameSelectWidget, verbose_name="Select a user to activate")
    # the username select widget is not a standard Django widget, I just made it up

    def clean_user_id(self):
        user_id = self.cleaned_data['user_id']
        if User.objects.get(pk=user_id).active:
            raise ValidationError("This user cannot be activated")
        # you can also check authorizations etc. 
        return user_id

    def execute(self):
        """
        This is not a standard method in the forms API; it is intended to replace the 
        'extract-data-from-form-in-view-and-do-stuff' pattern by a more testable pattern. 
        """
        user_id = self.cleaned_data['user_id']

        user = User.objects.get(pk=user_id)

        # set active flag
        user.active = True
        user.save()

        # mail user
        send_mail(...)

        # etc etc

Мышление в запросах

Вы, например, не содержали никаких запросов, поэтому я взял на себя смелость составить несколько полезных запросов. Я предпочитаю использовать термин "вопрос", но запросы - классическая терминология. Интересные запросы: "Как называется этот пользователь?", "Может ли этот пользователь войти?", "Показать список отключенных пользователей" и "Каково географическое распределение деактивированных пользователей?"

Прежде чем приступать к ответам на эти запросы, вы должны всегда задавать себе два вопроса: это презентационный запрос только для моих шаблонов и/или бизнес-логический запрос, связанный с выполнением моих команд, и/или отчетный запрос.

Презентационные запросы просто сделаны для улучшения пользовательского интерфейса. Ответы на запросы бизнес-логики напрямую влияют на выполнение ваших команд. Запросы отчетности предназначены только для аналитических целей и имеют ограниченные временные ограничения. Эти категории не являются взаимоисключающими.

Другой вопрос: "Я полностью контролирую ответы?" Например, при запросе имени пользователя (в этом контексте) мы не имеем никакого контроля над результатом, потому что мы полагаемся на внешний API.

Выполнение запросов

Самый простой запрос в Django - это использование объекта Manager:

User.objects.filter(active=True)

Конечно, это работает только в том случае, если данные действительно представлены в вашей модели данных. Это не всегда так. В этих случаях вы можете рассмотреть варианты ниже.

Пользовательские теги и фильтры

Первый вариант полезен для запросов, которые являются просто презентационными: пользовательские теги и фильтры шаблонов.

template.html

<h1>Welcome, {{ user|friendly_name }}</h1>

template_tags.py

@register.filter
def friendly_name(user):
    return remote_api.get_cached_name(user.id)

Методы запросов

Если ваш запрос не просто презентационный, вы можете добавить запросы к services.py (если вы используете это) или добавить модуль queries.py:

queries.py

def inactive_users():
    return User.objects.filter(active=False)


def users_called_publysher():
    for user in User.objects.all():
        if remote_api.get_cached_name(user.id) == "publysher":
            yield user 

Прокси-модели

Прокси-модели очень полезны в контексте бизнес-логики и отчетности. В основном вы определяете расширенный поднабор вашей модели.

models.py

class InactiveUserManager(models.Manager):
    def get_query_set(self):
        query_set = super(InactiveUserManager, self).get_query_set()
        return query_set.filter(active=False)

class InactiveUser(User):
    """
    >>> for user in InactiveUser.objects.all():
    …        assert user.active is False 
    """

    objects = InactiveUserManager()
    class Meta:
        proxy = True

Модели запросов

Для запросов, которые по своей сути сложны, но выполняются довольно часто, есть возможность моделей запросов. Модель запроса - это форма денормализации, где соответствующие данные для одного запроса хранятся в отдельной модели. Разумеется, трюк заключается в том, чтобы сохранить денормализованную модель в синхронизации с основной моделью. Модели запросов можно использовать только в том случае, если изменения полностью находятся под вашим контролем.

models.py

class InactiveUserDistribution(models.Model):
    country = CharField(max_length=200)
    inactive_user_count = IntegerField(default=0)

Первый вариант - обновить эти модели в ваших командах. Это очень полезно, если эти модели изменяются только одной или двумя командами.

forms.py

class ActivateUserForm(forms.Form):
    # see above

    def execute(self):
        # see above
        query_model = InactiveUserDistribution.objects.get_or_create(country=user.country)
        query_model.inactive_user_count -= 1
        query_model.save()

Лучшим вариантом было бы использование пользовательских сигналов. Ваши сигналы, конечно, испускаются вашими командами. Преимущество сигналов состоит в том, что вы можете синхронизировать несколько моделей запросов с исходной моделью. Кроме того, обработка сигналов может быть выгружена в фоновые задачи, используя Celery или аналогичные структуры.

signals.py

user_activated = Signal(providing_args = ['user'])
user_deactivated = Signal(providing_args = ['user'])

forms.py

class ActivateUserForm(forms.Form):
    # see above

    def execute(self):
        # see above
        user_activated.send_robust(sender=self, user=user)

models.py

class InactiveUserDistribution(models.Model):
    # see above

@receiver(user_activated)
def on_user_activated(sender, **kwargs):
        user = kwargs['user']
        query_model = InactiveUserDistribution.objects.get_or_create(country=user.country)
        query_model.inactive_user_count -= 1
        query_model.save()

Сохранение чистоты

При использовании этого подхода становится нелепо легко определить, остается ли ваш код чистым. Просто следуйте этим рекомендациям:

  • В моей модели содержатся методы, которые делают больше, чем управление состоянием базы данных? Вы должны извлечь команду.
  • В моей модели содержатся свойства, которые не отображаются в поля базы данных? Вы должны извлечь запрос.
  • Является ли моя эталонная инфраструктура моей модели не моей базой данных (например, почтой)? Вы должны извлечь команду.

То же самое относится к представлениям (поскольку представления часто страдают от одной и той же проблемы).

  • Является ли мой взгляд активным управлением моделями баз данных? Вы должны извлечь команду.

Некоторые ссылки

Документация Django: прокси-модели

Документация Django: сигналы

Архитектура: дизайн, управляемый доменом

  • 17
    Очень хороший ответ! Я перечитал это несколько раз :)
  • 0
    Очень проницательно! Один вопрос / проблема: эти предложения подразумевают, что вся обработка находится на веб-сайте django. Альтернативная архитектура - использовать django в качестве веб-интерфейса для уровня платформы бэкэнда (см. Lethain.com/introduction-to-architecting-systems-for-scale/… ). Этот уровень платформы позволяет запускать код за пределами платформы веб-сайта. Модель данных, модель предметной области, уровень обслуживания и т. Д. Будут находиться на уровне платформы. И, учитывая, что этот уровень находится за пределами django, можно использовать SQL Alchemy в качестве ORM для уровня платформы вместо django.
Показать ещё 6 комментариев
87

Обычно я использую сервисный уровень между представлениями и моделями. Это действует как ваш API проекта и дает вам хороший обзор вертолетов о том, что происходит. Я унаследовал эту практику от моего коллеги, который много использует эту технику наслаивания с Java-проектами (JSF), например:

models.py

class Book:
   author = models.ForeignKey(User)
   title = models.CharField(max_length=125)

   class Meta:
       app_label = "library"

services.py

from library.models import Book

def get_books(limit=None, **filters):
    """ simple service function for retrieving books can be widely extended """
    if limit:
        return Book.objects.filter(**filters)[:limit]
    return Book.objects.filter(**filters)

views.py

from library.services import get_books

class BookListView(ListView):
    """ simple view, e.g. implement a _build and _apply filters function """
    queryset = get_books()

Помните, я обычно беру модели, представления и службы на уровень модуля и отделить еще больше в зависимости от размера проекта

  • 5
    Мне нравится общий подход, хотя из моего понимания ваш конкретный пример обычно реализуется как менеджер .
  • 8
    @arie не обязательно, возможно, лучший пример, для услуг интернет-магазина будет включать такие вещи, как создание сеансов корзины, асинхронные задачи, такие как вычисление оценок продуктов, создание и отправка электронных писем и т. д.
Показать ещё 1 комментарий
50

Прежде всего, Не повторяйте.

Тогда, пожалуйста, будьте осторожны, чтобы не перерабатывать, иногда это просто пустая трата времени и заставляет кого-то потерять сосредоточение на том, что важно. Периодически проверяйте zen of python.

Взгляните на активные проекты

  • больше людей = больше нужно правильно организовать
  • репозиторий django, они имеют простую структуру.
  • репозиторий pip у них есть структура каталогов straigtforward.
  • репозиторий ткани также является хорошим, на что можно смотреть.

    • вы можете разместить все свои модели под yourapp/models/logicalgroup.py
  • e.g User, Group и связанные модели могут находиться под yourapp/models/users.py
  • e.g Poll, Question, Answer... может находиться под yourapp/models/polls.py
  • загрузите то, что вам нужно в __all__ внутри yourapp/models/__init__.py

Подробнее о MVC

  • Модель
  • - ваши данные
    • это включает в себя ваши фактические данные
    • это также включает данные сессии/файла cookie/cache/fs/index
  • пользователь взаимодействует с контроллером для управления моделью
    • это может быть API или представление, которое сохраняет/обновляет ваши данные.
    • это можно настроить с помощью request.GET/request.POST... и т.д.
    • подкачка или фильтрация.
  • данные обновляют представление
    • шаблоны берут данные и форматируют их соответственно.
    • API-интерфейсы даже без шаблонов являются частью представления; например tastypie или piston
    • это также должно учитывать промежуточное программное обеспечение.

Воспользуйтесь middleware/templatetags

  • Если вам потребуется какая-то работа для каждого запроса, промежуточное ПО - это один из способов.
    • например. добавление временных меток
    • например. обновление метрик о просмотрах страниц
    • например. заполнение кеша
  • Если у вас есть фрагменты кода, которые всегда повторяются для форматирования объектов, templatetags хороши.
    • например. активные вкладки /url панировочные сундуки

Воспользуйтесь менеджерами моделей

  • Создание User может идти в UserManager(models.Manager).
  • gory детали для экземпляров должны идти на models.Model.
  • gory детали для queryset могут идти в models.Manager.
  • вам может понадобиться создать User по одному, так что вы можете подумать, что он должен жить на самой модели, но при создании объекта вы, вероятно, не имеете всех подробностей:

Пример:

class UserManager(models.Manager):
   def create_user(self, username, ...):
      # plain create
   def create_superuser(self, username, ...):
      # may set is_superuser field.
   def activate(self, username):
      # may use save() and send_mail()
   def activate_in_bulk(self, queryset):
      # may use queryset.update() instead of save()
      # may use send_mass_mail() instead of send_mail()

Использовать формы, где это возможно

Многие шаблоны кода могут быть устранены, если у вас есть формы, которые сопоставляются с моделью. ModelForm documentation довольно хорош. Разделение кода для форм из кода модели может быть хорошим, если у вас много настроек (или иногда избегайте циклических ошибок импорта для более сложных применений).

Используйте команды управления, когда это возможно

  • например. yourapp/management/commands/createsuperuser.py
  • например. yourapp/management/commands/activateinbulk.py

Если у вас есть бизнес-логика, вы можете выделить ее

  • django.contrib.auth использует бэкэнды, так же как db имеет бэкэнд... и т.д.
  • добавить setting для вашей бизнес-логики (например, AUTHENTICATION_BACKENDS)
  • вы можете использовать django.contrib.auth.backends.RemoteUserBackend
  • вы можете использовать yourapp.backends.remote_api.RemoteUserBackend
  • вы можете использовать yourapp.backends.memcached.RemoteUserBackend
  • делегировать сложную бизнес-логику на бэкэнд
  • обязательно установите правильное значение ожидания на входе/выходе.
  • изменение бизнес-логики так же просто, как изменение настройки:)

пример бэкэнд:

class User(db.Models):
    def get_present_name(self): 
        # property became not deterministic in terms of database
        # data is taken from another service by api
        return remote_api.request_user_name(self.uid) or 'Anonymous' 

может стать:

class User(db.Models):
   def get_present_name(self):
      for backend in get_backends():
         try:
            return backend.get_present_name(self)
         except: # make pylint happy.
            pass
      return None

больше о шаблонах проектирования

больше о границах интерфейса

  • Является ли код, который вы хотите использовать на самом деле частью моделей? → yourapp.models
  • Является ли код частью бизнес-логики? → yourapp.vendor
  • Является ли код частью общих инструментов /libs? → yourapp.libs
  • Является ли частью кода бизнес-логики libs? → yourapp.libs.vendor или yourapp.vendor.libs
  • Вот хороший: можете ли вы проверить свой код самостоятельно?
    • да, хорошо:)
    • Нет, у вас может возникнуть проблема с интерфейсом
    • когда есть четкое разделение, unittest должен быть ветерок с использованием насмешек
  • Является ли разделение логическим?
    • да, хорошо:)
    • нет, может возникнуть проблема с тестированием этих логических понятий отдельно.
  • Как вы думаете, вам нужно будет реорганизовать, когда вы получите 10-кратный код?
    • да, нехорошо, нет bueno, рефактору может быть много работы.
    • Нет, это просто потрясающе!

Короче говоря, вы могли бы

  • yourapp/core/backends.py
  • yourapp/core/models/__init__.py
  • yourapp/core/models/users.py
  • yourapp/core/models/questions.py
  • yourapp/core/backends.py
  • yourapp/core/forms.py
  • yourapp/core/handlers.py
  • yourapp/core/management/commands/__init__.py
  • yourapp/core/management/commands/closepolls.py
  • yourapp/core/management/commands/removeduplicates.py
  • yourapp/core/middleware.py
  • yourapp/core/signals.py
  • yourapp/core/templatetags/__init__.py
  • yourapp/core/templatetags/polls_extras.py
  • yourapp/core/views/__init__.py
  • yourapp/core/views/users.py
  • yourapp/core/views/questions.py
  • yourapp/core/signals.py
  • yourapp/lib/utils.py
  • yourapp/lib/textanalysis.py
  • yourapp/lib/ratings.py
  • yourapp/vendor/backends.py
  • yourapp/vendor/morebusinesslogic.py
  • yourapp/vendor/handlers.py
  • yourapp/vendor/middleware.py
  • yourapp/vendor/signals.py
  • yourapp/tests/test_polls.py
  • yourapp/tests/test_questions.py
  • yourapp/tests/test_duplicates.py
  • yourapp/tests/test_ratings.py

или что-нибудь еще, что поможет вам; поиск интерфейсов, которые вам нужны, а границы помогут вам.

19

Django использует слегка модифицированный вид MVC. В Django нет понятия "контроллер". Самый близкий прокси - это "представление", которое, как правило, вызывает путаницу с конвертируемыми MVC, потому что в MVC вид больше похож на "шаблон" Django.

В Django "модель" - это не просто абстракция базы данных. В некоторых отношениях он разделяет обязанности с "представлением" Django в качестве контроллера MVC. Он содержит всю совокупность поведения, связанного с экземпляром. Если этому экземпляру необходимо взаимодействовать с внешним API как часть его поведения, то этот код все еще моделируется. На самом деле, модели не обязаны вообще взаимодействовать с базой данных, поэтому вы могли бы иметь модели, которые полностью существуют как интерактивный уровень для внешнего API. Это гораздо более свободная концепция "модели".

4

В Django структура MVC, как сказал Крис Пратт, отличается от классической модели MVC, используемой в других рамках, я думаю, что основная причина для этого - избежать слишком строгой структуры приложения, например, происходит в других средах MVC, таких как CakePHP.

В Django MVC был реализован следующим образом:

Вид слоя разделен на два. Представления должны использоваться только для управления HTTP-запросами, они вызываются и отвечают на них. Представления взаимодействуют с остальной частью вашего приложения (формы, модели, пользовательские классы, в простых случаях непосредственно с моделями). Для создания интерфейса мы используем Шаблоны. Шаблоны похожи на Django, они сопоставляют контекст с ними, и этот контекст был передан приложению приложением (при запросе вида).

Уровень модели предоставляет инкапсуляцию, абстракцию, проверку достоверности и делает ваши данные объектно-ориентированными (они говорят, что когда-нибудь СУБД также будет). Это не означает, что вы должны создавать огромные файлы models.py(на самом деле очень хороший совет - разделить ваши модели в разных файлах, поместить их в папку под названием "модели", сделать файл "__init__.py" в этом где вы импортируете все свои модели и, наконец, используете атрибут "app_label" для моделей. Класс модели). Модель должна абстрагировать вас от работы с данными, это упростит ваше приложение. Вы также должны, при необходимости, создавать внешние классы, такие как "инструменты" для своих моделей. Вы также можете использовать наследие в моделях, устанавливая атрибут "abstract" вашей модели Meta-класса на "True".

Где остальные? Ну, небольшие веб-приложения, как правило, представляют собой своего рода интерфейс к данным, в некоторых небольших программных случаях достаточно использовать представления для запроса или вставки данных. Более распространенные случаи будут использовать Forms или ModelForms, которые на самом деле являются "контроллерами". Это не что иное, как практическое решение общей проблемы и очень быстрая. Это то, что использует веб-сайт.

Если формы для вас не нужны, тогда вы должны создать свои собственные классы, чтобы сделать магию, очень хорошим примером этого является приложение администратора: вы можете прочитать код ModelAmin, это фактически работает как контроллер. Существует не стандартная структура, я предлагаю вам изучить существующие приложения Django, это зависит от каждого случая. Это то, что намеревались разработчики Django, вы можете добавить класс парсера xml, класс соединителей API, добавить Celery для выполнения задач, скрутить для приложения на базе реакторов, использовать только ORM, сделать веб-сервис, изменить приложение администратора и многое другое... Это ваша ответственность, чтобы сделать код хорошего качества, уважать философию MVC или нет, сделать его модульным и создать свои собственные уровни абстракции. Он очень гибкий.

Мой совет: прочитайте как можно больше кода, есть много приложений django, но не воспринимайте их так серьезно. Каждый случай отличается, шаблоны и теория помогают, но не всегда, это неточный язык, django просто предоставляет вам хорошие инструменты, которые вы можете использовать, чтобы смягчить некоторые боли (например, интерфейс администратора, проверку веб-формы, i18n, реализацию шаблона наблюдателя, все ранее упомянутые и другие), но хорошие проекты исходят от опытных дизайнеров.

PS: используйте класс "Пользователь" из приложения auth (из стандартного django), вы можете сделать, например, профили пользователей или, по крайней мере, прочитать его код, это будет полезно для вашего случая.

0

Старый вопрос, но я все равно хочу предложить свое решение. Это основано на признании того, что объектам модели также требуются некоторые дополнительные функции, в то время как неудобно размещать их в пределах models.py. Тяжелая бизнес-логика может быть написана отдельно в зависимости от личного вкуса, но я, по крайней мере, как модель, делаю все, что связано с ней. Это решение также поддерживает тех, кто любит иметь всю логику, размещенную внутри самих моделей.

Как таковой, я разработал хак, который позволяет мне отделять логику от определений моделей и все еще получать все намеки от моей IDE.

Преимущества должны быть очевидны, но в этом перечислены некоторые из них, которые я наблюдал:

  • Определения БД остаются такими, что - никакой логический "мусор" не прикреплен
  • Логика, связанная с моделью, размещается аккуратно в одном месте.
  • Все службы (формы, REST, представления) имеют единую точку доступа к логике
  • Лучше всего: Мне не пришлось переписывать какой-либо код, как только я понял, что мои models.py стали слишком загроможденными и должны были отделить эту логику. Разделение является гладким и итеративным: я мог бы выполнять функцию за один раз или весь класс или все модели .py.

Я использовал это с Python 3.4 и выше и Django 1.8 и выше.

приложение/models.py

....
from app.logic.user import UserLogic

class User(models.Model, UserLogic):
    field1 = models.AnyField(....)
    ... field definitions ...

приложение/логика/user.py

if False:
    # This allows the IDE to know about the User model and its member fields
    from main.models import User

class UserLogic(object):
    def logic_function(self: 'User'):
        ... code with hinting working normally ...

Единственное, что я не могу понять, это сделать, чтобы моя IDE (PyCharm в этом случае) признала, что UserLogic на самом деле является моделью пользователя. Но поскольку это, очевидно, хак, я очень рад принять небольшую неприятность, всегда указывающую тип для параметра self.

0

Я в основном согласен с выбранным ответом (https://stackoverflow.com/questions/12578908/separation-of-business-logic-and-data-access-in-django), но хочу добавить опцию в раздел "Создание запросов".

Можно определить классы QuerySet для моделей для запросов фильтра и сына. После этого вы можете проксировать этот класс запроса для диспетчера модели, например, для классов сборки и QuerySet.

Хотя, если вам пришлось запрашивать несколько моделей данных для получения одной модели домена, мне кажется более разумным поставить это в отдельный модуль, как это было предложено ранее.

-2

Django предназначен для простого использования для доставки веб-страниц. Если вы не можете с этим справиться, возможно, вы должны использовать другое решение.

Я пишу корневые или общие операции над моделью (чтобы иметь тот же интерфейс), а остальные - на контроллере модели. Если мне нужна операция из другой модели, я импортирую ее контроллер.

Этот подход достаточно для меня и сложности моих приложений.

Ответ Hedde - это пример, демонстрирующий гибкость самого django и python.

Очень интересный вопрос в любом случае!

  • 8
    Как сказать, что это достаточно хорошо для тебя, чтобы понять мой вопрос?
  • 0
    Django может предложить гораздо больше, кроме django.db.models, но большая часть экосистемы сильно зависит от вашей модели, использующей модели django.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню