DBについて
DjangoはDB(テーブル)を設計できれば、割と簡単にWebアプリが作れます。裏を返せばテーブル設計できないとダメです。
Djangoに関するDB関連のことと、一般的なテーブル設計についてです。
DBMS
使うDBMSによって注意点があるので Databases | Django documentation | Django を参照。
上記以外のDBMSもサードパーティーのドライバ Databases | Django documentation | Django があります。
また、NoSQLを使いたい方向けのプロジェクト Django non-rel もあります。
一般的なテーブルの論理設計(データモデリング)のこと
クラウドでDBのPaaSを使うと「これでDB作れたのか?」「勝手にスケールできちゃう!」「勝手にインデックス張ってくれる?!」になってます。今のところテーブルの論理設計はエンジニアがやらないとできないので、まとめておきたい。
(mBaaSやら、自然言語からSQLを作るサービスもあるので、そのうちテーブル設計もエンジニアがやらなくなりそうですが…)
テーブル設計について一通り盛り込まれていて、簡潔にまとまってる記事を見つけたので拝借。 DB論理設計のノウハウ - Qiita
この記事の内容で気になる点がいくつかあったのでメモしておきます。
自然キーを使うべき?
業務が変わるとキーが変わる可能性もある(殆どないですが…)ので代理キーを使うべき。の考え方もあり、私は代理キー派です。またDjangoを普通に使うと代理キーです。
正規化は第三正規形まででOK?
非正規化すると検索し易くなり(その検索処理だけコードが簡単になったり、レスポンスが良くなったりし)ます。逆に、正規化するほど業務の実態に近づきます。業務の実態に近いということは、仕様が変わってもテーブルの変更も対応し易い(正しくテーブル設計できていれば、テーブルには手が入らない。または、変更はなくテーブルの追加だけで対応できる。)です。非正規化した項目は、画面の仕様が変わると、全く役に立たないゴミデータになる可能性があります。後々のことを考えると、できるだけ正規化しておきたいです。
物理設計の内容
クラウドサービスを使うとあまり意識しなくて良くなってきてます。もちろん理解しておいた方が良いですが、優先度を下げて考えても良いのかと思います。
先述の記事でテーブル設計について一通りまとまっていますが、難しい単語があって頭に入りにくい部分もあります。
なので、もう少し分かり易い記事。 4ステップで作成する、DB論理設計の手順とチェックポイントまとめ - Qiita
この記事も気になる点をメモ。
主キーをidにするとSQLでjoinした際に混乱するからentity名_idとするべき?
Djangoでは主キーを定義しないと、自動的にidという主キーを作ってくれます。DjangoのORMだけ使用する場合、この記事の指摘は気にしなくて大丈夫ですが、Djangoでも生SQLを書くことができます。その場合はこの記事のとおり モデル名_id にしておいた方が無難でしょう。
中間テーブルについて
中間テーブルが「多:多の関係を解消するために、業務要件にないけど人工的につくるテーブル」として説明されています。確かに多:多を解消しますが、業務分析が不充分であるとも言えます。
この記事の例で言うと、学生は新学期が始まる際に新しい講義を選択し、受講期間を申し込むイベントがあるはずです。例にある中間テーブルに日付(受講期間)を追加したものが、このイベントのテーブルとして定義されるべきです。
上記の中間テーブルをイベントのエンティティに落とし込む点に重点をおき、分かり易く業務分析/データモデリング(≒論理設計)する手順を説明したスライドを見つけました。
イミュータブルデータモデル(入門編)
このスライドを作成した方のベースにはT字型ERがあるようです。
私も以前この本を読みました。言葉が難しいですが、テーブル設計が楽に出来るようになります。余裕があれば読んでみてはいかがでしょうか。
テーブル設計におけるDjangoの制約
複合キーは使えない
使いたい場合は、サロゲートキー + 複合ユニークキーにする。
日々の記録 : django で複合ユニーク制約をつける方法
ORMでテーブルを結合検索したい場合、modelのFieldにForeignKeyの指定が必要
ForeignKeyを張ると面倒な場面があるので、以前は物理設計時にForeignKey制約を外したこともありましたが、外さない方が良いです。ForeignKey制約についてちゃんと考えてる記事 キーレスエントリ(外部キー嫌い) - Ynishi Bussiness Logs があったので参考にしてみて下さい。
ちなみに、 Djangoでも modelのField定義で db_constraint=False を指定することで、ForeignKey制約なしにするのは可能ではあります。
customer = models.ForeignKey('Customer', null=True, blank=True, db_constraint=False)