Суммирование внутри модели корзины промежуточного итога каждой записи TabularInline в Django Admin - PullRequest
0 голосов
/ 03 октября 2018

Не уверен, что это возможно, но в моем подробном представлении Корзина (класс модели) в Django Admin, я хотел бы суммировать весь мой класс модели TabularInline Entry промежуточные итоги и сохраните это значение в атрибуте total_price моей корзины .Есть ли способ сделать это или каким-то образом использовать фильтр или виджет формы, чтобы добавить все промежуточные итоги вместе для той же цели?Заранее спасибо за любую помощь!

Ниже приведен пример того, что я хотел бы сделать.Вы можете видеть в поле итоговой цены, которое я вручную ввел 130 (итого: 90 + 20 + 20 = 130).Я бы хотел, чтобы это вычислялось автоматически при каждом добавлении записи из инвентаря и изменении ее количества.

enter image description here

Пока что у моего администратора.py У меня есть административный класс TabularInline, который возвращает промежуточный итог для каждой записи, умножая ее количество на соответствующую цену.Затем мой класс CartAdmin отображает эти встроенные отношения в подробном представлении модели корзины.

admin.py

class EntryInline(admin.TabularInline):
    model = Entry
    extra = 0
    readonly_fields = ['subtotal']
    exclude = ['price']
    def subtotal(self, obj):
        return "$" + str(obj.quantity * obj.inventory.price)


class CartAdmin(admin.ModelAdmin):
    inlines = [EntryInline]
    fieldsets = (
        (None, {
            'fields':('user', 'total_price')
            }),
    )

models.py

class Inventory(models.Model):
    quantity        = models.IntegerField()
    price           = models.DecimalField(max_digits=5, decimal_places=2)


class Cart(models.Model):
    user            = models.OneToOneField(User)
    total_price     = models.DecimalField(max_digits=4, decimal_places=2, blank=True, null=True)


class Entry(models.Model):
    cart            = models.ForeignKey(Cart, related_name="entries")
    inventory       = models.ForeignKey(Inventory, related_name="entries")
    quantity        = models.PositiveSmallIntegerField(default=1)
    price           = models.DecimalField(max_digits=4, decimal_places=2, blank=True, null=True)

Ответы [ 3 ]

0 голосов
/ 05 октября 2018

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

А пока вот как я смог получить промежуточные итоги и общее количество:


В models.py Я добавил поле 'промежуточный итог' для моей модели Entry:

subtotal = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True)

В admin.py:

class EntryInline(admin.TabularInline):
    model = Entry
    extra = 0
    # calls my helper method
    readonly_fields = ['get_subtotal']
    # exclude redundant field being replaced by helper method
    exclude = ['subtotal']


    # gets subtotal of each entry
    def get_subtotal(self, obj):
        # for a given entry, find that id
        entry = Entry.objects.get(id=obj.id)
        # subtotal the entry quantity * its related price
        entry_subtotal = obj.quantity * obj.inventory.price
        # check if entry obj has a subtotal and try to save to db
        if entry.subtotal != entry_subtotal:
            try:
                entry.subtotal = entry_subtotal
                entry.save()
            except DecimalException as e:
                print(e)
        # return a str representation of entry subtotal
        return "$" + str(entry_subtotal)
    # set helper method's description display
    get_subtotal.short_description = 'subtotal'


# initialization of variable
total_price = 0

class CartAdmin(admin.ModelAdmin):
    model = Cart
    inlines = [EntryInline]
    # calls get_total helper method below
    readonly_fields = ['get_total']
    exclude = ['total_price']


    def get_total(self, obj):
        # extend scope of variable
        global total_price
        # get all entries for the given cart
        entries = Entry.objects.filter(cart=Cart.objects.get(id=obj.id))
        # iterate through entries
        for entry in entries:
            # if entry obj has a subtotal add it to total_price var
            if entry.subtotal:
                total_price += entry.subtotal
        print(obj.total_price)
        # assign cart obj's total_price field to total_price var
        obj.total_price = total_price
        # save to db
        obj.save()
        # reset total_price var
        total_price = 0
        # return cart's total price to be displayed
        return obj.total_price
    # give the helper method a description to be displayed
    get_total.short_description = 'total'

** Следует отметить, что промежуточные итоги загружаются динамически, когда я редактирую количество и сохраняю его, потому что он использует вспомогательный метод.Мне все еще нужно обновить браузер еще раз, чтобы сохранить в базе данных, однако дисплей все еще там.Я не уверен, почему get_total () не работает так же;Там нет дисплея И я должен обновить браузер, чтобы сохранить в базе данных.Логика кажется противоречивой ...

0 голосов
/ 30 октября 2018

Ниже приведено то, что я использовал для обновления страницы после того, как я сохранил в admin для обновления всего:

cart.js

if (!$) {
    $ = django.jQuery;
 }
function addSecs(d, s) {
    return new Date(d.valueOf() + s * 1000);
}
function doRun() {
    document.getElementById("msg").innerHTML = "Processing JS...";
    setTimeout(function() {
        start = new Date();
        end = addSecs(start, 5);
        do {
            start = new Date();
        } while (end - start > 0);
        document.getElementById("msg").innerHTML = "Finished Processing";
    }, 10);
 }
$(function() {
    $(".change_form_save").click(doRun);

    if (window.localStorage) {
        if (!localStorage.getItem("firstLoad")) {
            localStorage["firstLoad"] = true;
            window.location.reload();
        } else localStorage.removeItem("firstLoad");
    }
});

Затем в моем администраторе.py под моим классом для CartAdmin (admin.ModelAdmin):

class Media:
    js = ('js/cart.js',)
0 голосов
/ 03 октября 2018

Вы можете попробовать выбрать total_price в администрировании корзины и заполнить поле следующим образом:

class CartAdmin(admin.ModelAdmin):
    inlines = [EntryInline]
    fieldsets = (
    (None, {
        'fields':('user', 'total_price')
        }),
    )

    def get_form(self, request, obj=None, **kwargs):
        form = super().get_form(request, obj, **kwargs)
        # check if the cart object exists
        if obj:
            try:
                _price = Entry.objects.filter(cart=obj).aggregate(sum=Sum(F('quantity')*F('inventory__price'), output_field=FloatField()))
                total = _price['sum']
                obj.total_price = total
            except:
                pass
    return form

Что касается вашей ошибки импорта, импортируйте F и Sum как:

from django.db.models import Sum, F

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

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...