2. Паттерн "Отложенная модель"

11 октября 2016 г. 14:55

До djangoSHOP версии 0.2 были абстрактные и конкретные модели: BaseProduct и Product, BaseCart и Cart, BaseCartItem и CartItem, BaseOrder и Orderand и наконец, BaseOrderItem и OrderItem.

Конкретные модели хранились в shop.models, в то время как абстрактные модели были сохранены в shop.models_bases. Это было достаточно запутано и трудно для нахождения нужной модели. К тому же, если кто-то хочет создать подкласс модели, то он должен был использовать директиву конфигурации, скажем, PRODUCT_MODEL, ORDER_MODEL, ORDER_MODEL_ITEM в settings.py.

Такая конфигурация достаточно сложна, которая имела и другие недостатки:

  • Если не все модели были переопределены, то нативные модели появлялись в административной панели ниже категории Интернет-магазин, в то время как кстомные модели появлялись под названием данного проекта. Это различие было трудно объяснить продавцам, почему так происходит.
  • В прошлом миксин-подклассы с нативными моделями выбрасывали много исключений по поводу зацикленных зависимостей (circular dependencies).

Поэтому в djangoSHOP начиная с версии 0.9 все конкретные модели Product, Order,OrderItem, Cart, CartItem были удалены. Сейчас все эти определения модели абстрактны и названы BaseProduct, BaseOrder, BaseOrderItem и т. д. Они все были перемещены в папку shop/models/, потому что данное место под модели привычно для программиста.

2.1. Материализация моделей

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

Например, материализовать корзину можно используя следующий фрагмент кода внутри нашего приложения интернет-магазина, например myshop, в файле models/shopmodels.py:

from shop.models import cart

class Cart(cart.BaseCart):
    my_extra_field = ...

    class Meta:
        app_label = 'my_shop'

class CartItem(cart.BaseCartItem):
    other_field = ...

    class Meta:
        app_label = 'my_shop'

Конечно, мы можем добавить столько дополнительных полей в конкретную модель, сколько пожелаем. Сейчас все модели управляются через наш экземпляр проекта. Это означает, что модели Cart, Order и другие управляются через основные команды миграций, такие как ./manage.py makemigration my_shop и ./manage.py migrate my_shop. Это также означает, что эти модели в административной панели показываются в категории my_shop.

2.1.1. Использование дефолтных моделей

Часто нам не нужны дополнительные поля, и, следовательно, абстрактных базовых моделей вполне хватает. Тогда материализация моделей может быть сделана с помощью некоторых удобных классов, которые находятся в inshop/models/defaults. Мы можем просто импортировать их в models.py или models/__init__.py в наше собственное приложение интернет-магазина.

from shop.models.defaults.cart import Cart # nopyflakes 
from shop.models.defaults.cart_item import CartItem # nopyflakes

Замечание: # nopyflakes был добавлен для скрытия предупреждений, так как эти классы не используются где-либо в models.py.

Все конфигурационные настройки от djangoSHOP <0.9: PRODUCT_MODEL, ORDER_MODEL,ORDER_MODEL_ITEM и т. д. не требуются больше и могут быть без опасения удалены из нашего settings.py.

2.2. Доступ к отложенным моделям

Так как во время создания экземпляра модели в djangoSHOP пока ещё не загружены, необходимо получить доступ к их материализованному экземпляру, используя паттерн Ленивый шаблон. Например, в Заказе для получения Корзины используйте:

def my_view(request):
    cart = CartModel.objects.get_from_request(request)
    cart.items.all()  # содержит queryset всех товаров в корзине

В этом примере CartModel - это "ленивый" объект, который вычисляется во время выполнения программы и указывает на материализацию, другими словами, на реальную модель Cart.

2.3. Технические моменты

2.3.1. Отображение внешних ключей

Можно возразить, что так не может работать, так как внешние ключи должны ссылаться на реальную модель, а не на абстрактную! Поэтому нельзя добавить поле ForeignKey, OneToOneField или ManyToManyField, которая ссылается на абстрактную модель в проекте djangoSHOP. Но отношения имеют основополагающее значение для правильно работающего программного обеспечения. Представьте себе CartItem без внешнего ключа к корзине.

К счастью, имеется ловкий трюк, позволяющий решить данную проблему. Для отложения отображения в реальную модель вместо использования реального ForeignKey можно использовать специальное "ленивое" поле, объявив связь с абстрактной моделью. Тогда, когда эти модели "материализовались", эти абстрактные отношения превращаются в реальные внешние ключи. Единственный недостаток этого решения состоит в том, что можно вывести из абстрактной модели только один раз, но для djangoSHOP это не проблема. Ведь, например, для корзины мы создаём один подкласс в любом случае. Также и с другими моделями.

Поэтому, во время использования паттерна Отложенная модель вместо использования models.ForeignKey, models.OneToOneField или models.ManyToManyField, используются специальные поля deferred.OneToOneField и deferred.ManyToManyField. Когда Django материализует модель, эти отложенные поля будут направлены на реальные внешние ключи.

2.3.2. Доступ к материализованной модели

При программировании абстрактных класс модели иногда они должны получить доступ к своему менеджеру модели или к их конкретному определению модели. Поэтому запрос, такой как BaseCartItem.objects.filter(cart=cart), не будет работать и сгенерируется исключение. Для решения этой задачи отложенные метаклассы добавляют дополнительный _materialized_model членам их базового класса при построении модели класса. Этот класс модель может быть доступен через ленивые вычисления, используя CartModel, CartItemModel, OrderModel, OrderItemModel и т. д.

Оцените статью

0 из 5 (всего 0 оценок)

captcha
Отмеченные звёздочкой поля ( * ) являются обязательными для заполнения.

Спасибо за ваш отзыв!

После нажатия кнопки "Отправить" ваше сообщение будет доставлено мне на почту.

Автор перевода

Артём Мальцев

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

Права на использование материала, расположенного на этой странице https://vivazzi.pro/ru/django-shop/pattern-otlozhennaya-model/:

Разрешается копировать материал с указанием её автора и ссылки на оригинал без использования параметра rel="nofollow" в теге <a>. Использование:

Автор перевода: Артём Мальцев
Ссылка на перевод статьи: <a href="https://vivazzi.pro/ru/django-shop/pattern-otlozhennaya-model/">https://vivazzi.pro/ru/django-shop/pattern-otlozhennaya-model/</a>

Больше: Правила использования сайта

Представляю вашему вниманию книгу, написанную моим близким другом Максимом Макуриным: Секреты эффективного управления ассортиментом.

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

Комментарии: 0

Вы можете оставить комментарий как незарегистрированный пользователь.

Но зарегистрировавшись, вы сможете:

  • получать оповещения об ответах
  • просматривать свои комментарии
  • иметь возможность использовать все функции разработанных сервисов

Для комментирования от своего имени войдите или зарегистрируйтесь на сайте Vuspace

Отправить

На данный момент нет специального поиска, поэтому я предлагаю воспользоваться обычной поисковой системой, например, Google, добавив "vivazzi" после своего запроса.

Попробуйте

Выберите валюту для отображения денежных единиц