【サンプルコード付き】DjangoでURLパラメータから主キーまたはスラグでオブジェクトを取得する方法3選


django.views.generic.detail.SingleObjectMixin.query_pk_and_slug は、Django のジェネリックビューフレームワークで使用されるミックスインクラスです。このクラスは、URL パラメータから主キー (pk) またはスラグ (slug) を使用して、単一のオブジェクトを取得するためのメソッドを提供します。取得されたオブジェクトは、コンテキストデータに追加され、テンプレートでレンダリングされます。

主な機能

  • テンプレートをレンダリングします。
  • 取得されたオブジェクトをコンテキストデータに追加します。
  • フィルタリングされたクエリセットから単一のオブジェクトを取得します。
  • 取得された主キーまたはスラグを使用して、クエリセットをフィルタリングします。
  • URL パラメータから主キー (pk) またはスラグ (slug) を取得します。

詳細

主キー (pk) とスラグ (slug) の取得

SingleObjectMixin クラスは、pk_url_kwargslug_url_kwarg 属性を使用して、URL パラメータから主キー (pk) とスラグ (slug) を取得します。これらの属性のデフォルト値は、それぞれ pkslug です。

class SingleObjectMixin:
    pk_url_kwarg = "pk"
    slug_url_kwarg = "slug"

URL パラメータが設定されている場合は、対応する属性に値が格納されます。

# 例:URL `/article/123/`

self.kwargs['pk'] == 123  # 主キー (`pk`) の値

クエリセットのフィルタリング

取得された主キー (pk) またはスラグ (slug) を使用して、クエリセットをフィルタリングします。

  • 主キー (pk) によるフィルタリング
if pk is not None:
    queryset = queryset.filter(pk=pk)
  • スラグ (slug) によるフィルタリング
if slug is not None and (pk is None or self.query_pk_and_slug):
    slug_field = self.get_slug_field()
    queryset = queryset.filter(**{slug_field: slug})

単一オブジェクトの取得

フィルタリングされたクエリセットから単一のオブジェクトを取得します。

try:
    obj = queryset.get()
except queryset.model.DoesNotExist:
    raise Http404(_("No %(verbose_name)s found matching the query") % {"verbose_name": queryset.model._meta.verbose_name})

コンテキストデータへの追加

取得されたオブジェクトは、object キーを使用してコンテキストデータに追加されます。

context = {
    "object": obj,
}

テンプレートのレンダリング

コンテキストデータを使用して、テンプレートをレンダリングします。

return render_to_response(self.get_template_names(), context)

query_pk_and_slug 属性

query_pk_and_slug 属性は、主キー (pk) とスラグ (slug) を同時に使用してオブジェクトを検索するかどうかを制御します。デフォルト値は False です。この属性を True に設定すると、主キー (pk) とスラグ (slug) の両方が一致するオブジェクトが検索されます。

class ArticleDetailView(DetailView):
    model = Article
    query_pk_and_slug = True  # 主キー (`pk`) とスラグ (`slug`) の両方を検索

この場合、URL /article/123/ または /article/my-article-slug/ のどちらにアクセスしても、同じ記事が詳細表示されます。

django.views.generic.detail.SingleObjectMixin.query_pk_and_slug は、URL パラメータから主キー (pk) またはスラグ (slug) を使用して、単一のオブジェクトを取得するための便利な機能です。この機能を使用することで、柔軟で使い勝手の良い詳細表示ビューを作成することができます。

  • [`


モデル定義

from django.db import models

class Article(models.Model):
    title = models.CharField(max_length=255)
    slug = models.SlugField(unique=True)
    body = models.TextField()
    pub_date = models.DateTimeField(auto_now_add=True)

ビュー定義

from django.views.generic import DetailView
from .models import Article

class ArticleDetailView(DetailView):
    model = Article
    query_pk_and_slug = True  # 主キー (`pk`) とスラグ (`slug`) の両方を検索

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['related_articles'] = Article.objects.exclude(pk=self.object.pk).filter(pub_date__lt=self.object.pub_date)[:5]
        return context
<h1>{{ object.title }}</h1>
<p>{{ object.body }}</p>
<p>Published: {{ object.pub_date|date }}</p>

<h2>Related Articles</h2>
<ul>
{% for article in related_articles %}
    <li><a href="{% url 'article_detail' article.pk %}">{{ article.title }}</a></li>
{% endfor %}
</ul>

このコードはあくまで一例であり、ニーズに合わせて変更することができます。

  • テンプレートは、Jinja2 テンプレートエンジンを使用しています。
  • このコードは、Django バージョン 5.0 を使用しています。


以下に、query_pk_and_slug の代替方法をいくつか紹介します。

カスタムビューを作成する

SingleObjectMixin を継承せずに、カスタムビューを作成することができます。この方法を使用すると、オブジェクトを取得するロジックを完全に制御することができます。

from django.views.generic import View
from .models import Article

class ArticleDetailView(View):
    def get(self, request, *args, **kwargs):
        try:
            pk = kwargs['pk']
            obj = Article.objects.get(pk=pk)
        except Article.DoesNotExist:
            try:
                slug = kwargs['slug']
                obj = Article.objects.get(slug=slug)
            except Article.DoesNotExist:
                raise Http404(_("No Article found matching the query"))

        context = {
            "object": obj,
        }

        return render(request, "article_detail.html", context)

get_object ヘルパー関数を使用する

get_object ヘルパー関数を使用すると、URL パラメータからオブジェクトを取得することができます。

from django.shortcuts import get_object_or_404
from .models import Article

def article_detail_view(request, pk=None, slug=None):
    obj = get_object_or_404(Article, pk=pk, slug=slug)

    context = {
        "object": obj,
    }

    return render(request, "article_detail.html", context)

lookup_field 属性を使用する

SingleObjectMixinlookup_field 属性を使用すると、URL パラメータ名と一致するモデルフィールドを指定することができます。

from django.views.generic import DetailView
from .models import Article

class ArticleDetailView(DetailView):
    model = Article
    lookup_field = 'slug'  # スラグ (`slug`) を使用してオブジェクトを検索

get_queryset メソッドをオーバーライドする

SingleObjectMixinget_queryset メソッドをオーバーライドすると、フィルタリングされたクエリセットを返すことができます。

from django.views.generic import DetailView
from .models import Article

class ArticleDetailView(DetailView):
    model = Article

    def get_queryset(self):
        queryset = super().get_queryset()
        return queryset.filter(published=True)  # 公開済み記事のみを表示