Django 私的便利な汎用viewの属性、メソッド


## 初めに
どのViewで何ができるのか整理するために、Djangoの「クラスベース汎用ビュー(Class-based Generic View)」の概要と属性とサブメソッドについてまとめたいと思います（一部抜粋）。


## Base Class-Based-View(ベース・ビュー)
### 概要
基本的な機能を提供するView。

| ビュー          | 用途                                                               |
|----------------|--------------------------------------------------------------------|
| View           | 基本的なビュー <br> 特定の HTTP メソッドを処理するための汎用的なベースクラス  |
| TemplateView   | テンプレートを表示するビュー                                          　|
| RedirectView   | 特定の URL にリダイレクトするビュー                                    |

### よく使われる属性
#### 1. template_name
- 使用するテンプレートの名前を指定する
- この属性を設定することで、Django がどのテンプレートを使ってレスポンスをレンダリングするかを決定
- 使われる汎用view: `TemplateView` `ListView` `DetailView`
    
    ```python
    class MyView(TemplateView):
        template_name = 'my_template.html'
    ```

#### 2. pattern_name
- リダイレクト先の URL パターンの名前を指定
- 使われる汎用view: `RedirectView`

    ```python
        class MyView(TemplateView):
        content_type = 'application/json'
    ```
    
#### 3.  content_type
- レスポンスのコンテンツタイプ (MIME タイプ) を指定
- 使われる汎用view: `TemplateView` `ListView` `DetailView`

    ```python
        class MyView(TemplateView):
        content_type = 'application/json'
    ```

### よく使われるメソッド
#### 1.  get_context_data()
- ビューに渡すコンテキストデータ（テンプレートに渡される辞書データ）を構成する
- 既存のコンテキストに追加のデータを加えたり、カスタマイズしたい場合にオーバーライド可能
- 使われる汎用view: `TemplateView` `ListView` `DetailView`

    ```python
    from django.views.generic import TemplateView

    class MyView(TemplateView):
        template_name = "my_template.html"
    
        def get_context_data(self, **kwargs):
            context = super().get_context_data(**kwargs)
            context['extra_data'] = "This is additional context data"
            return context
    ```

#### 2.  dispatch()
- HTTP リクエストを処理するエントリポイント
- GET, POST, PUT などのリクエストメソッドに基づいて適切な処理メソッドにルーティングする
- 共通の前処理や後処理を追加する際にオーバーライドする
- 使われる汎用view: `View` `RedirectView` `TemplateView` `ListView` `DetailView`

    ```python
    class MyView(View):
        def dispatch(self, request, *args, **kwargs):
            # 共通の処理を追加
            return super().dispatch(request, *args, **kwargs)
        
        def get(self, request, *args, **kwargs):
            return HttpResponse("GET request processed")
    ```

#### 3. get_redirect_url()
- リダイレクト先の URL を動的に計算するために使用
- 使われる汎用ビュー: `RedirectView`

    ```python
    from django.views.generic.base import RedirectView
    from django.urls import reverse
    
    class LoginRedirectView(RedirectView):
        permanent = False
    
        def get_redirect_url(self, *args, **kwargs):
            # ログイン状態に基づいてリダイレクト
            if self.request.user.is_authenticated:
                return reverse('dashboard')  # ログイン済みならダッシュボードへ
            return reverse('login')  # 未ログインならログインページへ
    ```

## ジェネリック表示ビュー (Generic display view)

### 概要
データを表示するための共通パターンを簡略化する。リストや詳細表示など、データの表示に特化したビューを効率的に作成するための汎用ビュー。

| ビュー          | 用途                           |
|----------------|--------------------------------|
| ListView       | オブジェクトのリストを表示する      |
| DetailView     | 単一オブジェクトの詳細情報を表示する |

## LiseView
### よく使われる属性
- `model` 
    - 表示するオブジェクトのモデルを指定
- `template_name`
    - 使用するテンプレートの名前を指定
    - 定義しないと、`django.core.exceptions.ImproperlyConfigured` 例外が発生
- `context_object_name`
    - テンプレートで使用するコンテキスト変数の名前を指定
- `paginate_by`
    - ページネーションの際に、1ページあたりに表示するオブジェクトの件数を指定します
- `ordering`
    - クエリセットのデフォルトの並び順を指定

### よくわれるメソッド
- `get_queryset() `
    - ビューが表示するオブジェクトを取得するために使われる、クエリセットを返す
    - デフォルトでは `model.objects.all()`
- `paginate_queryset()`
    - クエリセットをページネーション用に分割

```python
class ArticleListView(ListView):
    # 表示するオブジェクトのモデルを指定
    model = Article
    # 使用するテンプレートの名前を指定
    template_name = 'articles/article_list.html'
    # テンプレートで使用するコンテキスト変数の名前を指定
    context_object_name = 'articles'
    # 1ページあたりに表示するオブジェクトの件数を指定
    paginate_by = 5
    # クエリセットのデフォルトの並び順を指定
    ordering = ['-published_date']

    def get_queryset(self):
        """
        デフォルトのクエリセットをカスタマイズする。
        公開済みの記事のみを取得。
        """
        queryset = super().get_queryset()
        return queryset.filter(is_published=True)

    def paginate_queryset(self, queryset, page_size):
        """
        ページネーションの際にクエリセットを分割。
        デフォルトの paginate_queryset() をオーバーライド。
        """
        paginated_queryset = super().paginate_queryset(queryset, page_size)
        return paginated_queryset

```
## DetailView
### よく使われる属性
- `model` 
    - 表示するオブジェクトのモデルを指定
- `template_name`
    - 使用するテンプレートの名前を指定
    - 定義しないと、`django.core.exceptions.ImproperlyConfigured` 例外が発生
- `context_object_name`
    - テンプレートで使用するコンテキスト変数の名前を指定
- `pk_url_kwarg`
    - URLから取得するプライマリキーのパラメータ名を指定
    - デフォルトは`pk`
- `slug_field`
    - スラッグフィールドを使用する場合に、モデルのスラッグを格納するフィールド名を指定
- `slug_url_kwarg`
    - URLから取得するスラッグのパラメータ名を指定

### よく使われるメソッド
- `get_object() `
    - 表示する単一のオブジェクトを取得

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

class ArticleDetailView(DetailView):
    model = Article  # 表示するモデルを指定
    template_name = 'article/detail.html'  # 使用するテンプレートの指定
    context_object_name = 'article'  # テンプレートで使用するコンテキスト変数の名前
    pk_url_kwarg = 'article_id'  # URLから取得するプライマリキーのパラメータ名
    slug_field = 'slug'  # スラッグを使用する場合に指定するフィールド名
    slug_url_kwarg = 'slug'  # URLから取得するスラッグのパラメータ名

    def get_object(self, queryset=None):
        # `get_object` メソッドで特定のオブジェクトを取得する場合はカスタマイズ可能
        # デフォルトでは `self.model.objects.get(pk=self.kwargs['pk'])` が呼ばれます
        return super().get_object(queryset)

```

## まとめ
ここまで目を通していただき、ありがとうございました。
調べていく中でも知らない属性があったり、メソッドの呼び出す順番や継承しているViewなど理解が深まっていく過程を楽しむことができました。

## 参照
https://docs.djangoproject.com/ja/5.1/ref/class-based-views/base/

https://docs.djangoproject.com/ja/5.1/ref/class-based-views/generic-display/

https://github.com/sinjorjob/django-Class-Based-View?tab=readme-ov-file