Django アップグレード手順まとめ 1.6.x to 1.8.x
この記事は、Python その2 Advent Calendar 2015 の10日目の記事です。
昨日は @CS_Toku さんの Python2からPython3.0での変更点 - Qiita 。明日は @FGtatsuro さん !
どんな話題?
Webアプリを長期運用する時に避けれないのが、フレームワークのアップグレード。約1年前に作った Djangoアプリも例にもれず、1.6.xのメンテナンスが終了ということで、長期サポート(LTS)である 1.8.x へのアップグレードに取り組みました。
大まかな流れとしては、こんな感じです。
- 複数バージョンの環境を準備
- 1.6.x で Deprecateに対応
- 1.7系にバージョンをあげる
- migrate する / Deprecateに対応
- 1.8系にバージョンをあげる
- migrate する / Deprecateに対応
- その他の対応
環境
1.7で DB migrate 機能が入ったためか、結構難儀。教訓としては 『メジャーバージョンは1つずつあげていこう』 でしょうか(あたりまえ??)。
(なお migration ツール South 未使用アプリの為、利用してるケースのフローは抑えてません。あと、本来なれば test 走らせるのでしょうか、カバレッジが全然低いので動作は手動で確認。。)
事前準備
公式では、pip使ってるのであれば -U オプションで上書きとありますが、なかなか勇気いりますよね。
僕の場合は、次のような準備を行って、1つずつバージョンを上げるようにしました(DBバックアップを取得したりしながら)。
- virtualenv/virtualenvwrapper などを用意して、1.6最新 , 1.7最新 , 1.8.x(目的のバージョン)を用意
- 各種環境で django-admin startproject
しておいて、settings.py の違いをdiffっておくと、概要の把握によかった
ちなみに pip で特定バージョンにしたい場合には、こんな書式でいけます。
$ pip install -U "Django<1.8" # 1.7最新版が欲しい場合
その他、公式でオススメされてるよな Release Notes , Deprecation timeline を(可能な限り)確認しておくといいかと思います。
既存バージョンでの確認
- Wd オプションをつけることで、DeprecationWarning , PendingDeprecationWarning 等を通知してもらうことが出来るので、事前に確認しておきます。
$ python -Wd manage.py runserver
次の2つが出てきたので、対処しました。
- DeprecationWarning: The TEMPLATE_DIRS setting must be a tuple. Please fix your settings, as auto-correction is now deprecated.
- settings.py : TEMPLATE_DIRS の値が、ただの文字列だった。文字列の最後に , を付けてタプル化して対処
- PendingDeprecationWarning: Creating a ModelForm without either the 'fields' attribute or the 'exclude' attribute is deprecated - form XyzForm needs updating
- XyzForm で fields, exclude属性のいずれもない状態だった。fields属性を追加して表示するフィールドを明示して対処
アップグレード to 1.7 & 確認
virtualenvwrapper で Django 1.7環境を作り、切り替え。migrate前にDBバックアップをとっておくと安心です。
runserver すると、次のメッセージ付きで動作:
Performing system checks... System check identified no issues (0 silenced). You have unapplied migrations; your app may not work properly until they are applied. Run 'python manage.py migrate' to apply them.
migrate を実施:
$ python manage.py migrate Operations to perform: Synchronize unmigrated apps: myapp Apply all migrations: admin, contenttypes, sites, auth, sessions Synchronizing apps without migrations: Creating tables... Installing custom SQL... Installing indexes... Running migrations: Applying contenttypes.0001_initial... FAKED Applying auth.0001_initial... FAKED Applying admin.0001_initial... FAKED Applying sessions.0001_initial... FAKED Applying sites.0001_initial... FAKED
再度 runserver 。今回は特別なメッセージなく動作したので、そのまま動作確認。
$ python -Wd manage.py runserver
アップグレード to 1.8 & 確認
virtualenvwrapper で Django 1.8環境に切り替え。
runserver すると、migration を促すメッセージの他、大量のWarningが出ました(僕のアプリの場合)。
とりあえず migrate してしまう :
Operations to perform: Synchronize unmigrated apps: myapp, staticfiles, messages Apply all migrations: admin, contenttypes, sites, auth, sessions Synchronizing apps without migrations: Creating tables... Running deferred SQL... Installing custom SQL... Running migrations: Rendering model states... DONE Applying contenttypes.0002_remove_content_type_name... OK Applying auth.0002_alter_permission_name_max_length... OK Applying auth.0003_alter_user_email_max_length... OK Applying auth.0004_alter_user_username_opts... OK Applying auth.0005_alter_user_last_login_null... OK Applying auth.0006_require_contenttypes_0002... OK
再度 runserver 。-Wd オプションの有無で、次の違いがある。
- Wdなし:RemovedInDjango19Warning のみ
- Wdあり:上記に加え RemovedInDjango110Warning も出る
今回は RemovedInDjango19Warning のみを対処:
- RemovedInDjango19Warning: Default value of 'RedirectView.permanent' will change from True to False in Django 1.9. Set an explicit value to silence this warning.
- RedirectView.permanent のデフォルト値がTrueからFalseに変わるよとのこと。permanent=Ture を明示して対処
その他の対応(結構重要)
上記までの対応で、とりあえず1.8.xで動作する状態にアップグレードできました。
ただ、今後もメンテナンスする事を考えると、できるだけ1.8.xネイティブな状態が良いと考えます。最低限やったことが settings.py の書式調整。事前準備でやった、各バージョン毎のデフォルトの diff をとり違いを把握して、書式を近づけます。
- 1.6 to 1.7 : 変更多し
- SecurityMiddleware の追加
- TEMPLATE_* 変数が TEMPLATES に集約される (ちなみに RemovedInDjango110Warning の対象)
- context_processors も TEMPLATES に内包された
- 1.7 to 1.8 : 変更なし (参照ドキュメントURLのみ)
context_processor 使っていたので、がんばって対応。注意点は、globalで登録されてる context_processor の数が異なる点。場合によっては調整しながら書き換えが必要。
from django.conf import settings In [5]: settings.TEMPLATES Out[5]: [{'APP_DIRS': True, 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [], 'OPTIONS': {'context_processors': ['django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages']}}] In [6]: settings.TEMPLATE_CONTEXT_PROCESSORS Out[6]: ('django.contrib.auth.context_processors.auth', 'django.template.context_processors.debug', 'django.template.context_processors.i18n', 'django.template.context_processors.media', 'django.template.context_processors.static', 'django.template.context_processors.tz', 'django.contrib.messages.context_processors.messages')
その他、次も対応を行いました。
- urls.py の書式も微妙に変わっていたので、1.8形式にあわせる
- admin template の HEADER文字列の変更が 1.7 からサポートされたので導入
- urls.py の中で admin.site.site_header = 'My administration' のように記載する
- 上記のため、文字列変更だけのためにやってた admin template のOverwriteを削除
対応完了後
かなりあったなぁとは感じましたが、 -Wd オプションとか、Warningなどが適切にでてくるように感じましたので、時間さえとれればなんとかできるだろうレベルでした。
1つずつメジャーバージョンを上げない作業もしてみましたが、 migrate が上手くいかず。1つ前のスキーマーからの変更のみが対象になっているのかもしれません。
なにわともあれ、一回経験しておけば、次回からの心のハードルはさがりますね。ドキュメントは読もうねという気付きはハードルあげるけど。まあ、無事に終わって良かった。
参考
Advent Calendar
Advent Calendar 初参加。昨日の
Python2からPython3.0での変更点 - Qiita を見た後で、最後の1ピース!と書きましたw 明日は @FGtatsuro さん !