0
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 3 years have passed since last update.

【Python】Djangoのクラスベース汎用ビュー【ListView】

Last updated at Posted at 2021-04-25

はじめに

Djangoは「クラスベース汎用ビュー」というクラスを使ったビューが用意されていて、少ないコードで豊富な機能を実装することができます。その一方でコードが内部に隠れてしまうので、仕組みが分かりにくいというデメリットもあります。

詳細は私もよく分からないのですが、カスタマイズの方法を記録として残しておきたいと思います。

今回はgeneric.ListViewです。

※補足

いつもはdjangoプロジェクトの作成から始めていますが、今回は割愛します。というのも、今回実装する機能は以前の記事「DjangoのCRUD処理について」をクラスベース汎用ビューに置き換えたものなので、詳細はそちらをご覧頂ければ幸いです。

イメージ

ListViewを使って、モデルを取得し、一覧で表示します。

スクリーンショット 2021-04-25 22.15.12.png

モデル

モデルはこのような感じです。

models.py
from django.db import models
from django.utils import timezone


class ReviewByClass(models.Model):
    STARS = (
        (1, ''),
        (2, '★★'),
        (3, '★★★'),
        (4, '★★★★'),
        (5, '★★★★★'),
    )

    store_name = models.CharField('store_name', max_length=255)
    title = models.TextField('title', max_length=255)
    text = models.TextField('review', blank=True)
    stars = models.IntegerField('stars', choices=STARS)
    created_at = models.DateTimeField('created_at', default=timezone.now)

    def __str__(self):
        return self.title

ビュー

肝心のListViewは以下のような感じです。クラスはたったの2行です。

ご覧の通り、テンプレートファイルの名称さえ書かなくても機能してしまいます。便利な反面、どうやってカスタマイズしたら良いか分かりにくいです。

views.py
from .models import ReviewByClass
from django.views import generic # クラスベース汎用ビュー


class ReviewList(generic.ListView):
    model = ReviewByClass

テンプレートファイル

テンプレートファイルは以下の様になります。

reviewcbyclass_list.html
{% extends "base.html" %}

<!-- コンテンツ -->
{% block content %}
<div class="container">
  <h1>Reviews By Class</h1>
  <hr>
  {% for reviewbyclass in reviewbyclass_list %}
    <article>
      <h3><a href="{% url 'reviewsByClass:reviewbyclass_detail' reviewbyclass.pk %}">{{ reviewbyclass.store_name }}</a></h3>
      <p>{{ reviewbyclass.get_stars_display }} - {{ reviewbyclass.title }} - {{ reviewbyclass.created_at }}</p>
    </article>
  {% endfor %}
  <a href="{% url 'reviewsByClass:reviewbyclass_create' %}">create review</a>
</div>
{% endblock %}

仕様: テンプレートファイルの名称

ListViewの場合、デフォルトで使用されるテンプレートファイルは「モデル名小文字_list.html」になります。

仕様: QuerySetの名称

テンプレートファイルに渡されるQuerySet(モデルインスタンス)は「モデル名小文字_list」または「object_list」になります。

リストの並び替え

上のテンプレートでリストを取り出すのにfor文を使っていますが、取り出す順番を変えたくなる事があります。取り出すリストの順番を並び替える方法は以下の通りです。

views.py
class ReviewList(generic.ListView)
    model = ReviewClass
    ordering = ('-stars', '-created_at')
    # 別の書き方?
    # queryset = ReviewByClass.objects.order_by('-stars', '-created_at')

starsフィールドを降順にした上で、星の数が同じものは作成日(created_at)が新しい投稿を上に表示されます。

get_orderingメソッドを上書きする方法もあります。これによって、昇順、降順を動的に制御することができるみたいです。

views.py
class ReviewList(generic.ListView):
    model = ReviewByClass

    def get_ordering(self):
        a = 10
        if a > 5:
            return ('-stars', 'created_at')
        else:
            return '-creates_at' 

データの受け渡し

views.pyからテンプレートファイルへデータを受け渡す方法は以下の通りです。

views.py
class ReviewList(generic.ListView):
    model = ReviewByClass
    ordering = ('-stars','-created_at')
    extra_context = {'KEY': 'VALUE!!'}

get_context_dataメソッドを使用する方法もあります。こちらもget_orderingメソッドと同様にif文などと組み合わせる事ができます。

views.py
class ReviewList(generic.ListView):
    model = ReviewByClass
    ordering = ('-stars','-created_at')
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['KEY'] = 'VALUE!!'
        return context

テンプレートファイル側の受け方は以下の通りです。

reviewbyclass_list.html
  <h1>Reviews By Class</h1>
  <h1>{{ KEY }}</h1>
  <hr>
  <!-- 以下省略 -->

画面は以下のようになります。

スクリーンショット 2021-04-25 22.43.28.png

QuerySetの絞り込み

テンプレートファイルへ渡すQuerySetを絞り込むこともできます。例えば、検索フォームのようなものがついている時などがあるそうです。このような場合は、get_queryメソッドを上書きする必要があります。

views.py
class ReviewList(generic.ListView):
    model = ReviewByClass

    def get_queryset(self):
        queryset = super().get_queryset()
        if True:
            queryset = queryset.filter(stars=5)
            # queryset = queryset.filter(title__contains="A")
        
        return queryset

filterの使い方については、こちらとかが参考になるかも知れません。

参考

Djangoビギナーズブック: クラスベース汎用ビューの仕組みが詳しく書いてあります。

0
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
0
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?