TECH BLOG


DjangoのModelsのみ使用する

LINEで送る
Pocket

はじめに

既存のPythonスクリプトにDB処理を追加する際にDjangoのModelsのみ使用したくなることがありました。DjangoのチュートリアルのDBを例にして、既存のPythonスクリプトにDjangoのModelsを使用するコードを追加する方法を紹介します。

新規のスクリプトでDB処理にDjangoのModelsを使用したい場合は、Djangoのカスタムコマンドを作成したほうがいいと思います。

前提

環境

項目 内容
OS Windows 10 Pro
Python バージョン 3.7.0 (64bit)
Django バージョン 2.1.3

作成済みのDB(DjangoのチュートリアルのDB)

作成済みのDBとして、チュートリアルその2まで行ったSQLiteのファイル(db.sqlite3)を使用します。

Django関連のPythonスクリプト

Django関連のPythonスクリプトの配置

DjangoのModelsを使用するためのスクリプト(app.pymodels.py)を、既存のプロジェクトディレクトリ直下に pollsディレクトリを作成しその下に配置します。

既存のプロジェクトディレクトリ
 ├─ main.py
 ├─ db
 │   └── db.sqlite3
 └─ polls
     ├── apps.py
     └── models.py

app.py の内容

チュートリアルその1で作成されるapp.pyと同じ内容で作成します。

from django.apps import AppConfig

class PollsConfig(AppConfig):
    name = 'polls'

models.py の内容

チュートリアルその2で作成するmodels.pyと以下の点が異なります。

  • 作成済みのDBを使用するために、class Metadb_tableプロパティとmangedプロパティを指定する。
  • db_tableプロパティには、使用するテーブル名を指定する。この例ではSQLiteなのでテーブル名だけですが、別のDB(PostgreSQL等)の場合は必要に応じてスキーマ名等も含めて指定する。
  • mangedプロパティには、マイグレーションを行わないのでFalseを指定する。
import datetime

from django.db import models
from django.utils import timezone

class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')

    def __str__(self):
        return self.question_text

    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

    class Meta:
        db_table = 'polls_question'
        managed = False

class Choice(models.Model):
    db_table = 'polls_choice'
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

    def __str__(self):
        return self.choice_text

    class Meta:
        db_table = 'polls_choice'
        managed = False

実際は、既存のDBのテーブル定義に合わせてフィールドを作成する必要があります。(inspectdbを使用する方法もあります。)

既存のPythonスクリプトに追加する

既存のPythonスクリプト(main.py)にModelsを使用するためのコードを追加します。

既存のプロジェクトディレクトリ
 ├─ main.py
 ├─ db
 │   └── db.sqlite3
 └─ polls
     ├── apps.py
     └── models.py

Djangoのセットアップ

main.pyにDjangoをセットアップするコードを追加します。

from django.conf import settings
settings.configure(
    DATABASES={
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': './db/db.sqlite3',
        }
    },
    INSTALLED_APPS=['polls.apps.PollsConfig']
)

import django
django.setup()
  • settingsconfigure関数を使用して最低限 必要なDATABASESINSTALLED_APPSを設定する。
  • DATABASESには、DBの接続情報をdefaultに記載する。記載内容はDBによって異なり、SQLiteの場合はNAMEにSQLiteのファイルパスを指定する。
  • INSTALLED_APPSには、apps.pyに定義したPollsConfigを指定する。
  • django.setup()を使用してdjangoをセットアップする。

Modelsを使用する

セットアップまでできたら、DjangoのModelsの使い方は一緒なので以下のようにします。

from django.conf import settings
settings.configure(
    DATABASES={
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': './db/db.sqlite3',
        }
    },
    INSTALLED_APPS=['polls.apps.PollsConfig']
)

import django
django.setup()

from polls.models import Question, Choice
for q in Question.objects.all():
    print(q.question_text)
for c in Choice.objects.all():
    print(c.choice_text)

from polls.models import Question, Choicedjango.setup()より前に書くと以下のエラーが発生します。

django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.