Djangoのモデルフィールドについてまとめてみた

# はじめに
Djangoはさまざまなデータ型を格納するためのフィールドを提供しています。
これらを理解し適切に使用することで、データベース設計を効率的かつ正確に行うことができます。
今回はフィールドの種類をまとめてみました。

# フィールドの種類

## AutoField
自動的にインクリメントされる整数を保存するフィールド(最大値が約20億(2,147,483,647)の32ビット)
`id`フィールドとして自動的に生成されるデフォルトのフィールドです。
明示的に宣言しなくてもモデルに1つ作成されます。
カスタマイズが必要な場合は手動で追加しカスタマイズが可能です。

## BigAutoField
こちらも自動的にインクリメントされる整数を保存するフィールドですが、AutoFieldより大きな整数値を保存できる。
1~最大値が約9京(9223372036854775807)の64ビット。
大規模アプリケーションでAutoFieldの最大値20億が足りない場合必要になります。

## BigIntegerField
約-9京(-9223372036854775808)~最大9京(9223372036854775807)の64ビットの整数値を保存できるフィールドです。

## BinaryField
生のバイナリデータを格納するフィールドです。

## BooleanField
`True/False`を保存できるフィールドです。

## CharField
文字列を保存することができるフィールドです。
`max_length`(最大文字数)の指定が必須です。

## DateField
日付を保存します。例: 2024-12-25

## DateTimeField
日付と時間を保存します。例: 2024-12-25 00:00:00

## DecimalField
高精度な小数点付きの数値を保存します。
対して`FloatField`は近似値を保存するため、正確な値が必要な場合は`DecimalField`を選ぶのが良いです。
max_digits(小数点以下も含む数値全体の桁数)の指定と、
decimal_places(小数点以下の桁数)の指定が必須です。

## DurationField
時間の長さや期間を表すデータを保存するフィールド。
PostgreSQLでのデータ型はintervalになり、時刻関係の演算で便利見たいです。

## EmailField
メールアドレスを保存するフィールドです。
CharFieldにEmail形式であることのバリデーションが加わったもののようです。

## FileField
画像、文書、音声などのファイルをデータベースに関連付けて保存するフィールドです。

:::note warn
**ファイルはデータベースに保存されるのではなく、指定したディレクトリに保存**され、そのパス（ファイル名）はデータベースのレコードに格納されます。
:::

## FilePathField
ファイルのパスを保存するためのフィールドです。

## FloatField
浮動小数点数(小数点を含む数値)を保存するフィールドです。

## GeneratedField
Django 5.0で導入されたフィールドで、データベースが自動的に生成する値を扱うために使用されます。通常のフィールドとは異なり、Djangoアプリケーション側ではなくデータベース側で値が生成されます。

今回は以下の簡単なサンプルのモデルで動作確認してみました。
`price(価格)`と`quantity(数量)`を掛け合わせた結果を`total_cost`のカラムに設定します。
```python
from django.db import models

class Product(models.Model):
    price = models.DecimalField(max_digits=10, decimal_places=2)
    quantity = models.PositiveIntegerField()
    total_cost = models.GeneratedField(
        expression=models.F('price') * models.F('quantity'),
        output_field=models.DecimalField(max_digits=15, decimal_places=2),
        db_persist=True
    )

    class Meta:
        db_table = "product"
```

- expression
他のフィールドを使って計算式を定義します。

- output_field
フィールドのデータ型を定義します。

- db_persist
データベースカラムが実際のカラムのようにストレージを占有するかどうかを決定します。 
Trueの場合は計算結果を物理的に格納します。SELECT時に計算しません。
Falseの場合は計算結果を物理的に格納せず、SELECT時に計算します。

### テーブル構造確認
```bash
mydatabase=# \d product;
                                            Table "public.product"
   Column   |     Type      | Collation | Nullable |                         Default                          
------------+---------------+-----------+----------+----------------------------------------------------------
 id         | bigint        |           | not null | generated by default as identity
 price      | numeric(10,2) |           | not null | 
 quantity   | integer       |           | not null | 
 total_cost | numeric(15,2) |           |          | generated always as ((price * quantity::numeric)) stored
Indexes:
    "newrelic_app_product_pkey" PRIMARY KEY, btree (id)
Check constraints:
    "newrelic_app_product_quantity_check" CHECK (quantity >= 0)
```
実際に`INSERT`後に`SELECT`し、計算式通りに`price * quantity`の結果が取得できていること確認できました。
```bash
postgres=# INSERT INTO product (price, quantity) VALUES (1000, 5);
INSERT 0 1
postgres=# select * from product;                                            
 id |  price  | quantity | total_cost 
----+---------+----------+------------
  3 | 1000.00 |        5 |    5000.00
(1 row)
```

## GenericIPAddressField
IPv4またはIPv6のIPアドレスを保存するフィールドです。

## ImageField
画像ファイルを保存するフィールドです。
FileFieldを拡張して画像専用にしたもの。

## IntegerField
約-20億(-2147483648)~約20億(2147483647)の整数を保存するフィールドです。

## IPAddressField
IPv4アドレスを保存するフィールドです。GenericIPAddressFieldよりも制約が少ない。

## JSONField
JSON 形式のデータを保存するフィールド。リストや辞書などの複雑なデータ構造を保存するのに適しています。

## ManyToManyField
多対多の関係を表すフィールドです。
`to`で指定したモデルと多対多の関連を作成します。

## OneToOneField
一対一の関係を表すフィールドです。
`to`で指定したモデルと一対一の関連を作成します。

## PositiveBigIntegerField
`BigIntegerField`の正の値のみを許可します。

## PositiveIntegerField
`IntegerField`の正の値のみを許可します。

## PositiveSmallIntegerField
`SmallIntegerField`の正の値のみを許可します。

## TextField
長いテキスト(文字列)を保存するフィールドです。
`CharField`よりも長い文字列を格納できます。

## TimeField
時間(時:分:秒)を保存するフィールドです。
日付を含まない時刻のみを保存します。

## SlugField
スラグとは、アルファベット、数字、アンダースコア、またはハイフンのみを含む、何かの短いラベルです。一般的にURLで使われます。
URLやSEOで使用するためのスラッグ（英数字の簡略化された識別子）を保存するフィールドです。

## SmallAutoField
AutoFieldのサイズが小さい版のようなもの(1~32767)

## SmallIntegerField
小さい整数(-32768~32767)を保存するフィールド。

## URLField
URLを保存するフィールドです。
URLのバリデーションも行ってくれます。

## UUIDField
UUIDを保存するフィールドです。