Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用注释在Djangorm中创建通知日期字段_Django_Python 2.7_Django Queryset_Django Orm_Django Filter - Fatal编程技术网

如何使用注释在Djangorm中创建通知日期字段

如何使用注释在Djangorm中创建通知日期字段,django,python-2.7,django-queryset,django-orm,django-filter,Django,Python 2.7,Django Queryset,Django Orm,Django Filter,我想使用djangorm中的注释创建一个名为notification\u date的新字段 这是我的模型: SpeciesType(models.Model): # ... some species type setting fields. heat_lapse = IntegerField() estrous = IntegerField() Breeding(models.Model): # .. some breeding fields species_

我想使用djangorm中的注释创建一个名为
notification\u date
的新字段

这是我的模型:

SpeciesType(models.Model):
   # ... some species type setting fields.
   heat_lapse = IntegerField()
   estrous = IntegerField()


Breeding(models.Model):
   # .. some breeding fields

   species_type = ForeignKey(SpeciesType, related_name="breedings", on_delete=CASCADE)


   created_at = DateTimeField(auto_add_now=True)
现在育种日期通知的公式是

Breeding.created_at + (SpeciesType.heat_lapse * SpeciesType.estrous) in days 
例如2017年1月29日11:21PM+(3*21)天=2017年4月2日作为通知日期

from datetime import date, timedelta

from django.db import models
from django.utils.functional import cached_property


Breeding(models.Model):
    # .. your breeding fields

    @cached_propery
    def notification_date(self):
        delta = timedelta(days=(self.species_type.heat_leapse * self.species_type.estrous))
        return self.created_at + delta
因此,为了实现这一点,我使用timedelta、F()对象和ExpressionWrapper创建了这个查询过滤器:

from django.db.models import F, ExpressionWrapper, DateField
from datetime import date, timedelta

Breeding.objects.annotate(
     notification_date = ExpressionWrapper(
        F('created_at') + 
        timedelta(days=(
            F('species_type__heat_lapse') * F('species_type__estrous')
        ))
     , output_field=DateField())
).filter(
    notification_date__lte == date.today()
)
但是这不起作用,因为你不能在时间差内做F()。有人知道如何表达这个期望的查询吗?这对我来说是一个很大的帮助。

< P>也许考虑在你的模型上使用A。这将更容易,并且不涉及任何额外的查询。如果您小心,所有使用的值都已正确预取。您也可以像使用普通属性一样使用它,这意味着使用
my\u breading\u实例访问它。notification\u date

from datetime import date, timedelta

from django.db import models
from django.utils.functional import cached_property


Breeding(models.Model):
    # .. your breeding fields

    @cached_propery
    def notification_date(self):
        delta = timedelta(days=(self.species_type.heat_leapse * self.species_type.estrous))
        return self.created_at + delta
此外,该值将在首次访问后缓存

更新:

如果您确实需要对其进行注释,因为您想在
通知\u日期
上进一步过滤查询集,那么您必须编写自己的聚合函数

正如您已经注意到的,您不能在注释中使用timedelta,因为要注释的值必须完全在数据库中计算。因此,只能使用数据库函数进行计算

Django提供了一些类似于
SUM
COALESCE
或similar的工具,可以在查询中生成有效的sql

然而,您需要的一个并没有在django中实现。但是你可以自己写。mysql需要的一个名为。该函数必须创建如下所示的sql:

SELECT OrderId,DATE_ADD(OrderDate,INTERVAL 30 DAY) AS OrderPayDate FROM Orders
class DateAdd(models.Func):
    """
    Custom Func expression to add date and int fields as day addition
    """
    function = 'DATE_ADD'
    arg_joiner = ", INTERVAL "
    template = "%(function)s(%(expressions)s DAY)"
    output_field = models.DateTimeField()
DATE_ADD("created_at", INTERVAL ("heat_lapse" * "estrous") DAY) AS "notifiaction_date"
qs = Breeding.objects.annotate(
    notifiaction_date=DateAdd('created_at', (models.F('species_type__heat_lapse') * models.F('species_type__estrous')))
)
应该是这样的:

SELECT OrderId,DATE_ADD(OrderDate,INTERVAL 30 DAY) AS OrderPayDate FROM Orders
class DateAdd(models.Func):
    """
    Custom Func expression to add date and int fields as day addition
    """
    function = 'DATE_ADD'
    arg_joiner = ", INTERVAL "
    template = "%(function)s(%(expressions)s DAY)"
    output_field = models.DateTimeField()
DATE_ADD("created_at", INTERVAL ("heat_lapse" * "estrous") DAY) AS "notifiaction_date"
qs = Breeding.objects.annotate(
    notifiaction_date=DateAdd('created_at', (models.F('species_type__heat_lapse') * models.F('species_type__estrous')))
)
这将创建如下所示的sql:

SELECT OrderId,DATE_ADD(OrderDate,INTERVAL 30 DAY) AS OrderPayDate FROM Orders
class DateAdd(models.Func):
    """
    Custom Func expression to add date and int fields as day addition
    """
    function = 'DATE_ADD'
    arg_joiner = ", INTERVAL "
    template = "%(function)s(%(expressions)s DAY)"
    output_field = models.DateTimeField()
DATE_ADD("created_at", INTERVAL ("heat_lapse" * "estrous") DAY) AS "notifiaction_date"
qs = Breeding.objects.annotate(
    notifiaction_date=DateAdd('created_at', (models.F('species_type__heat_lapse') * models.F('species_type__estrous')))
)
使用arg_joiner连接
DateAdd
函数的两个参数,从而创建必要的sql,这是一个肮脏的把戏

您可以这样使用它:

SELECT OrderId,DATE_ADD(OrderDate,INTERVAL 30 DAY) AS OrderPayDate FROM Orders
class DateAdd(models.Func):
    """
    Custom Func expression to add date and int fields as day addition
    """
    function = 'DATE_ADD'
    arg_joiner = ", INTERVAL "
    template = "%(function)s(%(expressions)s DAY)"
    output_field = models.DateTimeField()
DATE_ADD("created_at", INTERVAL ("heat_lapse" * "estrous") DAY) AS "notifiaction_date"
qs = Breeding.objects.annotate(
    notifiaction_date=DateAdd('created_at', (models.F('species_type__heat_lapse') * models.F('species_type__estrous')))
)
我从中获取了一些,但这是一个只适用于postgres的函数。我测试了这个,它在postgres数据库上运行。我没有为mysql测试我的代码,所以你可能需要对它进行一些调整。但这基本上就是如何做到的


如果您想了解更多关于如何编写自己的表达式,或者深入了解Django源代码,并查看已经实现的表达式,比如./P>由一个实例访问它将影响它的性能,考虑有多少记录与<代码> MyAsPultIGIN实例。如果使用get()获取实例,则会找到if,但是filter可能意味着更大的记录,因此我想您必须编写自己的
Func
。这取决于您使用的数据库。对于postgres,你必须使用
INTERVAL
函数,对于mysql,你必须使用
DATEADD
。我使用的是mysql,Func是什么意思?类似于存储过程的东西?