今回のお題
今回はdjangoアプリのmodel
, qeuryset
, get_queryset
についてまとめます。
これらは全てListView
においてレコードを取得する際に用いられ、どれか一つが指定されていればテンプレートにインスタンスが渡ります(modelに関しては他のテンプレートニューでも利用可能)が、この3つの関係性が自分の中で今ひとつ整理できていなかったのでメモとして残しておきます。
ビューからテンプレートにインスタンスのリストが渡る仕組み
ListView
の継承元の一つであるMultipleObjectMixin
には、model
, queryset
という二つの属性値とget_querysetメソッド
が定義されている(属性値ふたつの初期値はNone
)。
テンプレートにcontextが渡る際には参照されるのはqueryset
の値であり、最終的にはここに目的のリストが入っていれば良い。
queryset
をテンプレートに渡すための方法は3つあり、
- ビューの初期値として設定する
- modelを指定してquerysetに変換する
- get_querysetメソッドの中でquerysetを取得できるようにする
のいずれかをとることになる。
class MultipleObjectMixin(ContextMixin):
"""A mixin for views manipulating multiple objects."""
allow_empty = True
queryset = None
model = None
paginate_by = None
paginate_orphans = 0
context_object_name = None
paginator_class = Paginator
page_kwarg = 'page'
ordering = None
def get_queryset(self):
"""
Return the list of items for this view.
The return value must be an iterable and may be an instance of
`QuerySet` in which case `QuerySet` specific behavior will be enabled.
"""
# querysetがあればそこからインスタンスを取得
if self.queryset is not None:
queryset = self.queryset
if isinstance(queryset, QuerySet):
queryset = queryset.all()
# querysetがなくてもmodelがあればそこからインスタンスを取得可能
elif self.model is not None:
queryset = self.model._default_manager.all()
else:
raise ImproperlyConfigured(
"%(cls)s is missing a QuerySet. Define "
"%(cls)s.model, %(cls)s.queryset, or override "
"%(cls)s.get_queryset()." % {
'cls': self.__class__.__name__
}
)
ordering = self.get_ordering()
if ordering:
if isinstance(ordering, str):
ordering = (ordering,)
queryset = queryset.order_by(*ordering)
return queryset
get_querysetメソッドの中でqeuryセットを取得する場合には、querysetを取得した後に継承元のget_querysetを呼び出す形になる(以下参照)。
def get_queryset(self):
keyword = self.request.GET.get("keyword")
if keyword:
self.queryset = Menu.objects.filter(name__contains=keyword).all()
else:
self.queryset = Menu.objects.all()
return super().get_queryset()
以下のようにただ単にself.queryset
を返して終わっている例も見かけるが、大元のget_querysetメソッドにはordering
の処理などもあるのでsuper().get_qeuryset()
も呼び出しておいた方が無難かなと個人的には思った(検証はしていないです)。
def get_queryset(self):
keyword = self.request.GET.get("keyword")
if keyword:
self.queryset = Menu.objects.filter(name__contains=keyword).all()
else:
self.queryset = Menu.objects.all()
return self.queryset