8
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

メモ〜djangoのmodel, queryset, get_querysetについてまとめる

Posted at

今回のお題

今回はdjangoアプリのmodel, qeuryset, get_querysetについてまとめます。

これらは全てListViewにおいてレコードを取得する際に用いられ、どれか一つが指定されていればテンプレートにインスタンスが渡ります(modelに関しては他のテンプレートニューでも利用可能)が、この3つの関係性が自分の中で今ひとつ整理できていなかったのでメモとして残しておきます。

ビューからテンプレートにインスタンスのリストが渡る仕組み

ListViewの継承元の一つであるMultipleObjectMixinには、model, querysetという二つの属性値とget_querysetメソッドが定義されている(属性値ふたつの初期値はNone)。

テンプレートにcontextが渡る際には参照されるのはquerysetの値であり、最終的にはここに目的のリストが入っていれば良い。

querysetをテンプレートに渡すための方法は3つあり、

  • ビューの初期値として設定する
  • modelを指定してquerysetに変換する
  • get_querysetメソッドの中でquerysetを取得できるようにする

のいずれかをとることになる。

get_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
8
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?