Как создать поле в модели Django, используя значения других полей той же модели? - PullRequest
0 голосов
/ 02 апреля 2019

Я хочу создать имя поля: всего , которое имеет общую стоимость всех продуктов * количество.Что я хочу, это как я могу сделать total = price*quantity в модели Django.Как вы можете видеть, может быть более одного продукта.
Я присоединился к модели OderItem с Order через tabularinline.

enter image description here

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

Ответы [ 2 ]

1 голос
/ 03 апреля 2019

Хотя я, как и 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, вам понадобится post_save на 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)

И вам также необходимо обновить значение при удалении:

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)
1 голос
/ 02 апреля 2019

Вы можете получить общую цену за 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, как объяснено здесь :

Поле только для чтения может не только отображать данные из поля модели, но также отображать выходные данные метода модели или метода самого класса ModelAdmin.Это очень похоже на поведение ModelAdmin.list_display.

...