如何使用字符串筛选Django中的DateField或DateTimeField?

如何使用字符串筛选Django中的DateField或DateTimeField?,django,django-models,Django,Django Models,我使用的是我的前端,它允许全局搜索(遍历所有字段以查找匹配项) 这就是我希望在django(版本1.9.1)中能够做到的: 使用“ma”作为日期字段的筛选器,以便所有三月和五月日期 归还 或 使用“Mar 1”作为日期字段的筛选器,以便 3月10日至3月19日返回 经过一些修补,我有了这个自定义查找 from django.db.models import Lookup from django.db.models.fields import DateField @DateField.r

我使用的是我的前端,它允许全局搜索(遍历所有字段以查找匹配项)

这就是我希望在django(版本1.9.1)中能够做到的:

  • 使用“ma”作为日期字段的筛选器,以便所有三月和五月日期 归还

  • 使用“Mar 1”作为日期字段的筛选器,以便 3月10日至3月19日返回
经过一些修补,我有了这个自定义查找

from django.db.models import Lookup
from django.db.models.fields import DateField

@DateField.register_lookup
class DateTextFilter(Lookup):
    lookup_name = 'dttxt'
    def as_postgresql(self, compiler, connection):
        lhs, lhs_params = self.process_lhs(compiler, connection)
        rhs = self.rhs.strftime("%b %d, %Y")
        return "to_char(%s,'Mon DD, YYYY') ~* '%s'", ([lhs,rhs])
我是这样运行的:

outputQ = Q(**{"appt_date"+"__dttxt" : "Mar 09"})
Appts.objects.filter(outputQ)
 if isinstance(<ModelName>.model._meta.get_field(searchableColumn), DateField):
        outputQ |= self._filter_by_date_field(customSearch,\
                                              searchableColumn,outputQ)
它生成运行(在Postgres中)的SQL,但当我运行filter()时,会出现错误

ValidationError: [u"'Mar 09' value has an invalid date format. 
It must be in YYYY-MM-DD format."]
公平地说,“2009年3月”不是一个有效的日期,但是原始SQL是有效的并且可以运行(我用“2016-03-09”测试了它,以绕过这个错误并让django创建SQL)

我可以使用,但这将被弃用

我可能会用这个来解析字符串(为了获得这个功能,使用原始sql是一个很大的折衷方案),但是我会失去一些我想要的功能

不确定这是否可行…

解决方案#1

创建一个方法,用于构建Q对象以测试部分中的日期:

def _filter_by_date_field(self, fld_value, searchableColumn, outputQ):
    mon_val = -1
    Mons = ['jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov','dec']
    if len(fld_value) >= 3 and fld_value[0:3].lower() in Mons:
        mon_val = next(i for i,v in enumerate(Mons) \
                    if v == fld_value[0:3].lower())+1
        outputQ |= Q(**{searchableColumn+"__month" : mon_val})
    if len(fld_value) >= 6 and mon_val > -1 and \
              re.search(r'^\d{2}$', fld_value[4:6]):
        outputQ &= Q(**{searchableColumn+"__day" : fld_value[4:6]})
    if len(fld_value) >= 8 and mon_val > -1 and \
              re.search(r'^\d{4}$', fld_value[8:12]):
        outputQ &= Q(**{searchableColumn+"__year" : fld_value[8:12]})
    return outputQ
如果该字段是DateField,则调用该方法的方式如下:

outputQ = Q(**{"appt_date"+"__dttxt" : "Mar 09"})
Appts.objects.filter(outputQ)
 if isinstance(<ModelName>.model._meta.get_field(searchableColumn), DateField):
        outputQ |= self._filter_by_date_field(customSearch,\
                                              searchableColumn,outputQ)
解决方案#2

使用CharField(原始模型使用日期字段)为模型创建数据库视图

景色

   CREATE VIEW get_appts_vw AS
    select to_char(a.appt_date,'Mon DD, YYYY') as appt_date
    ….
    from appts
这是可行的,但仍然需要对子句进行排序

解决方案#3

(我在用这个)

这样叫

from .CustomFilters import * # or whatever you name your custom filters module
....
    if isinstance(<ModelName>.model._meta.get_field(searchableColumn), DateField):
            outputQ |= Q(**{<column_name>+"__txtdt__dttxt" : <search_value>})
from.CustomFilters import*#或任何您命名的自定义过滤器模块
....
如果是实例(.model.\u meta.get\u字段(searchableColumn),则日期字段:
outputQ |=Q(**{+“uuuxtdt_uuudttxt”:})

你的最后一个看起来很奇怪。我希望
TextDate
转换中调用char(…)
,然后查询将是
列\uuuuuuxtdt\uuuuu like=value
@ShaiBerger,对您的解决方案感兴趣。我见过使用简单函数(ABS、lower等)的转换,但我没有见过转换与我所需要的类似的情况,即到字符(%s,\'Mon DD,YYYY\')。如果你有一个例子,我会非常感兴趣看到你似乎写得正确。。。试试看。请随时询问您的解决方案是否无效。在这个问题上,一个有一个参数的函数和一个有两个参数且其中一个参数是常数的函数之间没有什么区别。
from django.db.models import Lookup
from django.db.models.fields import DateField
from django.db.models import CharField, Transform

@DateField.register_lookup
class TextDate(Transform):
    lookup_name = 'txtdt'

    @property
    def output_field(self):
        return CharField()


@TextDate.register_lookup
class DateTextFilter(Lookup):
    lookup_name = 'dttxt'

    def as_postgresql(self, compiler, connection):
        lhs, lhs_params = compiler.compile(self.lhs.lhs)
        rhs, rhs_params = self.process_rhs(compiler, connection)
        params = lhs_params + rhs_params
        return 'to_char(%s,\'Mon DD, YYYY\') ~* %s ' % (lhs, rhs), params
from .CustomFilters import * # or whatever you name your custom filters module
....
    if isinstance(<ModelName>.model._meta.get_field(searchableColumn), DateField):
            outputQ |= Q(**{<column_name>+"__txtdt__dttxt" : <search_value>})