按型号属性过滤输出

时间:2016-12-20 03:56:16

标签: python django csv

在我的模型中,我计算了属性current_tobe_payed

我想生成我的属性current_tobe_payed小于零的所有行的CSV报告

请参阅下面的视图:

def export_leaseterm_csv(request):
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="leaseterm.csv"'
    writer = csv.writer(response)
    leaseterms = serializers.serialize( "python", LeaseTerm.objects.all())
    [obj for obj in leaseterms if obj.current_tobe_payed > 0]

    for leaseterm in  obj:
        writer.writerow(leaseterm['fields'].values())
    return response

然而,我收到一个错误:

'dict' object has no attribute 'current_tobe_payed'

我该如何解决这个问题呢? (我也想只将某些字段输入CSV而不是所有表格。)

更新:

请参阅下面的模型:

class LeaseTerm(CommonInfo):
    version = IntegerVersionField( )
    start_period = models.ForeignKey(Period, related_name='start_period' )
    end_period = models.ForeignKey(Period, related_name='end_period')
    lease = models.ForeignKey(Lease)
    increase  = models.DecimalField(max_digits=7, decimal_places=2)
    amount  = models.DecimalField(max_digits=7, decimal_places=2)
    is_terminated = models.BooleanField(default=False)

    # _total = None
    _current_period  = None
    _total_current = None

    _total_payment = None
    _total_current_payment = None

    _total_discount = None
    _total_current_discount = None

    _current_tobe_payed = None
    _current_balance = None


    def _get_total(self):
        from payment.models import LeasePayment
        from conditions.models import LeaseDiscount
        total_payment_dict = LeasePayment.objects.filter(leaseterm_id=self.id, is_active = True ).aggregate(Sum('amount'))

        if total_payment_dict ['amount__sum']:
            total_payment =  total_payment_dict['amount__sum'] 
        else:  
            total_payment =  0

        total_discount_dict = LeaseDiscount.objects.filter(leaseterm_id=self.id, is_active = True ).aggregate(Sum('amount'))

        if total_discount_dict ['amount__sum']:
            total_discount =  total_discount_dict['amount__sum'] 
        else:  
            total_discount =  0

        # current = Period.objects.filter( is_active = True, _is_current = True )

        current_date=datetime.datetime.now().date()
        current_period_dict = Period.objects.filter(start_date__lte=current_date,end_date__gte=current_date, is_active = True ).aggregate(Max('order_value'))

        #self._current_period = current_period
        if current_period_dict['order_value__max']:
            current_period =  current_period_dict['order_value__max'] 
        else:  
            current_period =  0

        current_discount_dict = LeaseDiscount.objects.filter(leaseterm_id=self.id, 
            is_active = True, period_date__gte=self.start_period,
             period_date__lte=current_period).aggregate(Sum('amount'))

        if current_discount_dict ['amount__sum']:
            current_discount =  current_discount_dict['amount__sum'] 
        else:  
            current_discount =  0

        current_periods_number = current_period - self.start_period.order_value + 1

        current_tobe_payed =  current_periods_number * self.amount -  current_discount

        current_balance =  total_payment - current_tobe_payed

        self._current_period = current_period
        self._total_payment = total_payment
        self._total_discount = total_discount
        self._current_tobe_payed  = current_tobe_payed 
        self._current_balance = current_balance


    @property
    def current_tobe_payed(self):
        if self._current_tobe_payed is None:
            self._get_total()
        return self._current_tobe_payed

    @property
    def current_balance(self):
        if self._current_balance is None:
            self._get_total()
        return self._current_balance

    @property
    def current_period(self):
        if self._current_period is None:
            self._get_total()
        return self._current_period   

    @property
    def total_payment(self):
        if self._total_payment is None:
            self._get_total()
        return self._total_payment

    @property
    def total_discount(self):
        if self._total_discount is None:
            self._get_total()
        return self._total_discount

    def clean(self):
            model = self.__class__

            if self.lease_id and (self.is_terminated == False) and (self.is_active == True) and model.objects.filter(lease=self.lease, is_active=True ).exclude(id=self.id).count() == 1:
                raise  ValidationError('!Lease has a active condition already, Terminate prior to creation of new one'.format(self.lease))

    def save(self, *args, **kwargs):
        self.full_clean()
        return super(LeaseTerm, self).save(*args, **kwargs)

    def __unicode__(self):
        return u'%s %i %s %s ' % ("term:",self.id, self.start_period, self.end_period)

3 个答案:

答案 0 :(得分:2)

您在get_total方法中进行了相当冗长的计算。我在里面计算了五个查询,下面的代码将导致为你表上的每一行执行这五个查询。

[obj for obj in leaseterms if obj.current_tobe_payed > 0]

这意味着如果表中只有1000行,则表示您正在进行5000次查询。对于10,000行,此列表理解将需要很长时间才能运行。

解决方案。将您的媒体资源转换为模型字段。

to_be_payed  = models.DecimalField(max_digits=7, decimal_places=2)

我经常告诉deves不要将简单计算的结果保存到db列中。但你的不是一个简单的计算,而是一个复杂的计算,所以它值得一个领域。你可以在保存方法中更新这个字段

def save(self, *args, **kwargs):
    self.to_be_payed = self.get_total()
    super(LeaseTerm, self).save(*args, **kwargs)

如果您说,要支付的金额取决于付款实例的更改,您可以做的是在付款模型上有一个post_save信号,以触发相关的LeaseTerm对象更新。进行这样的更新仍然比进行5000次计算更便宜

答案 1 :(得分:1)

您正在使用一个返回python词典对象的序列化程序。它不是模型的实例。我建议如下:

已编辑解决方案

def export_leaseterm_csv(request):
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="leaseterm.csv"'

    writer = csv.writer(response)

    # get all the LeaseTerm instances
    leaseterms = LeaseTerm.objects.all()

    # filter based on current_tobe_payed
    tobe_payed_terms = [obj for obj in leaseterms if obj.current_tobe_payed > 0]
    tobe_payed_dict = serializers.serialize( "python", tobe_payed_terms)
    # serialize these objects and write to values to the csv
    for term in tobe_payed_dict:
         writer.writerow(term['fields'].values())



    return response

答案 2 :(得分:0)

最后我没有信号而没有消毒器

此表中的记录数量永远不会超过100。此报告每周只由一个人在公司执行一次。在测试过程中,如果性能不足,我会将其异常化,然后我希望尽可能将其标准化。

 def export_leaseterm_csv(request):

    response = HttpResponse(content_type='text/csv')

    response['Content-Disposition'] = 'attachment; filename="leaseterm.csv"'
    writer = csv.writer(response)

    writer.writerow([
        "lease",
        "tenant",
        "amount",
        "current balance",
    ])


    leaseterms = LeaseTerm.objects.filter(is_terminated = False, is_active = True )



    tobe_payed_terms = [obj for obj in leaseterms if obj.current_balance < 0]

    for term in tobe_payed_terms:



             writer.writerow([
                term.lease,
                term.tenant,
                term.amount,
                term.current_balance,

            ])

    return response