代码之家  ›  专栏  ›  技术社区  ›  Etienne

如何处理Django中MySQL的“部分”日期(2010-00-00)?

  •  8
  • Etienne  · 技术社区  · 14 年前

    日期 也接受“部分”日期的字段,如仅年(YYYY)、年和月(YYYY-MM)加上正常日期(YYYY-MM-DD)。

    这个 日期 MySQL中的字段可以通过接受 一个月一天。所以呢 2010-00-00 2010-05-00

    所以我开始创造一个 PartialDateField 以支持此功能。但是我遇到了麻烦,因为在默认情况下,Django使用默认值MySQLdb,MySQL的python驱动程序,返回一个 datetime.date 日期 datetime.date() 只支持真实日期。因此,有可能修改转换器的 字段,并仅返回此格式的字符串 '年-月-日' . 不幸的是,MySQLdb使用的转换器是在连接级别设置的,所以它适用于所有MySQL 日期 领域。但是Django DateField 依赖于数据库返回 datetime.date日期 对象,因此如果我将转换器更改为返回字符串,Django一点也不高兴。

    有人有解决这个问题的想法或建议吗?如何创建

    编辑

    艾莉森R。 瓦尔查尔 年-月-日 .

    a的性质 类似于对其执行此类查询的字段: . 我可能可以在客户端重新实现这个功能,但在我的例子中这不是一个有效的解决方案,因为数据库可以从其他系统(mysql客户端、MS Access等)进行查询

    5 回复  |  直到 14 年前
        1
  •  7
  •   Etienne    14 年前

    首先,谢谢你的回答。从目前的情况来看,没有一个能很好地解决我的问题,但是,为了你的辩护,我应该补充一点,我没有给出所有的要求。但每一个都帮助我思考我的问题,你的一些想法是我最终解决方案的一部分。

    所以我的最终解决方案,在DB方面,是使用 瓦尔查尔 00 对于没有月份和/或日期的月份和日期(如 MySQL中的字段)。通过这种方式,这个字段可以与任何数据库一起工作,数据可以由一个人使用一个简单的客户机(比如mysql客户机、phpmyadmin等)直接、轻松地读取、理解和编辑。这是一个要求。它也可以导出到Excel/CSV没有任何转换等缺点是,格式是不强制(除了在Django)。有人可以写 '不是约会' 或者在格式上做一个错误,DB会接受它(如果你对这个问题有想法…)。

    这样也可以做所有的 特殊的 a的查询 日期

    在Django方面,我做了两件事。首先,我创建了一个 PartialDate datetime.date 但支持日期没有月份和/或日期。在这个对象中,我使用datetime.datetime对象来保存日期。我使用小时和分钟作为标志,当月和日被设置为1时,它会告诉我们它们是否有效 史蒂夫哈 建议但采用不同的实现(并且仅在客户端)。使用 datetime.datetime 对象为我提供了很多处理日期的好特性(验证、比较等)。

    PartialDateField 主要处理 分部酸

    到目前为止,它运行得非常好(我基本上已经完成了大量的单元测试)。

        2
  •  2
  •   Alison R.    14 年前

    您可以将部分日期存储为整数(最好是存储在一个以您正在存储的日期部分命名的字段中,例如 year, month day

    编辑

    如果你需要真正的日期功能,你可能需要真正的,而不是部分,日期。例如,“get everything after 2010-0-0”的返回日期是包括2010年还是仅包括2011年及以后的日期?2010年5月的另一个例子也是如此,不同语言/客户端处理部分日期的方式(如果它们完全支持的话)可能非常特殊,而且不太可能与MySQL的实现相匹配。

    另一方面,如果你储存 year 整数,例如2010,很容易在数据库中查询“所有年份记录”>了解任何客户在任何平台上的结果。您甚至可以将此方法组合用于更复杂的日期/查询,例如“所有记录的年份”>2010年及以后月份>5".

    第二次编辑

    您唯一的另一个(也许是最好的)选择是存储真正有效的日期,并在应用程序中为它们的含义制定一个约定。一个名为like的DATETIME字段 date_month 可能有一个值2010-05-01,但您会将其视为代表2010年5月的所有日期。在编程时需要考虑到这一点。如果你有 在Python中,作为datetime对象,需要调用如下函数 date_month.end_of_month() 查询该月之后的日期(这是伪代码,但是可以用 calendar

        3
  •  2
  •   intuited    14 年前

    听起来像是要存储日期间隔。在Python中,这一点(据我所知)最容易通过存储两个datetime.datetime对象来实现,一个指定日期范围的开始,另一个指定结束。与用于指定列表切片的方式类似,端点本身不会包含在日期范围中。

    例如,此代码将日期范围实现为命名元组:

    >>> from datetime import datetime
    >>> from collections import namedtuple
    >>> DateRange = namedtuple('DateRange', 'start end')
    >>> the_year_2010 = DateRange(datetime(2010, 1, 1), datetime(2011, 1, 1))
    >>> the_year_2010.start <= datetime(2010, 4, 20) < the_year_2010.end
    True
    >>> the_year_2010.start <= datetime(2009, 12, 31) < the_year_2010.end
    False
    >>> the_year_2010.start <= datetime(2011, 1, 1) < the_year_2010.end
    False
    

    甚至可以添加一些魔法:

    >>> DateRange.__contains__ = lambda self, x: self.start <= x < self.end
    >>> datetime(2010, 4, 20) in the_year_2010
    True
    >>> datetime(2011, 4, 20) in the_year_2010
    False
    

    relativedate 来自 dateutil 包将通过允许将“years”关键字参数传递给构造函数来实现这一点,而且更具表现力。

    但是,将这样一个对象映射到数据库字段要复杂一些,因此实现它最好只需将这两个字段分开,然后将它们组合起来。我猜这取决于DB框架;我对Python的这方面还不是很熟悉。

    无论如何,我认为关键是把“部分日期”看作一个范围,而不是一个简单的值。

    编辑

    添加更多的魔法方法来处理 > < 操作员。这里有点模棱两可:一个“大于”给定范围的日期是发生在范围结束之后,还是开始之后?最初似乎应该使用 <= 表示公式右侧的日期在范围开始之后,以及 < 表示它在结束之后。

    但是,这意味着范围和范围内的日期相等,这是不正确的,因为它意味着2010年5月等于2010年,因为2010年5月4日等于这两者。你最后会变成这样 2010-04-20 == 2010 == 2010-05-04 是真的。

    因此,实现这样的方法可能更好 isafterstart 显式检查日期是否在范围的开始之后。但话说回来,可能有人已经做过了,所以可能值得一看 pypi 看看什么是可以生产的。在给定模块的pypi页面的“Categories”部分中出现“Development Status::5-Production/Stable”就表明了这一点。注意,并不是所有模块都被赋予了开发状态。

    >>> datetime(2012, 12, 21) >= the_year_2010.start
    True
    
        4
  •  1
  •   steveha    14 年前

    你能把日期和一个标志一起存储吗?这个标志告诉你有多少日期是有效的?

    YEAR_VALID = 0x04
    MONTH_VALID = 0x02
    DAY_VALID = 0x01
    
    Y_VALID = YEAR_VALID
    YM_VALID = YEAR_VALID | MONTH_VALID
    YMD_VALID = YEAR_VALID | MONTH_VALID | DAY_VALID
    

    那么, PartialDateField 将是一个类,它将日期和上面描述的日期有效标志捆绑在一起。

        5
  •  1
  •   Blue Waters    12 年前

    虽然不是在Python中,但下面是一个在Ruby中如何解决相同问题的示例—使用单个整数值和按位运算符存储年、月和日,其中月和日是可选的。

    https://github.com/58bits/partial-date

    我相信类似的解决方案也可以用Python编写。

    要持久化日期(可排序),只需将整数保存到数据库中。