読者です 読者をやめる 読者になる 読者になる

AWS / PHP / Python ちょいメモ

amazon web service , PHP, Python を使ったときのメモ。日本語でググってもわからなかった事を中心に。

Django アップグレード手順まとめ 1.6.x to 1.8.x

Django 運用

この記事は、Python その2 Advent Calendar 2015 の10日目の記事です。

昨日は @CS_Toku さんの Python2からPython3.0での変更点 - Qiita 。明日は @FGtatsuro さん !

どんな話題?

Webアプリを長期運用する時に避けれないのが、フレームワークのアップグレード。約1年前に作った Djangoアプリも例にもれず、1.6.xのメンテナンスが終了ということで、長期サポート(LTS)である 1.8.x へのアップグレードに取り組みました。

大まかな流れとしては、こんな感じです。

  1. 複数バージョンの環境を準備
  2. 1.6.x で Deprecateに対応
  3. 1.7系にバージョンをあげる
  4. migrate する / Deprecateに対応
  5. 1.8系にバージョンをあげる
  6. migrate する / Deprecateに対応
  7. その他の対応

環境

  • Django 1.6.8 で当初開発
  • 開発したmyapp , auth, adminぐらいで構成された比較的小さなプロジェクト
  • DBMSは開発環境のSQLiteと、本番環境のMySQLの2つ


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 さん !