Закрыть

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

Цитата дня

Vivazzi.ru

Личный сайт Мальцева Артема

Если ничего не помогает, прочтите документацию, наконец! (о программировании)
RaD

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

11 октября 2016 г. 10: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 оценок)

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

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

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

Права на использование данной статьи, расположенной на настоящей странице http://vivazzi.ru/django-shop/pattern-otlozhennaya-model/:

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

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

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

Вам нужно саморазвиваться или вы хотите зарабатывать деньги?

Или вы ищите хорошие IT сервисы или книги? Сохраните свое время и взгляните на мою подборку рекомендаций, которыми постоянно пользуюсь.
Посмотреть рекомендации

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

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

Чтобы оставить комментарий от своего имени войдите или зарегистрируйтесь обычным способом или через социальные сети:

Отправить

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

Попробуйте