Djangoでモデル(データベース)の設定を行うにはmodels.pyに設定を記載します。Djangoにはデータベースを管理する仕組みが搭載されていて多様なDBを扱うことができます。
Djangoのモデルの記述方法を学ぶと、直接SQL文を書かずにDBを扱うことができてとても便利です。
Contents
Modelの作成
Personというテーブルを作成するときは以下のように記載します。
0 1 2 3 4 |
class Person(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=30) |
Class [テーブル名] (models.Model): でテーブル名を指定します。
その下にカラムの設定を行います。Filedに使う設定の一覧です。
Filed一覧
Field | 説明 |
CharField | 文字列 |
TextField | 文字列(長い) |
IntegerField | 整数 |
PositiveIntegerField | 0または正の整数 |
FloatField | 浮動小数点 |
BooleanField | True / False |
JSONField | JSONエンコードされたデータ |
DateTimeField | 日付・時刻 |
DateField | 日付 |
TimeField | 時刻 |
EmailField | メールアドレス(@マークが無いとエラー) |
URLField | URL(http , https , ftp , ftpsが無いとエラー) |
GenericIPAddressField | IP Address |
FileField | ファイル |
ImageField | 画像ファイル |
SlugField | 文字列限定(アルファベット・数字・アンダーバー・ハイフン) |
Django Model名の命名規則
モデル名は基本的に単数形で定義します。Django管理用画面では複数形のsが付いて表示されます。(こちらはDjangoが自動で複数形にしています)
キャメルケース記述で Category、複数の単語をつなげるときは SampleCategoryのようにします。
categoryの複数形はcategoriesですが、DjangoだとCategorysと単純に後ろにsが付いた形になります。これはMetaオプションで修正することができます。
0 1 2 3 |
class Meta: verbose_name_plural = 'Categories' |
Django Modelの属性(カラム)命名規則
Django Modelの属性はスネークケースで書きます。category_nameの形式です。
よく使うものは命名の規則を決めておくと可読性が良くなります。
_name , _code , _id , _no , _date , _time , _dt(日時), _num , _type , is_(真偽値) , _file など
Fieldの詳細設定方法
CharField
0 1 2 3 4 5 6 |
# 最大文字数を設定(最大255まで) title = models.CharField(max_length=255) #TextField text = models.TextField() |
max_lengthは設定しないと「CharFields must define a ‘max_length’ attribute.」エラーが出ます。255文字以上になる場合はCharFieldではなく、TextFieldを使います。
BooleanField
0 1 2 3 4 5 6 7 8 9 |
# 初期値(noneにする) isExist = models.BooleanField() #初期値(Trueに設定) isExist = models.BooleanField(default=True) #初期値(Falseに設定) isExist = models.BooleanField(default=False) |
DateTimeField / DateField / TimeField
日付時間型のオプションは「auto_now_add」と「auto_now=True」になります。
0 1 2 3 4 5 6 |
#最初に作成されたときに現在の日時等が保存される created_at = models.DateTimeField(auto_now_add=True) #更新されるときに現在の日時等が保存される。 updated_at = models.DateTimeField(auto_now=True) |
FileField
ファイルを登録する場合、パスと拡張子を指定するオプションがあります。
0 1 2 |
file = models.FileField(upload_to='uploads/%Y/%m/', validators=[FileExtensionValidator(['txt'])]) |
ImageField
画像を登録するときもファイルと同様、パスと拡張子を指定するオプションがあります。
FieldOption
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# null # DBでNullを使えるように・使えないようにする。 hoge = models.BooleanField(null=True) hoge = models.BooleanField(null=False) #blank #カラムへの入力を必須にする(必須にしない)の選択 hoge = models.BooleanField(blank=True) hoge = models.BooleanField(blank=False) #choice #指定したデータから選択できるようにする class Person(models.Model): SHIRT_SIZES = [ ("S", "Small"), ("M", "Medium"), ("L", "Large"), ] name = models.CharField(max_length=60) shirt_size = models.CharField(max_length=1, choices=SHIRT_SIZES) #default #データを指定しない場合TrueがDBに保存される hoge = models.BooleanField(default=True) #primary_key #idではなくhogeをプライマリーキーに設定する場合 #指定が無いとDjangoがIntegerFieldが自動に生成されてそれが主キーとなる。 hoge = models.CharField(max_length=100, primary_key=True) #unique #重複を防止するための設定 hoge = models.PositiveIntegerField(unique=True) #verbose_name #管理画面で表示される文字を変更する。 hoge = models.CharField(max_length=, verbose_name='変更した文字') |
一対一(OneToOneField)
0 1 2 |
column_name = models.OneToOneField([参照先modelクラス名], on_delete=[オプション],[その他オプション]) |
on_deleteオプションはリレーションシップされているモデルのデータをどのように扱うかを設定します。
種別 | 説明 |
models.CASCADE | データ削除時に参照しているデータも連動して削除(デフォルト設定) |
models.PROTECT | 別モデル(テーブル)から参照させれていると削除できない |
models.RESTRICT | 削除エラーが表示される。片方のデータが削除され、紐づく先のデータは残る |
models.SET_NULL | 参照先のレコードをNullに設定(参照先でNullが許可されている必要あり) |
models.SET_DEFAULT | 参照先のレコードをDefault値に設定(カラムにDefalut値の設定が必要) |
user (id , name ) / address (id , address ) という2つのモデル(テーブル)が存在する場合、addressモデルにOnetoOneFieldを設定するとuser_idというカラムが自動に生成されます。userモデルのidとaddressモデルのuser_idカラムがリレーションされます。
一対多(ForeignKey)
一対多の場合はForeingKeyを使います。一対多のリレーションはテーブルの1つのレコードが他のテーブルの2つ以上とリンクする場合を指します。
一人の人が複数のブログ記事を投稿する、出版社が複数の種類の本を出版しているなどのケースが該当します。
0 1 2 3 4 5 6 7 8 9 |
class Manufacturer(models.Model): # ... pass class Car(models.Model): manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE) # ... |
自動車会社が複数の車を作っている場合のケースです。
ManufacturerテーブルのidフィールドとCarテーブルに自動生成されたmanufacturer_idフィールドが紐づくようになります。
主キーを自動連番以外に設定する場合
下記は本とショップの2つのモデルを一対多でリレーションする例です。BookCodeは連番ではなく4桁の文字列を使います。
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#テーブルA (一側) class Book(models.Model): book_code = models.CharField(max_length=4, unique=True, primary_key=True) #主キー・重複なしを設定 name= models.CharField(max_length=50) def __str__(self): return '[' + str(self.book_code) + '] ' + str(self.name) #テーブルB (多側) class Store(models.Model): book_code = models.ForeignKey(Book, on_delete=models.CASCADE, related_name='booksStores') #リレーション設定 store_name= models.CharField(max_length=50) def __str__(self): return '[' + str(self.Bbook_code) + '] ' + str(self.store_name) |
まず、BookモデルにBookCodeカラムを作成し、重複なし・主キーの設定を行います。
StoreモデルでBookCodeカラムにForeignKeyを設定します。on_deleteはBookのデータが消されたときにリレーションしているStoreの情報も自動削除する設定になります。
0 1 2 3 |
def __str__(self): return '[' + str(self.book_code) + '] ' + str(self.store_name) |
def __str__(self): は管理画面にデータの内容を表示する設定です。これを設定しないと管理画面で何のデーターがあるのかがわかりません。この例ですと
[本のコード] 本の名前 を表示します。
多対多(MyanyToManyField)
多対多リレーションは特定のテーブルの複数レコードが、他のテーブルの複数レコードと紐づくケースが該当します。
複数のブログ記事に、複数のカテゴリーが登録されている。複数の車に、複数の色が割り当てられている場合などが当てはまります。
ピザとトッピングの2つのテーブルを多対多で関連付けてみます。
0 1 2 3 4 5 6 7 8 9 |
class Topping(models.Model): # ... pass class Pizza(models.Model): # ... toppings = models.ManyToManyField(Topping) |
公式ドキュメントから引用していますが、このケースの場合、Pizzaの方にだけManyToManyFieldが設定されています。Pizza , Topping どちらに定義しても良いですが、どちらか片方にのみ設定するのがルールになっています。また ManyToManyField のフィールド名は関係先モデルのフィールド名の複数形が推奨されています。Pizzaテーブル側に設定するのでToppingテーブルの複数形 toppings をフィールド名として設定します。
多対多の場合、2つのテーブルの他に中間テーブルが設定されます。両方のIDを関連付けて管理するためです。
中間テーブルはcar_pizzaとなり、 id , car_id , pizza_id というフィールドが作られます。
更に複雑な多対多のリレーションは以下のように記載します。詳しい解説はDjango公式ホームページ参照
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
class Person(models.Model): name = models.CharField(max_length=128) def __str__(self): return self.name class Group(models.Model): name = models.CharField(max_length=128) members = models.ManyToManyField(Person, through="Membership") def __str__(self): return self.name class Membership(models.Model): person = models.ForeignKey(Person, on_delete=models.CASCADE) group = models.ForeignKey(Group, on_delete=models.CASCADE) date_joined = models.DateField() invite_reason = models.CharField(max_length=64) |
データーベースへの反映
まず、models.pyにモデルを定義したら、データベーススキーマに反映させます。まずはマイグレーションを行います。Djangoがモデルに記載された内容を分析し、マイグレーションファイルを作成します。DBに登録する準備を行うと考えるとわかりやすいです。ターミナルから以下のコマンドを実行します。
マイグレーション
0 1 2 |
$ python manage.py makemigrations |
マイグレーションの段階ではDBに変更は何もされません。以下のマイグレートを実行することによりDBに反映されます。こちらもターミナルから下記のコマンドを実行します。
マイグレート
0 1 2 |
$ python manage.py migrate |
マイグレートのロールバック
マイグレートを戻すには、下記のような手順を踏みます。
まず、マイグレーションの一覧を表示します。
0 1 2 |
$ python manage.py showmigrations AppName |
最後にアプリ名を付けるとアプリに関するマイグレーション情報が表示されます。アプリ名を付けないとプロジェクト全体のものが表示されます。
今までDjangoProject初回のマイグレーション、次にCompanyというテーブルを作成、その次にBookというテーブルを作成しています。
今回は3回目に作成したBookというテーブルを削除して、0002の状態に戻してみます。
一つ前の状態を指定するのがポイントです。
0 1 2 3 |
$ python manage.py migrate [AppName] [MigrationName] #記述例) $ python manage.py migrate Sample 0002_company_stockprices |
0003番の✗が消えて一つ前の状態に戻りました。
あとはmigrationディレクトリで該当するファイルを削除すれば完了です。
(参考)