【问题标题】:Comparing dates stored as strings in Django比较在 Django 中存储为字符串的日期
【发布时间】:2013-02-25 00:20:40
【问题描述】:

我的数据库中包含一列以字符串格式 (varchar) 存储的日期,例如 "12-Mar-2011""11-Apr-2012" 等。有没有办法在 Django 中比较这些日期?

models.py 中,列定义为字符串格式。例如:

startdate = models.CharField(max_length=11)

现在我必须将这些日期与日期进行比较。任何帮助表示赞赏。

【问题讨论】:

    标签: django django-models python-2.7


    【解决方案1】:

    在您的models.py 中,添加一个返回datetime 对象的方法,如下所示:

    from datetime import datetime as dt
    
    class SomeModel(models.Model):
        # other fields
    
        def startdate_as_date(self):
            return dt.strptime(self.startdate,'%d-%b-%Y')
    

    我省略了一些错误检查(例如确保设置了 startdate)并检查日期是否为有效日期 - 您应该稍后添加这些。

    现在你可以这样做了:

    foo = SomeModel.objects.get(pk=1)
    the_date = foo.startdate_as_date()
    

    现在the_date 是一个datetime 对象,您可以使用它进行常规比较。

    【讨论】:

    • 感谢您的快速回复。但是现在我可以像 obj = SomeModel.filter(the_date__gte=givenDate) 一样使用 the_date 吗?
    • 不,为了做到这一点,您必须按照 Francis 的建议迁移数据库并更改模型中的类型。
    • 现在除了迁移之外,还有什么方法可以作为比较数据库中存储为字符串的日期的临时修复方法吗?
    【解决方案2】:

    这不是您要寻找的答案,但是...

    真的应该将您的数据库迁移到使用models.DateField 类型。

    除此之外,

    objects = YourModel.objects.raw("""
        SELECT 
            STR_TO_DATE(your_string_date_field, '%e-%b-%Y') AS a_mysql_date_field,
            *
        FROM your_table
        """)
    

    做一个原始查询来获取字符串日期作为实际的mysql日期,也许你可以用它来完成你想要做的任何事情。

    【讨论】:

    • 你的建议是 100% 正确的。我们必须进行迁移。但现在我正在寻找解决这个问题的临时方法。原始对象的问题是它们无法分页。即使我们不能为他们编写 len(obj) 来编写我们自己的分页函数
    【解决方案3】:

    您还可以使用注释创建一个新的虚拟字段,以日期时间格式包含您的值。

    from django.db.models.expressions import RawSQL
    Yourmodel.objects.annotate(startdate_datetime = RawSQL("SELECT STR_TO_DATE(startdate, '%%d-%%b-%%Y')", ())
    

    注意:

    • 您的数据库必须支持STR_TO_DATE。据我所知,MySQL和PostgreSQL都有这个功能。
    • 有双重%,因为RawSQL函数实际上在内部做了一些格式化,所以%必须被转义。
    • 如果您的请求无效,则字段值为None。例如,如果您使用不存在的格式字符或无效的格式值。例如如果您尝试使 %m 匹配大于 12 的月份等。

    【讨论】:

      【解决方案4】:

      通过使用 Func、Value 和 MySQL 的 STR_TO_DATE 函数创建自定义管理器并将此管理器添加到您的模型中,然后对其进行过滤,您完全可以完全按照您想要的方式进行操作,而无需使用原始 SQL。如果您使用 MySQL 或 MariaDB 以外的其他数据库后端,您可能需要相应地更改您提供给 Func 的函数字符串和模式。

      ma​​nagers.py:

      from django.db import models
      from django.db.models import Value, Func
      
      class WeirdDateManager(models.Manager):
      
          def get_queryset(self):
              queryset = super().get_queryset()
              queryset = queryset.annotate(
                  start_date = Func(
                      Value('start_date_string'),
                      Value('%d-%b-%Y'),
                      function='STR_TO_DATE',
                  ),
              )
              return queryset
      

      models.py:

      from .managers import WeirdDateManager
      
      class WeirdDateModel(models.Model):
      
          objects = WeirdDateManager()
      
          start_date_string = models.CharField(db_column="startdate", max_length=11) # I've renamed your field here so that I can use the start_date name to filter on the actual date, not the string.
      

      views.py:

      from .models import WeirdDateModel
      
      objects = WeirdDateModel.objects.filter(start_date__gte = given_date)
      

      【讨论】:

        猜你喜欢
        • 2020-12-25
        • 1970-01-01
        • 2012-10-19
        • 1970-01-01
        • 2011-12-18
        • 2015-08-14
        • 2013-12-23
        • 2015-09-29
        • 1970-01-01
        相关资源
        最近更新 更多