How to create a field in django model using values of other fields of same model?

被刻印的时光 ゝ 提交于 2019-12-02 13:18:13

You can get the total price for an Order directly with a database query, so there's no need to save it in the database:

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

This adds a total field to each result of the query. So then:

price_of_first_order = orders.first().total

And if you want to display the total for an order in the admin, subclass the ModelAdmin and add get_total_cost to the readonly_fields, as explained here:

A read-only field can not only display data from a model’s field, it can also display the output of a model’s method or a method of the ModelAdmin class itself. This is very similar to the way ModelAdmin.list_display behaves.

amazonic

While I, like dirkgroten don't quite see the point of saving the value in a model field, you could add a field total=models.IntegerField(null=True, blank=True) to your Order model and use a post_save to update the value.

So, since you already have a get_total_cost() we can do something like:

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

pre_save.connect(order_pre_save, sender=Order)

EDIT: As dirkgroten points out you'll need the post_save on the OrderItem:

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)

And you'd also need to update the value on delete:

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)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!