Не запускать код во время syncdb - PullRequest
1 голос
/ 02 июня 2009

У меня есть некоторый код, который выдает, заставляет syncdb выдавать ошибку (потому что он пытается получить доступ к модели до создания таблиц).

Есть ли способ предотвратить запуск кода на syncdb? что-то вроде:

if not syncdb:
    run_some_code()

Спасибо:)

edit : PS - я думал об использовании сигнала post_init ... для кода, который обращается к БД, это хорошая идея?

Подробнее

Вот дополнительная информация по запросу:)

Я сталкивался с этим пару раз, например ... Я взломал django-cron и решил, что необходимо убедиться, что при загрузке django не существует заданий (потому что он ищет во всех установленных приложениях в любом случае и добавляет их при загрузке).

Итак, я добавил следующий код в начало файла __init__.py:

import sqlite3

try:
        # Delete all the old jobs from the database so they don't interfere with this instance of django
        oldJobs = models.Job.objects.all()
        for oldJob in oldJobs:
                oldJob.delete()
except sqlite3.OperationalError:
        # When you do syncdb for the first time, the table isn't 
        # there yet and throws a nasty error... until now
        pass

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

Как вы можете видеть, вы получаете ошибку «Операционная ошибка» (в sqlite), и трассировка стека говорит что-то вроде «таблица django_cron_job not found»

Решение

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

Этого можно достичь, выполнив его в файле urls.py, поскольку его необходимо импортировать до того, как страница будет обслуживаться (очевидно).

И мне удалось убрать этот уродливый блок try / кроме :) Слава богу (и С. Лотту)

Ответы [ 2 ]

4 голосов
/ 02 июня 2009

"edit: PS - Я думал об использовании сигнала post_init ... для кода, который обращается к БД, это хорошая идея?"

Никогда.

Если у вас есть код, который обращается к модели до создания таблиц, у вас большие и большие проблемы. Вы, вероятно, делаете что-то серьезно не так.

Обычно вы запускаете syncdb примерно один раз. База данных создана. И ваше веб-приложение использует базу данных.

Иногда вы вносили изменения в конструкцию, удаляли и воссоздали базу данных. И тогда ваше веб-приложение долгое время использует эту базу данных.

Вам (как правило) не нужен код в модуле __init__.py. У вас (почти) никогда не должно быть исполняемого кода, который действительно работает в модуле __init__.py. Это очень, очень редко и неуместно для Джанго.

Я не уверен, почему вы связываетесь с __init__.py, когда Джанго Крон говорит, что вы принимаете меры по планированию в urls.py.


Редактировать

Очистка записей - это одно.

Возиться с __init__.py и Django-cron's base.py - совершенно неверные способы сделать это. Если это так сложно, вы делаете это неправильно.

Невозможно сказать, что вы пытаетесь сделать, но это должно быть тривиально.

Ваш urls.py может работать только после syncdb и после того, как весь материал ORM был настроен и правильно привязан.

Ваш urls.py может, например, удалить несколько строк, а затем добавить несколько строк в таблицу. На данный момент все проблемы с syncdb устранены.

Почему у вас нет логики в urls.py?

2 голосов
/ 02 июня 2009

Код, который пытается получить доступ к моделям до их создания, в значительной степени может существовать только на уровне модуля; как показано в вашем примере, это должен быть исполняемый код, запускаемый при импорте модуля. Это, как вы уже догадались, причина в syncdb не работает. Он пытается импортировать модуль, но процесс импорта модуля вызывает выполнение кода уровня приложения; «побочный эффект», если хотите.

Желание избежать импорта модулей, вызывающих побочные эффекты, настолько сильно в Python, что соглашение if __name__ == '__main__': для исполняемых скриптов Python стало обычным явлением. Когда простая загрузка библиотеки кода вызывает запуск приложения, возникают головные боли: -)

Для приложений Django это становится не просто головной болью. Рассмотрим эффект выполнения oldJob.delete() каждый раз, когда модуль импортируется. Может показаться, что он выполняется только один раз при запуске с сервером разработки Django, но в производственной среде он будет выполняться довольно часто. Например, если вы используете Apache, Apache будет часто запускать несколько дочерних процессов, ожидающих обработки запросов. По мере продвижения долго работающего сервера ваше приложение Django будет загружаться каждый раз, когда обрабатывается обработчик для вашего веб-сервера, а это означает, что модуль будет импортирован и delete() будет вызываться несколько раз, часто непредсказуемо. К сожалению, сигнал не поможет, так как сигнал может запускаться каждый раз, когда также запускается процесс Apache.

Между прочим, это не просто веб-сервер, который может привести к непреднамеренному выполнению вашего кода. Если вы используете такие инструменты, как epydoc, например, они будут импортировать ваш код для создания документации API. Это, в свою очередь, приведет к тому, что логика вашего приложения начнет выполняться, что, очевидно, является нежелательным побочным эффектом от запуска анализатора документации.

По этой причине подобный код очистки лучше всего обрабатывать заданием cron, которое периодически ищет устаревшие задания и очищает базу данных. Этот пользовательский сценарий также может быть запущен вручную или любым процессом (например, во время развертывания или как часть функции модульного теста setUp(), чтобы обеспечить чистый тестовый запуск). Независимо от того, как вы это делаете, важно, чтобы такой код всегда выполнялся явно , а не неявно в результате открытия исходного файла.

Надеюсь, это поможет. Я знаю, что он не позволяет определить, запущен ли syncdb, но проблема с syncdb волшебным образом исчезнет, ​​если вы создадите приложение Django с учетом развертывания в производственных условиях.

...