首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何处理来自MySQL在Django的“部分”日期(2010-00-00)?

如何处理来自MySQL在Django的“部分”日期(2010-00-00)?
EN

Stack Overflow用户
提问于 2010-06-04 02:49:07
回答 5查看 4.2K关注 0票数 8

在我的一个使用MySQL作为数据库的Django项目中,我需要有一个日期字段,这些日期字段也接受“部分”日期,比如只有年份(YYYY)和年份和月份(YYYY)加上正常日期(YYYY DD)。

MySQL中的date字段可以通过接受月份和日期的00来处理这个问题。所以2010-00-00在MySQL中是有效的,它代表了2010年.2010年5月的2010-05-00年也是一样。

所以我开始创建一个PartialDateField来支持这个特性。但我遇到了麻烦,因为默认情况下,Django使用默认值,MySQLdb是MySQL的python驱动程序,它为date字段返回datetime.date对象,而datetime.date()只支持真正的日期。因此,可以修改MySQLdb使用的日期字段的转换器,并且只返回这种格式的字符串‘YYYY DD’。不幸的是,MySQLdb使用的转换器设置在连接级别,因此它用于所有MySQL日期字段。但是Django DateField依赖于数据库返回一个datetime.date对象这一事实,因此如果我将转换器更改为返回一个字符串,Django一点也不高兴。

有人有解决这个问题的主意或建议吗?如何在Django中创建PartialDateField

编辑

此外,我还应该补充说,我已经想出了两个解决方案,为年份、月和日创建了3个整数字段(如Alison R.)或者使用varchar字段将日期保持为这种格式的字符串YYYY DD。

但是在这两种解决方案中,如果我没有错,我将放松日期字段的特殊属性,比如对它们执行此类查询:在此日期之后获取所有条目。我可能可以在客户端重新实现这个功能,但在我的情况下,这不是一个有效的解决方案,因为数据库可以从其他系统(mysql客户端、MS Access等)查询。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2010-06-12 03:50:38

首先,谢谢你的回答。事实上,它们都不是解决我问题的好办法,但对于你的辩护,我应该补充一点,我没有给出所有的要求。但是每一个都帮助我思考我的问题,你的一些想法是我最后解决方案的一部分。

因此,在DB端,我的最后解决方案是使用varchar字段(限制为10个字符),并以字符串的形式将日期存储在其中,在没有月份和/或日的月份和日(如MySQL中的日期字段)中,以ISO格式(YYYY DD)形式存储00。通过这种方式,该字段可以与任何数据库一起工作,数据可以由人使用简单的客户机(如mysql客户端、phpmyadmin等)直接读取、理解和编辑。这是一项要求。它也可以导出到Excel/CSV,不需要任何转换等等。缺点是格式没有强制执行(Django除外)。有人可以写“not a date”或者在格式上做错误,DB会接受它(如果你对这个问题有想法的话.)。

通过这种方式,还可以相对轻松地执行date字段的所有特殊查询。对于使用WHERE:<,>、<=、>=和=的查询,可以直接工作。IN和中间查询也直接工作。对于按日或月进行查询,您只需使用提取程序进行查询即可( day _月.)。订购工作也是直接的。因此,我认为它涵盖了所有的查询需求,而且基本上没有复杂。

在Django一边,我做了两件事。首先,我创建了一个PartialDate对象,它看起来很像datetime.date,但支持没有月和/或日的日期。在这个对象中,我使用一个datetime.datetime对象来保存日期。我使用“小时”和“分钟”作为标志,指示当月和日设置为1时是否有效。这与steveha提议的想法相同,但具有不同的实现(仅在客户端)。使用datetime.datetime对象为我提供了许多处理日期(验证、比较等)的好功能。

其次,我创建了一个PartialDateField,它主要处理PartialDate对象和数据库之间的转换。

到目前为止,它运行得很好(我已经完成了广泛的单元测试)。

票数 7
EN

Stack Overflow用户

发布于 2010-06-04 02:54:56

您可以将部分日期存储为整数(最好是在为存储日期的部分(如year, monthday)命名的字段中),并在模型中对日期对象进行验证和转换。

编辑

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

另一方面,如果存储像2010年这样的year整数,那么很容易要求数据库提供“所有年>2010年的记录”,并且很容易从任何平台上的任何客户端了解结果。您甚至可以将这种方法结合到更复杂的日期/查询中,例如“所有记录的年份> 2010和月份> 5”。

二次编辑

您唯一的其他(也许也是最好的)选择是存储真正有效的日期,并在您的应用程序中为它们的含义制定一个约定。名为date_month的DATETIME字段的值可能为2010-05-01,但您可以将其视为表示2010年5月的所有日期。在编程时,您需要适应这一点。如果将Python中的date_month作为日期时间对象,则需要调用像date_month.end_of_month()这样的函数来查询那个月之后的日期。(这是伪代码,但可以很容易地用类似于日历模块的方式实现。)

票数 2
EN

Stack Overflow用户

发布于 2010-06-04 23:00:34

听起来你想要存储一个日期间隔。在Python中,最容易实现的方法是存储两个datetime.datetime对象,一个指定日期范围的开始,另一个指定结束。以类似于指定列表切片的方式,端点本身不会包含在日期范围内。

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

代码语言:javascript
运行
复制
>>> 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

甚至添加一些魔法:

代码语言:javascript
运行
复制
>>> 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包的丁香醇类将通过允许将一个'years‘关键字参数传递给构造函数来做到这一点,而且更有表现力。

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

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

编辑

添加更多神奇的方法来处理><运算符的使用是很有诱惑力的,但我认为这是不合适的。有一点模棱两可:一个“大于”给定范围的日期是在范围结束后还是在开始之后发生?最初,使用<=表示方程右侧的日期是范围开始后的日期,使用<表示在结束之后。

然而,这意味着幅度与幅度内日期之间的平等,这是不正确的,因为这意味着2010年5月等于2010年,因为2010年5月4日等于两者。你最终会出现像2010-04-20 == 2010 == 2010-05-04这样的谎言。

因此,可能最好实现像isafterstart这样的方法,显式地检查日期是否在范围开始之后。但同样,有人可能已经做了,所以它可能值得一看皮皮,看看什么被认为是生产就绪。这表现在给定模块的pypi页面的“类别”部分中存在“开发状态::5-生产/稳定”。注意,并非所有模块都获得了开发状态。

或者,您可以简单地使用基本的namedtuple实现,显式检查

代码语言:javascript
运行
复制
>>> datetime(2012, 12, 21) >= the_year_2010.start
True
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2971198

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档