[Django] モデルフィールド 設定テンプレート

## この記事について

コピペで使えるようにしたモデルフィールドの定義例＋α。

参考：[公式 モデルフィールドリファレンス](https://docs.djangoproject.com/ja/2.0/ref/models/fields/)

## 共通オプションの説明

一部のみ

|オプション名|説明|デフォルト|
|:--|:--|:--|
|verbose_name|入力欄のタイトル|なし|
|blank|ブランク入力|False(不可)|
|null|別記参照|Fales(Not Null)|
|default|デフォルト値|なし
|editable|フォームでの表示|True(=表示する)
|max_length|最大文字長|フィールド別|
|help_text|ツールチップの内容|なし|

## フィールド定義例

### 文字列：CharField

入力値：文字列
入力項目：テキストボックス(text)

```python:models.py
    myChar = models.CharField(
        verbose_name='',
        blank=True,
        null=True,
        max_length=50,
        default='',
        validators=[validators.RegexValidator(
            regex=u'^[ぁ-んァ-ヶー一-龠]+$',
            message='全角のひらがな・カタカナ・漢字で入力してください',
        )]
    )
```

[派生フィールド]

フィールド型|用途
|:--|:--|
SlugField|[スラッグ](https://blog.s-giken.net/171.html)
URLField|URL
EmailField|メールアドレス
UUIDField|[UUID](https://remotestance.com/blog/2794/)
FilePathField|ファイルパス
GenericIPAddressField|IPアドレス(v4/v6/両方)

- 専用のバリデーションが付く
- DBによっては専用のカラム型が使われる（別項参照）


###文字列：TextField

入力項目：テキストエリア

```python:models.py
    myText = models.TextField(
        verbose_name='',
        blank=True,
        null=True,
        max_length=1000,
    )
```

###整数：IntegerField

入力項目：テキストボックス(nunber)

```python:models.py
    myInteger = models.IntegerField(
        verbose_name='',
        blank=True,
        null=True,
        default=0,
        validators=[validators.MinValueValidator(0),
                    validators.MaxValueValidator(100)]
    )
```


[派生フィールド]

最小最大値の制限が異なる

|フィールド|最小値|最大値|
|:--|:--|:--|
IntegerField|-2147483648|2147483647
SmallIntegerField|-32768|32767
PositiveIntegerField|0|2147483647
PositiveSmallIntegerField|0|32767
BigIntegerField| -9223372036854775808|9223372036854775807

### 浮動小数点：FloatField

入力項目：テキストボックス(nunber)

```python:models.py
myFloat = models.FloatField(
    verbose_name='',
    blank=True,
    null=True,
    default=0,
       [validators.MinValueValidator(0.001),
        validators.MaxValueValidator(0.999)])
)
```

### 固定小数点：DecimalField

入力項目：テキストボックス(nunber)

専用オプション

- max_digits 数字部分の最大桁数, 
- decimal_places 小数部分の桁数

(max_digits=5, decimal_places=2) なら -999.99 ～ 999.99 が有効値となる

```python:models.py
myfield = models.DecimalField(
    verbose_name='',
    max_digits=5,
    decimal_places=2
    blank=True,
    null=True,
    default=0.00,
       [validators.MinValueValidator(0.01),
        validators.MaxValueValidator(100.00)])
)
```

### 論理値：BooleanField

入力項目：チェックボックス

```python:models.py
    myBoolean = models.BooleanField(
        verbose_name='',
        default=False,
    )
```


### 論理値：NullBooleanField

Nullが可能なBooleanField
入力項目：セレクトボックス「不明・はい・いいえ」

```python:models.py
    myNullBoolean = models.NullBooleanField(
        verbose_name='',
        default=Null,
    )
```

### 時間：DateTimeField

[専用オプション]

- auto_now_add = True
 - 登録時に現在時間を設定
- auto_now = True
 - 登録時と更新時に現在時間を設定

どちらかを設定すると`editable=False`が暗黙的に設定され、モデルフォーム上に表示されなくなる。

```python:models.py

    from django.utils import timezone

    myDateTime = models.DateTimeField(
        verbose_name='',
        blank=True,
        null=True,
        default=timezone.now
    )
```

    

[類似フィールド]

|フィールド|型|
|:--|:--|
|TimeField|時間|
|DateField|日付|
|DurationField|期間|

###ファイル系
FileField、ImageField についてはこちらを参照
- [ファイルアップロード機能の使い方 [基本設定編]](https://qiita.com/okoppe8/items/86776b8df566a4513e96)
- [ファイルアップロード機能の使い方 [クラウドストレージ編]](https://qiita.com/okoppe8/items/7ecbc92187171926238f)

###リレーション系

リレーション先のモデルは先に定義する。

```python:models.py
    # 1 x N
    parent = models.ForeignKey(
        Parent, 
        on_delete=models.CASCADE)

    # 1 x 1
    parent = models.OneToOneField(
        Parent, 
        on_delete=models.CASCADE)

    # N x N
    many = models.ManyToManyField(Many)
```

## nullオプションについて

仕様がややこしい。

- null=False時
 - カラム定義にNOT NULL制約が**付与される**。
 - 文字列入力欄が空の時は**空文字**が設定される。文字列以外のフィールドはＤＢエラーを出す。
 
- null=True時
 - カラム定義にNOT NULL制約が**付与されない**
 - 入力欄が空の時は**NULL**が設定される。 

ただしOracleでは空文字が使えないため、文字列フィールドについては「null=False」を指定してもマイグレーション時に「null=True」として扱われる。

**以下のルールで運用しないと空文字とNullが混在するので注意する**

- 「blank=Ture」を定義したときは必ず「null=Ture」も設定する
 - ブランクは「null」になる。 
- もしくは「null」オプションを一切使わない。
 - ブランクは「空文字」になる。 

上で統一した方がいい気がするが判断基準がみつからない…。

## choiceオプションについて

choiceオプションを使って入力項目を選択項目にできる。
入力ウィジェットはデフォルトでセレクトボックスだが、[モデルフォームを定義する](https://qiita.com/okoppe8/items/b8b110803a89b09b00bd)ことでラジオボタンやリストボックスにに変更可能である。

```
    YEAR_CHOICES = (
        (10, '10代'),
        (20, '20代'),
        (30, '30代'),
        (40, '40代'),
    )

    age = models.IntegerField(
        verbose_name="年齢",
        choices=YEAR_CHOICES)
```

以下の定義だと、optgroupタグでグループ化されたセレクトボックスになる。

```
    MENU_CHOICES = (
        ('食事', (
            ('Curry', 'カレー'),
            ('Ramen', 'ラーメン'),
        )),
        ('飲み物', (
            ('Bear', 'ビール'),
            ('Juice', 'ジュース'),
        )),
    )

    menu = models.CharField(
        verbose_name="メニュー",
        max_length=10,
        choices=MENU_CHOICES)

```

**choiceオプションはcallableであり、タプルを返す関数を指定すれば動的なリストを作ることができる**

## モデルフィールド x ＤＢカラム対応表

|データベース|SQLite3|Postgres9.6|MySQL5.7|Oracle 12.1|SQL Server 2017|
|:--|:--|:--|:--|:--|:--|
AutoField|integer|serial|integer|NUMBER|int 
CharField|varchar |varchar|varchar|NVARCHAR2|nvarchar 
SlugField|varchar |varchar |varchar|NVARCHAR2|nvarchar 
URLField|varchar |varchar |varchar|NVARCHAR2|nvarchar 
EmailField|varchar |varchar |varchar|NVARCHAR2|nvarchar 
UUIDField|char |uuid|char|VARCHAR2|char 
FilePathField|varchar |varchar |varchar|NVARCHAR2|nvarchar 
GenericIPAddressField|char|inet|char|VARCHAR2 |nvarchar
TextField|text|text|longtext|NCLOB|nvarchar
IntegerField|integer|integer|integer|NUMBER|int
SmallIntegerField|smallint|smallint|smallint|NUMBER|smallint
BigIntegerField|bigint|bigint|bigint|NUMBER NOT|bigint
PositiveIntegerField|integer unsigned |integer|integer|NUMBER|int
PositiveSmallIntegerField|smallint unsigned |smallint|smallint|NUMBER|smallint 
FloatField|real|double precision|double precision |DOUBLE PRECISION|double precision
DecimalField|decimal|numeric|numeric|NUMBER|numeric 
BooleanField|bool|boolean|bool|NUMBER|bit
NullBooleanField|bool|boolean|bool|NUMBER|bit
TimeField|time|time|time |TIMESTAMP|time
DateField|date|date|date|DATE|date
DateTimeField|datetime|timestamp with time zone |datetime|TIMESTAMP|datetime2
DurationField|bigint|interval|bigint|INTERVAL|bigint
BinaryField|BLOB|bytea|longblob|BLOB|varbinary
FileField|varchar |varchar|varchar |NVARCHAR2|nvarchar 
ImageField|varchar |varchar |varchar |NVARCHAR2|nvarchar