Django - ошибка серверной части Oracle

У меня в Django есть следующая модель:

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

Я использую базу данных Oracle 10g с Django 1.5 и cx_oracle 5.1.2. Проблема здесь в том, что когда я пытаюсь создать новый объект в интерфейсе администратора (выбирая даты из календаря), возникает следующая ошибка:

ORA-01843: not a valid month

syncdb создал DATE поле в oracle для start_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 ''))

Выполнение этого оператора позволяет оператору вставки иметь буквальные значения для полей DATE. Я проверил запрос, сгенерированный серверной частью, и он вставляет '2013-03-20' в start_date и end_date. Дата совпадает с NLS_DATE_FORMAT, так что теоретически это должно работать!

ОБНОВЛЕНИЕ: я считаю, что мой случай - относится к cx_oracle.

ОБНОВЛЕНИЕ: поскольку у меня до сих пор нет однозначного ответа (хотя я почти уверен, что эту проблему вызывает cx_oracle), я изменил свой DateField на DateTimeField, который переводится в TIMESTAMP оракула и отлично работает .


person Aziz Alfoudari    schedule 20.03.2013    source источник
comment
Итак, для ясности, вы проверяете таблицы Oracle SYS на предмет выполняемого SQL и видите в своей вставке что-то вроде TO_DATE('2013-03-20', 'YYYY-MM-DD')? Судя по вашему вопросу, это похоже на NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS', что отличается от фактической вставки, хотя я не знаю, какой эффект это будет иметь в этом контексте.   -  person woemler    schedule 22.03.2013
comment
Нет, из-за установки NLS_DATE_FORMAT оператора alter session вы можете вставить дату как литерал без to_date, что имеет место, когда я проверяю выполняемый SQL.   -  person Aziz Alfoudari    schedule 22.03.2013
comment
Можете ли вы опубликовать соответствующий SQL-запрос, который выполняется на сервере, что приводит к ошибке ORA-01843?   -  person woemler    schedule 22.03.2013
comment
В настоящее время у меня нет доступа к системе, но я попытался выполнить инструкцию SQL в SQL-клиенте, и она сработала нормально. Кстати, мне не удалось получить запрос из базы данных, так как он вызвал ошибку и, как мне кажется, не был выполнен. Распечатал в консоли.   -  person Aziz Alfoudari    schedule 22.03.2013
comment
Это может быть полезно при диагностике вашей проблемы: stackoverflow.com/questions/3468216/   -  person woemler    schedule 22.03.2013
comment
Что такое cursor? Это объект подключения или объект набора записей?   -  person Rachcha    schedule 22.03.2013
comment
Models.DateField () использует datetime.date [docs.djangoproject.com/en/dev/ref/models/fields/ В строках base.py 182–191 упоминается, как cx_oracle всегда возвращает datetime.datetime, поэтому он выполняет некоторое преобразование. Для подтверждения, вы проверили запрос, включив подробный вывод?   -  person John D    schedule 23.03.2013
comment
@JohnD Я добавил оператор печати в base.py в строке 774 для печати запросов и еще один оператор печати для списка, созданного self._param_generator(params); Я хотел увидеть, что передается в БД непосредственно перед ее выполнением, поскольку это ошибка ORA.   -  person Aziz Alfoudari    schedule 23.03.2013
comment
Итак, как выглядит SQL?   -  person igr    schedule 26.03.2013


Ответы (2)


На основе jtiai проблема описание, я сделал следующее обходное решение - перед вызовом любых проблемных sql-s (например, oracle 10.5.0.2 и 11.2.0.1, cx_oracle 5.1.2) снова сбросьте NLS_DATE_FORMAT / NLS_TIMESTAMP_FORMAT - выполняется в django / db / backends / oracle / base .py в методе def execute(...):

--- 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])
person Robert Lujo    schedule 31.10.2013

Причина ошибки в том, что вы ввели дату, но часть даты, указанная в месяце, не является допустимым месяцем. Oracle дает решения для этой проблемы.

1 - повторно введите значение даты, используя маску формата MONTH или MON. Допустимые значения для месяца:

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

OR

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

2 - если вышеуказанное разрешение не удалось, используйте вместо этого to_date function.

to_date( string1, [ format_mask ], [ nls_language ] )
person catherine    schedule 04.04.2013