通过检查一个日期时间与另一个月份的月份来过滤模型

时间:2013-11-13 17:16:55

标签: django datetime orm

使用Django的ORM,我试图根据两个日期时间变量找到myModel的实例;具体而言,这两个日期的月份不相等。我理解过滤一个modelfield的值,你可以使用Django的F( ) expressions,所以我想我会尝试这样的事情:

myModel.objects.filter(fixed_date__month=F('closed_date__month'))

我知道这不会发现它们不相等的情况,但我认为这是一个很好的第一步,因为我之前从未使用过F表达式。但是,它并没有像我想象的那样有效。我希望它能给我一个对象的查询集,其中fixed_date月的值等于closed_date月的值,但我得到一个错误:

FieldError: Join on field 'closed_date' not permitted. Did you misspell 'month' for the lookup type?

我不确定我尝试做的事情是不可能的,也不是简单的ORM,或者我只是犯了一个简单的错误。

2 个答案:

答案 0 :(得分:2)

看起来django F对象目前不支持在DateTimeField内提取月份,错误消息似乎表明F对象正在尝试转换字符串'closed_date__month'中的'__'作为不同对象之间的Foreignkey,通常作为连接存储在sql数据库中。

您可以通过迭代对象来执行相同的查询:

result = []
for obj in myModel.objects.all():
    if obj.fixed_date.month != obj.closed_date.month:
        result.append(obj)

或作为列表理解:

result = [obj for obj in myModel.objects.all() if obj.fixed_date.month != obj.closed_date.month]

或者,如果效率不高,则两个日期的月份可以缓存为模型中的IntegerFields,如:

 class myModel(models.Model):
     ....other fields....
     fixed_date = models.DateTimeField()
     closed_date = models.DateTimeField()
     fixed_month = models.IntegerField()
     closed_month = models.IntegerField()

在相关日期更新时存储两个整数:

myModel.fixed_month = myModel.fixed_date.month
myModel.save()

然后使用F对象比较两个整数字段:

myModel.objects.filter(fixed_month__ne=F('closed_month'))

ne修饰符将执行不相等的测试。

编辑 - 使用原始SQL

如果您使用的是基于sql的数据库,那么最有效的方法是使用.raw()方法手动指定sql:

myModel.objects.raw('SELECT * FROM stuff_mymodel WHERE MONTH(fixed_date) != MONTH(close_date)')

其中'stuff_mymodel'是数据库中表的正确名称。这使用SQL MONTH()函数从月份字段中提取值,并比较它们的值。它将返回一组对象。

有关django查询系统的一些说法,例如:http://charlesleifer.com/blog/shortcomings-in-the-django-orm-and-a-look-at-peewee-a-lightweight-alternative/。这个例子可以用来证明它的查询api中的另一个不一致。

答案 1 :(得分:1)

我的想法是:

class myModel(models.Model):
    fixed_date = models.DateTimeField()
    closed_date = models.DateTimeField()

    def has_diff_months(self):
        if self.fixed_date.month != self.closed_date.month:
            return True
        return False

然后:

[x for x in myModel.objects.all() if x.has_diff_months()]

但是,要获得真正有效的解决方案,您必须使用其他列。对我来说这是有意义的,它是你保存时创建的计算布尔字段,如下所示:

class myModel(models.Model):
    fixed_date = models.DateTimeField()
    closed_date = models.DateTimeField()
    diff_months = models.BooleanField()

    #overriding save method
    def save(self, *args, **kwargs):
        #calculating the value for diff_months
        self.diff_months = (self.fixed_date.month != self.closed_date.month)
        #aaand... saving:              
        super(Blog, self).save(*args, **kwargs)

然后过滤就是:

myModel.objects.filter(diff_months=True)