Help us understand the problem. What is going on with this article?

Djangoのお勉強(2)

More than 1 year has passed since last update.

はじめての Django アプリ作成、その2の内容にそって試したことや調べた事を記載する。

前回の記事は Djangoのお勉強(1)

Database の設定

Databeseの設定は<プロジェクト名>/settings.pyのファイル中下記のように定義されている

/settings.py
# Database
# https://docs.djangoproject.com/en/2.0/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

'ENGINE'は、使用するDatabaseエンジンの種別を表し、
'django.db.backends.sqlite3'
'django.db.backends.postgresql'
'django.db.backends.mysql'
'django.db.backends.oracle
のいずれかを指定する。色々DBを試してみるのは面倒なので、当分sqliteを使うことにする

'NAME'は、Databaseの名前を示す。
sqliteは、ファイルを直接アクセスするので、ファイルを指定する事になる。
他のDBだったら設定方法が変わるけど面倒なので調べない。
DATABASESに説明が書いてあるらしい

os.path.join(BASE_DIR, 'db.sqlite3')は、そのまんま、DBとなるファイル名を示している。
BASE_DIRは、settings.pyの上の方で、下記のように定義されていて、settings.pyが置かれているディレクトリのひとつ上のディレクトリを指している

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

os.path.join()は、ディレクトリ名とファイル名を連結する関数なので、結局、os.path.join(BASE_DIR, 'db.sqlite3')は、
"<プロジェクトディレクトリ>/db.sqlite3"というファイルを指している。

ローカライズ設定

タイムゾーンと言語コードは<プロジェクト名>/settings.pyのファイル中下記のように定義されている

/settings.py
# Internationalization
# https://docs.djangoproject.com/en/2.0/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

日本むけに変更する場合は下記のように変える

/settings.py
# Internationalization
# https://docs.djangoproject.com/en/2.0/topics/i18n/

LANGUAGE_CODE = 'ja'

TIME_ZONE = 'Asia/Tokyo'

とりあえずDatabaseを作る

ここまで設定したら、まずはDatabaseを作ってみる
プロジェクトのルートディレクトリ(BASE_DIRで示されているディレクトリ)terminalから下記のコマンドを実行する

python manage.py migrate

実行結果
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  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
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying sessions.0001_initial... OK

modelを作る

django.db.models.Modelを継承したクラスで、データベースのテーブル構造を定義する

チュートリアルに掲載されているソースでは、下記のように定義している

poll/model.py
from django.db import models


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


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

models.CharFieldは文字列のフィールド
models.DateTimeFieldは、日付時刻フィールド
models.ForeignKeyは、リレーションを表すフィールド
models.IntegerFieldは、整数フィールド
を、それぞれ表し、モデルフィールドリファレンスで定義されている

各クラス名(この場合、QuestionとChoice)は、DB上ではテーブル名に対応し、
各変数(question_text、pub_date、question、choice_text、votes)は、DB上ではフィールド名になる

ForeignKeyは、リレーションシップを表し、下記のインタフェースになっている

class ForeignKey(to, on_delete, **options)
toは、リレーション先を示す。この場合はQuestionクラスのIDを保持する事を示す
on_deleteは、レコードが削除された時の振る舞いを指定する

  • CASCADE  カスケード削除。 DjangoはSQL制約ON DELETE CASCADEの動作をエミュレートし、ForeignKeyを含むオブジェクトも削除します。
  • PROTECT  django.db.IntegrityErrorのサブクラスであるProtectedErrorを呼び出すことによって、参照されるオブジェクトの削除を防止します。
  • SET_NULL ForeignKey nullを設定します。 nullがTrueの場合にのみ可能です。
  • SET_DEFAULT ForeignKeyをデフォルト値に設定します。 ForeignKeyのデフォルトを設定する必要があります。
  • SET() ForeignKeyをSET()に渡された値に設定するか、または呼び出し可能なものが渡された場合は、その結果を呼び出します。ほとんどの場合、models.pyのインポート時にクエリを実行しないようにするには、呼び出し可能コードを渡す必要があります:
from django.conf import settings
from django.contrib.auth import get_user_model
from django.db import models

def get_sentinel_user():
    return get_user_model().objects.get_or_create(username='deleted')[0]

class MyModel(models.Model):
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET(get_sentinel_user),
    )
  • DO_NOTHING 何もするな。データベースバックエンドで参照整合性が強制されている場合、SQL ON DELETE制約をデータベースフィールドに手動で追加しない限り、IntegrityErrorが発生します。

(by google翻訳)

modelを有効にする

最初に、このアプリケーションを登録する

登録するアプリケーションの設定を保持しているクラスは、<アプリ名>/apps.pyにある。

pools/apps.py
from django.apps import AppConfig


class PollsConfig(AppConfig):
    name = 'polls'

この場合pollsConfigが、設定を保持するクラスになるが、このクラス名はアプリケーション生成時に、Djangoによって自動的に命名される。
デフォルトの状態で、設定されているのはnameだけであるが、他の設定項目はConfigurable attributesに記載されている。

このクラスを<プロジェクト名>/settings.pyファイルに登録する
今回、このPollsConfigは、polls/apps.pyの中にあるので、'polls.apps.PollsConfig',を登録する。

/settings.py
# Application definition

INSTALLED_APPS = [
    'polls.apps.PollsConfig',      # これを登録した
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

この設定をして

python manage.py makemigrations polls

を実行するとマイグレーションが作成される。実行結果は下記の通り

 Migrations for 'polls':
   polls\migrations\0001_initial.py
     - Create model Choice
     - Create model Question
     - Add field question to choice

python manage.py sqlmigrate polls 0001

とやると、実際に発行されたsql文が表示される

BEGIN;
--
-- Create model Choice
--
CREATE TABLE "polls_choice" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "choice_text" varchar(200) NOT NULL, "votes" integer NOT NULL);
--
-- Create model Question
--
CREATE TABLE "polls_question" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "question_text" varchar(200) NOT NULL, "pub_date" datetime NOT NULL);
--
-- Add field question to choice
--
ALTER TABLE "polls_choice" RENAME TO "polls_choice__old";
CREATE TABLE "polls_choice" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "choice_text" varchar(200) NOT NULL, "votes" integer NOT NULL, "question_id" integer NOT NULL REFERENCES "polls_question"
 ("id") DEFERRABLE INITIALLY DEFERRED);
INSERT INTO "polls_choice" ("id", "choice_text", "votes", "question_id") SELECT "id", "choice_text", "votes", NULL FROM "polls_choice__old";
DROP TABLE "polls_choice__old";
CREATE INDEX "polls_choice_question_id_c5b4b260" ON "polls_choice" ("question_id");
COMMIT;

これを実際にdatabaseに反映するには、ターミナルより

python manage.py migrate

を実行する。実行結果は以下の通り。

Operations to perform:
  Apply all migrations: admin, auth, contenttypes, polls, sessions
Running migrations:
  Applying polls.0001_initial... OK

Db Browser for SQliteで内容を確認してみる

Django01.jpg

polls_choiseとpolls_questionと2つのテーブルが出来ていることがわかる。
(その他にも、沢山出来ているけど)

Brouse Dataタブを選択し、テーブルの内容を確認する
Django02.jpg

polls_choiseテーブルにid,choice_text,votes,questionのフィールドが出来ている事がわかる。
idは勝手に作られる。

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away