【问题标题】:How do I add together fields from a manytomanyfield in django?如何在 django 中将来自 manytomanyfield 的字段加在一起?
【发布时间】:2015-01-16 00:01:34
【问题描述】:

我正在 Django 中创建一个报价生成器。我想计算所有项目的总数,将其插入到字段中并保存。

型号如下:

from django.db import models
from django.core.urlresolvers import reverse


class Product(models.Model):
    product_name = models.CharField(max_length=50)
    product_description = models.CharField(max_length=200)
    product_price = models.IntegerField(max_length=4)

    def __unicode__(self):
        return self.product_name

    class Meta:
        ordering = ('product_name',)


class Quote(models.Model):
    quotee_name = models.CharField("Name", max_length=40)
    quotee_email = models.EmailField("Email")
    quotee_phone = models.IntegerField("Phone", max_length=10)
    quotee_products = models.ManyToManyField(Product, verbose_name="Products")
    quotee_total = models.IntegerField("Estimate", max_length=10, null=True, blank=True)

    def __unicode__(self):
        return self.quotee_email

    class Meta:
        ordering = ('quotee_email',)

    def get_absolute_url(self):
        return reverse('quote-detail', kwargs={'pk': self.pk, })

我没有通过管理员使用它,所以这里是 forms.py:

from django import forms
from django.forms import CheckboxSelectMultiple


from InternalDusettenet.apps.quotes.models import Quote


class QuoteForm(forms.ModelForm):

    class Meta:
        model = Quote
        fields = ('quotee_name', 'quotee_email', 'quotee_phone',
                  'quotee_products')
        widgets = {
            'quotee_products': CheckboxSelectMultiple(attrs={'size': 10}),
        }

这里是views.py 文件。我将其设置为仅将“1”保存到表单中,以便实际保存。我想要的是用一个函数替换“1”,该函数为“Quote.quotee_products”中选择的每个产品返回“Product.product_price”的值。当我创建报价时,我选择了产品,它为我提供了与所选产品相关的所有选定“product_price”字段的总和:

from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.views.generic import ListView, DetailView
from django.shortcuts import Http404, get_object_or_404

from InternalDusettenet.apps.quotes.models import Quote
from InternalDusettenet.apps.quotes.forms import QuoteForm


class QuoteCreate(CreateView):
    model = Quote
    template_name = "quotes/quote_create_edit.html"
    fields = ['quotee_name', 'quotee_email', 'quotee_phone',
              'quotee_products']
    form_class = QuoteForm

    def form_valid(self, form):
        form.instance.quotee_total = 1
        return super(QuoteCreate, self).form_valid(form)


class QuoteList(ListView):
    model = Quote
    template_name = "quotes/quote_list.html"


class QuoteDetail(DetailView):
    model = Quote
    template_name = "quotes/quote_detail.html"


class QuoteUpdate(UpdateView):
    model = Quote
    template_name = "quotes/quote_create_edit.html"
    fields = ['quotee_name', 'quotee_email', 'quotee_phone',
              'quotee_products', 'quotee_total']
    form_class = QuoteForm


class QuoteDelete(DeleteView):
    model = Quote
    success_url = '/'
    template_name = "quotes/quote_delete.html"

我已多次阅读 Django 文档,但我不知道如何做这件简单的事情。

我正在使用 Django 1.7 和 Python 2.7。

【问题讨论】:

    标签: python django aggregate-functions django-orm manytomanyfield


    【解决方案1】:

    没有理由将其保存在数据库中,只需将其作为Quote对象的方法或属性即可:

    class Quote(models.Model):
        ...
        def quotee_total(self):
            return self.quotee_products.aggregate(total=models.Sum('product_price'))['total']
    

    如果需要,您可以缓存该值并在初始查询时填充缓存:

    class Quote(models.Model):
        ...
        def quotee_total(self):
            if not hasattr(self, '_quotee_total'):
                self._quotee_total = self.quotee_products.aggregate(total=models.Sum('product_price'))['total']
            return self._quotee_total
    
    quotes = Quote.objects.annotate(_quotee_total=models.Sum('quotee_products__product_price'))
    

    您当然可以将该值保存在数据库中,但没有什么理由。如果您担心性能,那么使用缓存比将值保存到数据库更好。

    【讨论】:

    • 使用 aggregate() 可能比我建议的方式更有效。注意: Sum() 函数不应与 Python 内置函数 sum() 混淆。使用from django.db.models import Sum
    • @HåkenLid 意思是写models.Sum 因为models 已经导入:P 这应该很清楚,但感谢您的说明。
    • 哇。这么多cmets。非常感谢大家。对于这个,我需要查看引号的唯一原因是在视图中。它不需要存储在数据库中。当我查询那个特定的报价时,我只需要准备好总数。很抱歉成为菜鸟,但如果将其作为第一个示例中的方法,我将如何通过视图/模板调用它?再次。很抱歉没有得到它。哈哈。我通常非常擅长弄清楚事情,但这只是让我感到困惑。谢谢。
    • 如果quote 是您的Quote 实例,请在视图中使用quote.quotee_total(),在模板中使用{{ quote.quotee_total }}。除了self 之外没有参数的函数和方法会在模板中自动调用。
    • 好东西!谢谢!我正用头穿过墙壁,我知道这很简单。如果我有任何问题,我会回来,但这非常简洁。
    【解决方案2】:

    我不会计算视图中的总数。这作为一种方法更有意义。

    class Quote(models.Model):
    
        def calculate_quotee_total(self):
            return sum(product.product_price for product in self.quotee_products.all())
    
        def __save__(self):
            self.quotee_total = self.calculate_quotee_total()
            super(Quote, self).save()
    

    Quote.quotee_total 也可以根据需要计算,而不是保存在数据库中。

    class Quote(models.Model):
    
        @property
        def quotee_total(self):
            return sum(product.product_price for product in self.quotee_products.all())
    

    【讨论】:

      猜你喜欢
      • 2013-02-05
      • 2012-12-10
      • 2016-03-27
      • 1970-01-01
      • 2013-09-22
      • 1970-01-01
      • 1970-01-01
      • 2013-08-03
      • 1970-01-01
      相关资源
      最近更新 更多