如何在django中的manytomanyfield中添加字段?

时间:2015-01-16 00:01:35

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

我在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, })

我没有通过Admin使用它,所以这里是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。

2 个答案:

答案 0 :(得分:2)

没有理由将其保存在数据库中,只需将其设为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'))

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

答案 1 :(得分:1)

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

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())