CategoryListView

Categoryをリスト表示するためのView。ListViewクラスを継承している。 ここでは、表示するHTMLの指定と、カテゴリ毎の記事数の集計を行う。

class CategoryListView(ListView):
	template_name = 'pages/category_list.html'
	queryset = Category.objects.annotate(num_posts=Count('article', filter=Q(article__is_public=True)))	

まず、テンプレートとしてpagesフォルダにあるcategory_list.htmlを指定している。

次にモデルからデータを抽出するために、querysetを定義している。 annotateとは「注釈をつける」という意味で、querysetに注釈として情報を付与することができる。詳しくはこちらを参照。

ここでは、以下の条件に一致するレコードを取得し、その数の情報を追加している。

・Categoryモデル ・filterメソッドで、is_public(公開状況)がTrue(公開中)である記事を抽出 ・カテゴリ名毎に、該当する記事の数(Count)をnum_postsに代入

また、上記querysetではRDBの仕組みを使ったCountを行っている。 下記の通り、Categoryクラスにはarticleという項目は存在しないし、is_publicも存在していない。どうやって、存在しない項目にアクセスしているのだろうか。

class Category(models.Model):
	class Meta:
		# テーブル名
		db_table = "Category"

	name = models.CharField('カテゴリ', max_length=20, unique=True)
	slug = models.SlugField(unique=True)
	timestamp = models.DateTimeField(auto_now_add=True)

	def __str__(self):
		return self.name

もう一度、Articleクラスを確認する。

class Article(models.Model):
	class Meta:
		# テーブル名
		db_table = "Article"

	""" Article data """
	category     = models.ForeignKey(Category, on_delete=models.PROTECT)
	title        = models.CharField('タイトル', max_length=20)
	section      = models.CharField('章', max_length=20, blank=True)
	text         = models.TextField('本文')
	tags         = models.ManyToManyField(Tag, verbose_name='タグ', blank=True)
	created_at   = models.DateTimeField('作成日', default=timezone.now)
	updated_at   = models.DateTimeField('更新日', default=timezone.now)
	published_at = models.DateTimeField(blank=True, null=True)
	is_public    = models.BooleanField('公開状況', default=True)

	def save(self, *args, **kwargs):
		if self.is_public and not self.published_at:
			self.published_at = timezone.now()
		super().save(*args, **kwargs)

	def __str__(self):
		return self.title

ArticleモデルのcategoryはCategoryモデルのForeignKeyになっており、この外部キーを利用して、CategoryモデルからArticleモデルを呼び出している。(reverse foreign key hop)

例えば、Categoryモデルに、「日記」というnameをもつレコードがあったとする。Articleモデルでは、Categoryモデルで定義された「日記」というカテゴリ名をcategoryとして利用している。つまり、各記事(Articleの各レコード)には、どのCategory名を使っているかという情報(Categoryモデルへの参照情報)が必ず含まれている。

上記のquerysetではこの参照を利用して、参照元のテーブルから外部キーを利用しているモデルにアクセスしている。さらに__でつなげることで、Articleモデルの項目であるis_publicにもアクセスしている。

最終更新

役に立ちましたか?