学習事項: admin, model(Foreignkey, ManytoManyField, ModelChoiceField), templatetags
背景
- Djangoについて、モデルの流れまでを学習した
- そのうち、Modelのリレーションシップフィールド、Templatetagsについて追加の学習を行った
- また、adminの利用についても学習した
- 忘れたときのために、それらについて整理をする
Model: ForeignKey, ManytoManyField
テーブルの結合を行う
- Modelが複数ある場合、それらを組み合わせて表示したい場合がある
- そうした場合には、ForeignKeyやManyToManyFieldを利用して結合を行う
ForeignKey
- いわゆる「外部キー」を通じて、もう一つのテーブルを紐づける(一対多の結合)
- ex) 店舗モデルの「A店舗」に対して、商品モデルの「せんべい」「チョコ」の注文が紐づいている
- 紐づけられるのは、モデルのインスタンス(表示の際は、「str」メソッドが呼び出されるので、必要に応じて調整する)
- 設定すると、「外部キー」の項目として必ず値の設定が必要になる(一つのみ)
- 値なしを許可することもできるかもしれない
- 使い方は、公式リファレンスによると以下のような形で使用する
- モデルフィールドリファレンス | Django ドキュメント | Django
- models.ForeignKey( ’紐づけるモデル', on_delete=models.CASCADE / models.PROTECT / ... )
- on_deleteは紐づいているデータを一緒に消すかどうかを指定する
- 参照整合性について、参照整合性 - リレーションシップ - Access入門などを参照
- 親側に登録されていないデータが、子側に登録されている矛盾が発生してしまう
from django.db import models class Car(models.Model): manufacturer = models.ForeignKey( 'Manufacturer', on_delete=models.CASCADE, ) # ... class Manufacturer(models.Model): # ... pass
ManyToManyField
- こちらは、多対多の結合を行って、もう一つのテーブルを紐づける
- ex) 顧客モデルの「Aさん」に対して商品モデルの「せんべい」「チョコ」、「Bさん」に対して「せんべい」「ポテトチップス」が紐づいている
- 紐づけられるのは、同じくモデルのインスタンス(表示の際は、「str」メソッドが呼び出されるので、必要に応じて調整する)
- 設定すると、「外部キー」の項目として必ず値の設定が必要になる(複数可)
- 値なしを許可することもできるかもしれない
- 使い方は、公式リファレンスによると以下のような形で使用する
- models.ManyToManyField( '紐づけるモデル' )
- on_deleteを指定する必要はない
from django.db import models class Person(models.Model): friends = models.ManyToManyField("self")
話は変わって:ModelChoiceField
「DBに格納されている値の中からどれか選ばせたい?そんなときModelChoiceFieldが便利なんですよ。」DjangoのFormを活用する (1) ModelChoiceField:株式会社サブスレッド
- とのことなので、必要に応じて利用する
- 公式リファレンス(Form fields | Django ドキュメント | Django)によると、
- 外部キーを表すモデルオブジェクト一つを選択肢として設定できる
- 100アイテム程度が限界
- 引数「queryset」に選択肢として提示するモデルのオブジェクト(model.object)を渡す
- 引数「empty_label」に、値がないときのラベルを設定する
- 引数「to_field_name」に、formのバリューとして<obj.pk>の代わりにセットするものを設定する(="name"なら、value="obj1.name"がHTML内にセットされる)
templatetags
templatetagsとは
- 独自のテンプレートタグとフィルタ | Django ドキュメント | Django
Django のテンプレート言語は、アプリケーションのプレゼンテーションロジックのニーズに対応するように設計された、多種多様な 埋め込みタグやフィルタ を搭載しています。それでもなお、テンプレート構成要素のコア・セットでカバーされていない機能が必要になることもあるでしょう。そのときは Python を使用し、独自のタグやフィルタを定義することによって、テンプレートエンジンを拡張できます。その上で、{% load %} タグを使用すると、テンプレートでそれらの機能を利用することができるようになります。
- templatetagsは、テンプレートの既存の埋め込みタグで対応しきれない場合に、独自にタグを定義して利用するもの
- templatetagsのファイルをアプリ下に作成し、その中に必要なタグの処理を記載したpythonファイルを格納する
- template内で{% load mytag.py %}などとすることで、作った関数を利用できる
利用
- 使い方は、公式リファレンスによると以下のような形で使用する
- まずtemplate.Library()を読み込んで、registerに格納する必要がある
有効なタグライブラリにするため、モジュールは、register という名前のモジュールレベルの変数を含む必要があります。これは、すべてのタグとフィルタが登録されている template.Library のインスタンスです。そのため、あなたのモジュールの上部に、次のコードを記述してください:
from django import template register = template.Library()
- そのあとデコレーターを利用して、register.simple_tagメソッドにreturnを返す関数を渡す
- デコレーターについては、Python のデコレータについて理解した話 | レコチョクのエンジニアブログなどを参照
- ここで作成したreturnの内容が、templateでの利用時にtemplate内に返される
import datetime from django import template register = template.Library() @register.simple_tag def current_time(format_string): return datetime.datetime.now().strftime(format_string)
コンテキストにアクセスしたい場合は、takes_context=Trueを引数に渡す
@register.simple_tag(takes_context=True) def current_time(context, format_string): timezone = context['timezone'] return your_get_current_time_method(timezone, format_string)
admin
- Djangoの管理画面
- python manage.py createsuperuserによってスーパーユーザーを作成することで、ログインできる
- modelのデータ管理などが行える
- あらかじめ、admin.py内でadmin.site.register(model)と記述するのを忘れないようにする
- Template内で{% url 'admin:app_model_add' %}などと指定することでアクセスができる
その他:検索フォーム関連の個人的まとめ
そもそもcontext: get_context_dataとは何をしている?
contextの正体をわかりやすく解説【原則から説明します】 - code for Django
そもそもquerysetとは?
querysetについて分かりやすく解説【具体例で説明します】 - code for Django
汎用ビューとcontext, querysetとの関係は?
[Django] よく使うクラスベースビューのよくオーバーライドするメソッドとアトリビュート一覧(まとめ)
get_queryset, get_context_dataのなかをprint関数で覗いてみる
- get_queryset, get_context_dataにそれぞれprint関数を置くと、get_querysetが先に呼ばれる
- get_querysetで必要な情報をDBから取得し、それをcontextに乗せて送り出している?
- また、各メソッドで利用している情報について、それぞれprint関数で出力すると以下のような値が得られる
- print(self.request.POST)
- <QueryDict: {'stage': ['1'], 'department': ['1']}>
- 「?=」以下のGETとして送っている内容を参照している(あとでフォームなどに反映させることができる)
- print(form): form = abcForm(self.request.GET)の場合
... など既に値が入ったフォームの「HTML」が得られる - stage:1が選択されている場合、「option value="1" selected」などの形でフォームに反映される
- self.request.GETの値を参照してフォームに反映した形で(デフォルト値など)、formsの形式に従ってフォームのHTMLを作成している
- print(context): get_context_data内
- paginator, object_list, model_list, viewが辞書の形で得られる
- formを追加した場合はそれも得られる('form':
など、ここで既に利用するフォームやモデルが含まれている) - ページネーションやモデルオブジェクトなど、必要な情報をまとめている(そしてTemplateに反映させられるようにしている)
- print(self.request.POST)