Django - Oracle后端错误

时间:2013-03-20 13:44:16

标签: django oracle oracle10g django-orm cx-oracle

我在Django中有以下模型:

class Event(models.Model):
    # some fields
    start_date = models.DateField()
    end_date = models.DateField()

我正在使用带有Django 1.5和cx_oracle 5.1.2的Oracle 10g数据库。这里的问题是当我尝试在管理界面中创建一个新对象(从日历中选择日期)时,会引发以下错误:

ORA-01843: not a valid month

syncdb已在oracle中为DATEstart_date创建了end_date字段。这看起来像是后端错误还是我做错了什么?

我确实有其他模型DateTimeField(),当我持久保存新对象时它们工作正常,问题看起来与DateField本身有关。

更新:我已检查了后端实施,并在backends/oracle/base.py行513到516中进行了检查:

cursor.execute(
    "ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS'"
    " NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF'"
    + (" TIME_ZONE = 'UTC'" if settings.USE_TZ else ''))

执行此语句允许insert语句具有DATE个字段的文字值。我检查了后端生成的查询,并在'2013-03-20'start_date中插入了end_date。日期与NLS_DATE_FORMAT匹配,因此理论上这应该有效!

更新:我认为我的案例是related to cx_oracle

更新:由于我仍然没有明确的答案(虽然我几乎可以肯定它是导致此问题的cx_oracle),但我将DateField更改为{{1}这转化为oracle的DateTimeField,并且完美无缺。

2 个答案:

答案 0 :(得分:1)

基于jtiai问题description,我做了以下解决方法 - 在调用任何有问题的sql-s(例如oracle 10.5.0.2和11.2.0.1,cx_oracle 5.1.2)之前,重置NLS_DATE_FORMAT / NLS_TIMESTAMP_FORMAT再次 - 在方法def execute(...)中的django / db / backends / oracle / base.py中完成:

--- base.py 2013-10-31 12:19:24.000000000 +0100
+++ base_new.py 2013-10-31 12:20:32.000000000 +0100
@@ -707,6 +707,18 @@
         query = convert_unicode(query % tuple(args), self.charset)
         self._guess_input_sizes([params])
         try:
+            # BUG-WORKAROUND: ulr1-131031 
+            # https://stackoverflow.com/a/17269719/565525
+            # It's actually a bug in the Oracle 10.5.0.2 and 11.2.0.1. Bug can be reproduced as following:
+            #     - set NLS_TIMESTAMP_FORMAT in session.
+            #     - Run any implicit or explicit TO_DATE conversion with unicode data.
+            #     - **Next implicit or explicit TO_TIMESTAMP with unicode data will trigger internal reset of timestamp format.**
+            #     - All consecutive TO_TIMESTAMP will fail and TO_CHAR of timestamp will produce invalid output.
+            self.cursor.execute(
+                "ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS'"
+                " NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF'"
+                + (" TIME_ZONE = 'UTC'" if settings.USE_TZ else ''))
+
             return self.cursor.execute(query, self._param_generator(params))
         except Database.IntegrityError as e:
             six.reraise(utils.IntegrityError, utils.IntegrityError(*tuple(e.args)), sys.exc_info()[2])

答案 1 :(得分:-2)

错误原因是您输入了日期,但日期的月份部分不是有效月份。 Oracle为此问题提供了解决方案。

1 - 使用MONTHMON格式掩码重新输入日期值。月份的有效值为:

January
February
March
.......
//and soon

OR

Jan
Feb
Mar
.......
//and soon

2 - 如果上述解决方案失败,请改用to_date function

to_date( string1, [ format_mask ], [ nls_language ] )