在我的模型中,我计算了属性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)
答案 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