Пример Django Admin Stacked Inline: отношения многие-к-одному и многие-ко-многим

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

Как добавить несколько товаров в корзину?

Django Admin — довольно мощный инструмент при работе с данными в стиле CRUD (создание, чтение, модификация, удаление). Одна из особенностей, о которой многие (даже опытные) разработчики не подозревают, — это наличие нескольких строк «many-one» или «many-to-many» на одной странице, как показано на этом рисунке:

Потрясно, правда? А рецепт простой, давайте посмотрим.

Data (Models)

from django.db import models


class Item(models.Model):
    name = models.CharField(max_length=100)
    price = models.DecimalField(default=0, decimal_places=2, max_digits=10)

    def __str__(self):
        return f"{self.name}: ${self.price}"


class Cart(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    paid = models.BooleanField(default=False)

    def total_price(self):
        return sum([
            cart_item.total()
            for cart_item in CartItem.objects.filter(cart=self)
        ])

    def __str__(self):
        return f"{self.created}, ${self.total_price()}: {self.paid}"


class CartItem(models.Model):
    cart = models.ForeignKey(Cart, on_delete=models.CASCADE)
    item = models.ForeignKey(Item, on_delete=models.CASCADE)
    count = models.IntegerField(default=1)

    def total(self):
        return self.count * self.item.price

    def __str__(self):
        return f"{self.item.name}, " \
               f"${self.item.price} * {self.count} = ${self.total()}"

Модели просты: у нас есть Items, Carts и таблица CartItem для отношения многие-ко-многим между Items и Carts. Мы не могли использовать здесь models.ManyToManyField, так как нам нужно дополнительное поле “count” внутри отношений. Когда я сам создаю отношения, это кажется более прозрачным.

Admin

Внутри Admin мы не просто регистрируем модели напрямую, нам нужно создать классы ModelAdmin и StackedInline.

Идея заключается в следующем. Сначала мы создаем многострочное представление (multiline view) для поддержки CRUD в таблице CartItem. А затем мы добавляем это представление к представлению корзины.

Это делается следующим образом:

from django.contrib import admin
from shop.models import Cart, Item, CartItem


class ItemInline(admin.StackedInline):
    model = CartItem
    extra = 5


class CartAdmin(admin.ModelAdmin):
    inlines = [ItemInline]
    list_display = ["created", "total_price", "paid"]


admin.site.register(Cart, CartAdmin)
admin.site.register(Item)

Вот и все. Полезная вещь и не занимает много времени.


Скоро состоится открытое занятие «О "регулярках" и не только», на котором:
- Поговорим о роли регулярных выражений в разработке.
- Оценим эффект от re.compile.
- Попробуем переписать код без использования регулярок и посмотрим, стоит ли тратить время на изучение этой непростой темы.

Регистрируйтесь по ссылке.

Источник: https://habr.com/ru/company/otus/blog/690274/


Интересные статьи

Интересные статьи

В 2019 году компания OpenAI опубликовала статью о точной настройке GPT-2, в которой она использовала Scale AI для сбора мнений живых разметчиков с целью совершенствования своих языковых моделей. Хот...
Не зря говорят, что лень это двигатель прогресса. Для облегчения и ускорения домашнего труда, в частности процедуры регулярной уборки, существует множество современных гаджетов. Один из гигантов в сфе...
Всем привет.Некоторое время назад я писал про альтернативные возможности, как можно добавить в django асинхронность (есть официальный подход, изложенный в DEP-09). С тех пор у меня получилось оформ...
Программист — творческая профессия. Мы создаем что-то новое, руководствуясь своими знаниями, внутренним пониманием качества и поставленными дедлайнами. Дедлайны и знания пока оставим в сторо...
6 февраля Убер опубликовал результаты компании за чётвертый квартал и подвёл итоги года. Чистый убыток в $8,5 млрд — не самая интересная новость. Изучая отчётность, я обнаружил неприкрытую манипу...