【问题标题】:How to create a field in django model using values of other fields of same model?如何使用同一模型的其他字段的值在 django 模型中创建一个字段?
【发布时间】:2019-04-02 10:50:12
【问题描述】:

我想创建一个字段名称:total,其中包含所有产品的总价格*数量。我想要的是如何在 django 模型中执行total = price*quantity。如您所见,产品可能不止一种。
我已经通过 tabularinline 加入了 OderItem 模型和 Order。

class OrderItemInline(admin.TabularInline):
    model = OrderItem
    raw_id_fields = ['product']

class OrderAdmin(admin.ModelAdmin):
    list_display = ['id','name', 'mobile_no','address','status', 'created']
    list_editable = ['status']
    list_per_page = 15
    list_filter = ['status']
    search_fields = ('id',)
    inlines = [OrderItemInline]


admin.site.register(Order, OrderAdmin)
class Order(models.Model):
    name = models.CharField(max_length=60)
    email = models.EmailField(max_length=60,default=None, blank=True)
    mobile_no = models.CharField(max_length=13, default=None) 
    address = models.CharField(max_length=150)
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)
    status_choices = (
        ('In Queue', 'In Queue'),
        ('Processing', 'Processing'),
        ('Ready', 'Ready'),
        ('Delivered', 'Delivered'),
        ('Paid', 'Paid'),
        ('Cancelled', 'Cancelled'),
    ) 
    status = models.CharField(max_length=15,       choices=status_choices, default=status_choices[0][0])


    class Meta:
        ordering = ('created', )

    def __str__(self):
        return 'Order {}'.format(self.id)

    def get_total_cost(self):
        return sum(item.get_cost() for item in self.items.all())



class OrderItem(models.Model):
    order = models.ForeignKey(Order, related_name='items', 
    on_delete=models.CASCADE)
    product = models.ForeignKey(MenuVariant, related_name='order_items', 
    on_delete=models.CASCADE, default=None)
    size = models.CharField(max_length=20, default=None)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    quantity = models.PositiveIntegerField(default=1)
    # total = models.DecimalField(max_digits=10, decimal_places=2,default=0)



    def __str__(self):
        return '{}'.format(self.id)

    def get_cost(self):
        return self.price * self.quantity

【问题讨论】:

  • 你想要“创建一个字段总计”是什么意思?您想在管理员中显示总价吗?或者您想访问代码中的总数?
  • 两者都想做
  • 但是你的代码中已经有了它:order.get_total_cost().
  • 它只显示一种产品的总价格,例如价格*数量
  • 嗯?它是所有项目的成本总和,而不仅仅是一种产品。你的代码是正确的。

标签: python django django-models django-2.1


【解决方案1】:

您可以通过数据库查询直接获得Order 的总价,因此无需将其保存在数据库中:

from django.db.models import Sum, F, FloatField
orders = Order.objects.annotate(total=Sum(F('items__quantity')*F('items__price'), output_field=FloatField()))

这会为查询的每个结果添加一个total 字段。那么:

price_of_first_order = orders.first().total

如果您想在管理员中显示order 的总数,请将ModelAdmin 子类化并将get_total_cost 添加到readonly_fields,如here 所述:

只读字段不仅可以显示模型字段的数据,还可以显示模型方法或 ModelAdmin 类本身的方法的输出。这与 ModelAdmin.list_display 的行为方式非常相似。

【讨论】:

  • 我在订单模型或订单项目模型中添加此代码?
  • 正如你所说,get_total_cost 函数正在做我要问的事情,那么我该如何在模型中做 total=get_total_cost
  • 你能帮帮我吗?
  • 如果您真的想保存它,请参阅@amazonic 下面的答案。但正如我所说,这样做是不好的做法,因为它是多余的,并且几乎可以肯定在某个阶段会导致数据库中的数据不一致。您需要始终保留一个事实来源,将其保存到数据库会为同一事实创建第二个来源。
  • 我很困惑如何使用你提供的代码,我复制了 Order 模型中的代码,但它不起作用。我是 django 的新手,我是第一次这样做。
【解决方案2】:

虽然我和 dirkgroten 一样不太明白将值保存在模型字段中的意义,但您可以将字段 total=models.IntegerField(null=True, blank=True) 添加到您的 Order 模型并使用 post_save 更新值。

所以,既然你已经有了get_total_cost(),我们可以这样做:

def order_pre_save(sender, instance, **kwargs):
    instance.total_cost = instance.get_total_cost()

pre_save.connect(order_pre_save, sender=Order)

编辑:正如 dirkgroten 指出的那样,您需要OrderItem 上的post_save

def order_item_pre_save(sender, instance, **kwargs):
    instance.order.total_cost = instance.order.get_total_cost()
    instance.order.save()

post_save.connect(order_item_pre_save, sender=OrderItem)

您还需要更新删除时的值:

def order_item_pre_delete(sender, instance, **kwargs):
    instance.order.total_cost = instance.order.get_total_cost() - instance.get_cost()
    instance.order.save()

post_delete.connect(order_item_pre_delete, sender=OrderItem)

【讨论】:

  • 这可行,但您需要连接保存OrderItem,而不是Order,以更新Order 上的字段。所以应该是instance.order.total_cost = instance.order.get_total_cost(); instance.order.save()
  • 问题是您还应该在删除 OrderItem 时更新它。在某些情况下也不会调用这些信号,例如当发生批量更新或批量创建时。
  • 当我运行 order_item_pre_save 函数时,它给出错误 OrderItem is not defined
  • 您是否在models.py 中定义了新功能?将您的帖子/预先保存在您的模型所在的 models.py 底部。
猜你喜欢
  • 2014-07-20
  • 2021-04-30
  • 1970-01-01
  • 2023-02-24
  • 2019-04-20
  • 1970-01-01
  • 1970-01-01
  • 2011-05-21
  • 1970-01-01
相关资源
最近更新 更多