【问题标题】:Django 2.0 Queryset annotate dateDjango 2.0 Queryset 注释日期
【发布时间】:2018-12-30 20:53:22
【问题描述】:

有没有办法在数据库 annotate 调用中将 F() 表达式传递给函数,例如 dateutil 的 relativedelta

鉴于以下情况,InterestLoan.objects.active_loans(start_date='2018-01-01', end_date='2019-01-01') 将返回一个查询集 a给定期限内的活跃贷款。 end_date 需要使用 start_date + term注释

相反,我得到 TypeError: bad operand type for unary +: 'F'

class InterestLoanSet(models.QuerySet):
    def add_end_date(self):
        return self.annotate(loan_end_date=ExpressionWrapper(F('start_date') + relativedelta(months=+F('term'), output_field=DateField())))

    def active_loans(self, start_date, end_date):
        return self.exclude(start_date__gt=end_date).add_end_date().exclude(loan_end_date__lt=start_date)


class InterestLoan(AbstractTransaction):
    objects = InterestLoanSet.as_manager()
    interest_nominal_code = models.ForeignKey(NominalCode, null=False, on_delete=models.PROTECT)
    balance_nominal_code = models.ForeignKey(NominalCode, null=False, on_delete=models.PROTECT, related_name='loans')
    principal = models.DecimalField(max_digits=10, decimal_places=2)
    term = models.PositiveIntegerField()
    interest_rate = models.DecimalField(max_digits=4, decimal_places=4)

【问题讨论】:

  • 它对relativedelta(month=+F('term'), ...) 中的+ 进行了比较。
  • 删除 '+' 会产生不同的错误:TypeError: int() 参数必须是字符串、类似字节的对象或数字,而不是 'F' @WillemVanOnsem
  • 这是不可能的,因为表达式的全部意义在于它是在数据库中完成的。您将需要找到可以转换为 SQL 的等价物。

标签: django python-3.x django-queryset django-annotate


【解决方案1】:

这是在 Daniel Roseman 的 cmets 之后找到的解决方案,该解决方案需要在数据库中处理该表达式。

class InterestLoanSet(models.QuerySet):
    def add_end_date(self):
        return self.annotate(loan_end_year=ExpressionWrapper(ExtractYear('start_date') + F('term'), output_field=IntegerField()))

    def active_loans(self, range_start_date, range_end_date):
        return self.exclude(start_date__gt=range_end_date).add_end_date().exclude(loan_end_year__lt=range_start_date.year, start_date__month__lt=start_date.month)

class InterestLoan(AbstractTransaction):
    objects = InterestLoanSet.as_manager()
    interest_nominal_code = models.ForeignKey(NominalCode, null=False, on_delete=models.PROTECT)
    balance_nominal_code = models.ForeignKey(NominalCode, null=False, on_delete=models.PROTECT, related_name='loans')
    principal = models.DecimalField(max_digits=10, decimal_places=2)
    term = models.PositiveIntegerField()
    interest_rate = models.DecimalField(max_digits=4, decimal_places=4)

此过滤器按年度过滤,但需要更复杂才能按月或天过滤。

感谢 Kyle Hansan 的article

【讨论】:

    猜你喜欢
    • 2019-01-22
    • 1970-01-01
    • 2020-04-10
    • 2019-09-24
    • 2011-03-05
    • 2019-08-03
    • 1970-01-01
    • 1970-01-01
    • 2019-10-28
    相关资源
    最近更新 更多