[Django] Model(データベース)の使い方

Djangoでモデル(データベース)の設定を行うにはmodels.pyに設定を記載します。Djangoにはデータベースを管理する仕組みが搭載されていて多様なDBを扱うことができます。

Djangoのモデルの記述方法を学ぶと、直接SQL文を書かずにDBを扱うことができてとても便利です。

Modelの作成

Personというテーブルを作成するときは以下のように記載します。

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整数
PositiveIntegerField0または正の整数
FloatField浮動小数点
BooleanFieldTrue / False
JSONFieldJSONエンコードされたデータ
DateTimeField日付・時刻
DateField日付
TimeField時刻
EmailFieldメールアドレス(@マークが無いとエラー)
URLFieldURL(http , https , ftp , ftpsが無いとエラー)
GenericIPAddressFieldIP Address
FileFieldファイル
ImageField画像ファイル
SlugField文字列限定(アルファベット・数字・アンダーバー・ハイフン)

Django Model名の命名規則

モデル名は基本的に単数形で定義します。Django管理用画面では複数形のsが付いて表示されます。(こちらはDjangoが自動で複数形にしています)

キャメルケース記述で Category、複数の単語をつなげるときは SampleCategoryのようにします。

categoryの複数形はcategoriesですが、DjangoだとCategorysと単純に後ろにsが付いた形になります。これはMetaオプションで修正することができます。

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

# 最大文字数を設定(最大255まで)
title = models.CharField(max_length=255)

#TextField
text = models.TextField()

max_lengthは設定しないと「CharFields must define a ‘max_length’ attribute.」エラーが出ます。255文字以上になる場合はCharFieldではなく、TextFieldを使います。

BooleanField

# 初期値(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」になります。

#最初に作成されたときに現在の日時等が保存される
created_at = models.DateTimeField(auto_now_add=True)

#更新されるときに現在の日時等が保存される。
updated_at = models.DateTimeField(auto_now=True)

FileField

ファイルを登録する場合、パスと拡張子を指定するオプションがあります。

file = models.FileField(upload_to='uploads/%Y/%m/', validators=[FileExtensionValidator(['txt'])])

ImageField

画像を登録するときもファイルと同様、パスと拡張子を指定するオプションがあります。

FieldOption

# 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)

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つ以上とリンクする場合を指します。

一人の人が複数のブログ記事を投稿する、出版社が複数の種類の本を出版しているなどのケースが該当します。

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桁の文字列を使います。

    
 #テーブル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の情報も自動削除する設定になります。

def __str__(self):
        return '[' + str(self.book_code) + ']  ' +  str(self.store_name)

def __str__(self): は管理画面にデータの内容を表示する設定です。これを設定しないと管理画面で何のデーターがあるのかがわかりません。この例ですと

[本のコード] 本の名前 を表示します。

多対多(MyanyToManyField

多対多リレーションは特定のテーブルの複数レコードが、他のテーブルの複数レコードと紐づくケースが該当します。

複数のブログ記事に、複数のカテゴリーが登録されている。複数の車に、複数の色が割り当てられている場合などが当てはまります。

ピザとトッピングの2つのテーブルを多対多で関連付けてみます。

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公式ホームページ参照

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に登録する準備を行うと考えるとわかりやすいです。ターミナルから以下のコマンドを実行します。

マイグレーション

$ python manage.py makemigrations

マイグレーションの段階ではDBに変更は何もされません。以下のマイグレートを実行することによりDBに反映されます。こちらもターミナルから下記のコマンドを実行します。

マイグレート

$ python manage.py migrate

マイグレートのロールバック

マイグレートを戻すには、下記のような手順を踏みます。

まず、マイグレーションの一覧を表示します。

$ python manage.py showmigrations AppName

最後にアプリ名を付けるとアプリに関するマイグレーション情報が表示されます。アプリ名を付けないとプロジェクト全体のものが表示されます。

今までDjangoProject初回のマイグレーション、次にCompanyというテーブルを作成、その次にBookというテーブルを作成しています。

今回は3回目に作成したBookというテーブルを削除して、0002の状態に戻してみます。

一つ前の状態を指定するのがポイントです。

$ python manage.py migrate [AppName] [MigrationName]
#記述例) $ python manage.py migrate Sample 0002_company_stockprices

0003番の✗が消えて一つ前の状態に戻りました。

あとはmigrationディレクトリで該当するファイルを削除すれば完了です。

(参考)



Author: webmaster