ぽらろいどの日記

新しい知見を得たり、得られた知見を記録したり共有したりする場を予定しています。

学習事項: admin, model(Foreignkey, ManytoManyField, ModelChoiceField), templatetags

背景

  • Djangoについて、モデルの流れまでを学習した
  • そのうち、Modelのリレーションシップフィールド、Templatetagsについて追加の学習を行った
  • また、adminの利用についても学習した
  • 忘れたときのために、それらについて整理をする

Model: ForeignKey, ManytoManyField

テーブルの結合を行う

  • Modelが複数ある場合、それらを組み合わせて表示したい場合がある
  • そうした場合には、ForeignKeyやManyToManyFieldを利用して結合を行う

ForeignKey

  • いわゆる「外部キー」を通じて、もう一つのテーブルを紐づける(一対多の結合)
    • ex) 店舗モデルの「A店舗」に対して、商品モデルの「せんべい」「チョコ」の注文が紐づいている
    • 紐づけられるのは、モデルのインスタンス(表示の際は、「str」メソッドが呼び出されるので、必要に応じて調整する)
  • 設定すると、「外部キー」の項目として必ず値の設定が必要になる(一つのみ)
    • 値なしを許可することもできるかもしれない
  • 使い方は、公式リファレンスによると以下のような形で使用する
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」メソッドが呼び出されるので、必要に応じて調整する)
  • 設定すると、「外部キー」の項目として必ず値の設定が必要になる(複数可)
    • 値なしを許可することもできるかもしれない
  • 使い方は、公式リファレンスによると以下のような形で使用する
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を返す関数を渡す
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に反映させられるようにしている)