在购物车模型中总计Django Admin中每个TabularInline条目的小计

时间:2018-10-03 06:37:58

标签: python django django-models django-admin django-admin-tools

不确定是否可行,但是在Django Admin的 Cart (模型类)详细信息视图中,我希望汇总所有TabularInline 条目模型类小计,然后将该值保存到我的购物车的total_price 属性中。有没有办法做到这一点,或者出于某种目的使用过滤器或表单小部件将所有小计加在一起?预先感谢您的帮助!

下面是我想做的一个例子。您可以在总价格字段中看到我手动输入的130(小计:90 + 20 + 20 = 130)。我希望每次从库存添加条目并对其数量进行编辑时,都会自动计算得出。

enter image description here

到目前为止,在我的admin.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 :(得分:0)

您可以尝试在购物车管理员中获取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。

希望有帮助。

答案 1 :(得分:0)

很高兴,当我在管理详细信息视图中编辑数量以查看购物车总价服务器端的更新更改时,我仍在设法刷新发出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()不能以相同的方式工作;没有显示,我必须刷新浏览器才能保存到数据库。逻辑似乎不一致...

答案 2 :(得分:0)

以下是我保存在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");
    }
});

然后在我的admin.py中的类下,选择CartAdmin(admin.ModelAdmin):

class Media:
    js = ('js/cart.js',)