djangoで1ファイルでORMの挙動を確認する方法
以前 1ファイルでhello worldを作る方法 を書きましたが。
djangoで最も試してみたい事柄はORM部分かもしれません。そのORM部分を1ファイルだけで試す方法についてです。
1ファイルで試すには、ちょっとした細工が必要ですが、最近のdjangoではそれもそれなりに手軽にできるようになりました。
具体的には以下のような作業が必要になります。
- settingsをpython側から設定する
- djangoのApplicationRegistryにmodelを登録する
- 各modelのテーブルを生成する
settingsをpython側から設定する
settingsの設定がない場合には、以下のような例外が出てしまいます。
django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_INDEX_TABLESPACE, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.
エラーメッセージの通り、DJANGO_SETTINGS_MODULE
を環境変数として登録しておくかsettings.configure()
を呼びましょう。
最低限必要な設定は以下の通りです。
from django.conf import settings
settings.configure(
DEBUG=True,
DATABASES={"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": ":memory:"
}},
INSTALLED_APPS=[__name__]
)
DEBUG=True
はsqlのquery結果を出力する際に必要なので付けておいた方が良いでしょう。また、DBの設定は必要です。ここではsqliteのオンメモリDBを指定しています。INSTALLED_APPS
については後述するmodelの登録の際に指定を忘れていた場合ManyToMany
の関連が上手く動作しない様になってしまいます。
djangoのApplicationRegistryにmodelを登録する
django.setup()
を呼んでください。これによりdjango.apps.registry.Apps
のpopulate()
が呼ばれます。この中でdjangoのregistryにmodelが登録されていきます。これがなかった場合にはModel.save()
を呼んだタイミングなどで以下のようなエラーが発生します。
django.core.exceptions.AppRegistryNotReady: Models aren't loaded yet.
また注意点として、定義するmodelにはapp_label
を設定してください。これがないとmodelクラスを生成できません。以下のようなエラーが出てしまいます。
IndexError: list index out of range
定義する時には以下の様にするということです。
class X(models.Model):
name = models.CharField(max_length=255, default="foo", blank=True)
class Meta:
app_label = __name__
各modelのテーブルを生成する
通常はpython manage.py migrate
などでDBのテーブルを生成しますが。1ファイルの場合にはその手順がありません。他の方法を考える必要があります。
例えば、テーブルを生成する関数を作ってあげます。
from django.db import connections
from django.core.management.color import no_style
def create_table(model):
connection = connections['default']
cursor = connection.cursor()
sql, references = connection.creation.sql_create_model(model, no_style())
for statement in sql:
cursor.execute(statement)
for f in model._meta.many_to_many:
create_table(f.rel.through)
# 一つ一つ生成していく必要がある
create_table(X)
まとめ
以上のことを一通りまとめると以下の様になります。これで手軽にmodelの挙動を確かめる事ができますね。
# -*- coding:utf-8 -*-
import django
from django.db import models
from django.conf import settings
from django.db import connections
from django.core.management.color import no_style
settings.configure(
DEBUG=True,
DATABASES={"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": ":memory:"
}},
INSTALLED_APPS=[__name__]
)
def create_table(model):
connection = connections['default']
cursor = connection.cursor()
sql, references = connection.creation.sql_create_model(model, no_style())
for statement in sql:
cursor.execute(statement)
for f in model._meta.many_to_many:
create_table(f.rel.through)
class X(models.Model):
name = models.CharField(max_length=255, default="foo", blank=True)
class Meta:
app_label = __name__
if __name__ == "__main__":
import logging
logging.basicConfig(level=logging.DEBUG)
django.setup()
create_table(X)
xs = X.objects.bulk_create([X(id=1), X(id=2), X(id=3)])
print(X.objects.count())