これは何?
普段Djangoで開発していて、たまに思うことがあるかもしれません。
今問題なく動いているんだけど、アプリケーション名がちょっと気に食わない。
試しにただフォルダ名を変更してみると、不要なテーブルが出来てしまい、既存のデータも使えません。
「既存のテーブルに入っているデータはそのまま使いつつ、アプリケーション名を変更したい」という時に何をすればいいのか
色々な方法があると思いますが、そのうちの一つとしてまとめました。
結論
stack overflow/How to change the name of a Django app?
ここに書いている通りです。
- フォルダ名を変更する
- AppConfigを変更, settingsの
INSTALLED_APPS
を変更する - アプリケーション名変更前のテーブルを新しいアプリケーション名に合わせてrenameする
- django_content_typeとdjango_migrationsを書き換える
の4ステップで既存のコードやレコードはそのままにアプリケーション名を変更することが出来ました。
なぜ上記のステップが必要なのか。
なぜフォルダ名を変更しただけでは想定通りの動きをしてくれないのかを簡単に書きます。
Djangoのmigrationは、django_migrations
テーブルで管理されています。(Sequel Proを使っています)
↓django_migrations
appカラムはsettings.py
のINSTALLED_APPS
、
nameカラムは各アプリケーションのmigrations
内のファイル名が入っています。
また、Modelはdjango_content_type
テーブルで管理されています。
↓django_content_type
app_labelカラムは同様にsettings.py
のINSTALLED_APPS
、
modelカラムは各アプリケーション内のmodels.py
のモデル名が入っています。
フォルダ名を変更したとしても、これらがそのままだと、Djangoから新しい全く違うアプリケーションが作成された
と認識されてしまいます。
上記の3, 4のステップを踏むことで、Djangoにrenameしたアプリケーションを元からあるものだと認識してもらう必要があります。
下では手を動かした過程を書いています。
興味のある方は是非読んでみてください。
前提
作った blogs app
を vlogs app
に renameしたくなったとします。
blogs app
を作ります。
1: Django projectを作成
$ django-admin startproject my-site
2: blogs app を作成
$ python manage.py startapp blogs
3: PostModelを作成
blogs/models.py
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=255)
4: migrationを走らせる
my-site/settings.py
INSTALLED_APPS = [
'blogs.apps.BlogsConfig',
...
]
$ python manage.py migrate
ここから blogs
をvlogs
に変更します。
1.フォルダ名を変更する
試しにフォルダ名を変更するだけだとどうなるのかを紹介します。
/blogs
→ /vlogs
とします。
この状態で
$ python manage.py migrate
とするともちろん
ModuleNotFoundError: No module named 'blogs'
となります。
では次です。
2. AppConfigを変更, settingsのINSTALLED_APPS
を変更する
1で怒られてしまったように、INSTALLED_APPS
を編集しなければいけません。
vlogs/apps.py
from django.apps import AppConfig
class VlogsConfig(AppConfig):
name = 'vlogs'
settings.py
INSTALLED_APPS = [
'vlogs.apps.VlogsConfig',
...
]
これでDjangoがvlogs app
を認識してくれるようになるはずです。
showmigrations
を実行します
$ python manage.py showmigrations
admin
[X] 0001_initial
[X] 0002_logentry_remove_auto_add
[X] 0003_logentry_add_action_flag_choices
auth
[X] 0001_initial
[X] 0002_alter_permission_name_max_length
[X] 0003_alter_user_email_max_length
[X] 0004_alter_user_username_opts
[X] 0005_alter_user_last_login_null
[X] 0006_require_contenttypes_0002
[X] 0007_alter_validators_add_error_messages
[X] 0008_alter_user_username_max_length
[X] 0009_alter_user_last_name_max_length
[X] 0010_alter_group_name_max_length
[X] 0011_update_proxy_permissions
contenttypes
[X] 0001_initial
[X] 0002_remove_content_type_name
sessions
[X] 0001_initial
vlogs
[ ] 0001_initial
認識されていますね。migrate
します。
$ python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions, vlogs
Running migrations:
Applying vlogs.0001_initial... OK
このようにうまく実行されますが、
vlogs_post
とblogs_post
が出来てしまいます。
理想はvlogs_post
だけになっていることです。
ではblogs_post
をvlogs_post
に変更します。
3. アプリケーション名変更前のテーブルを新しいアプリケーション名に合わせてrenameする
PostModelから作られるテーブルはblogs app
をvlogs app
にrenameすることでvlogs_post
になって欲しいです。
テーブル名を変更します。
mysql> ALTER TABLE blogs_post RENAME TO vlogs_post;
4. django_content_typeとdjango_migrationsを書き換える
今までblogsとして扱っていたアプリケーションを今後はvlogsとして扱ってもらうために
django_content_type
とdjango_migrations
を書き換えます。
mysql> UPDATE django_content_type SET app_label='vlogs' WHERE app_label='blogs'
mysql> UPDATE django_migrations SET app='vlogs' WHERE app='blogs'
結果
では、問題ないかどうかを確認します。
確認の方法としては
1: Modelに変更を加えずにmigrateを実行した時に何も起こらないこと
$ python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions, vlogs
Running migrations:
No migrations to apply.
2: Modelに変更を加えた時に続きからmigrationが作成されること
Postモデルにcontentカラムを追加します。
vlogs/models.py
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=255)
content = models.CharField(max_length=255, null=True)
$ python manage.py makemigrations
Migrations for 'vlogs':
vlogs/migrations/0002_post_content.py
- Add field content to post
$ python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions, vlogs
Running migrations:
Applying vlogs.0002_post_content... OK
このようにvlogs/migrations
配下に0002_post_content.py
が続きとして作成されcontentカラムが問題なく追加されました。
まとめ
Djangoのmigrationが何を見て動いているのかをなんとなく理解するのに良いお題だと思いました。
普段あまり意識することのないdjango_content_type
にも触れられました。
一応GitHubです。
ありがとうございました。