Djangoにおける関数ベースビュー(FBV)の詳細解説

DjangoのMTV(Model-Template-View)アーキテクチャにおいて、ビューはリクエストを受け取り、ビジネスロジックを処理した上でレスポンスを返す「制御塔」の役割を果たします。関数として定義されるビューはFBV(Function-Based Views)と呼ばれ、そのシンプルさと直感的な構造から多くのプロジェクトで利用されています。

レスポンスの生成と制御

Djangoでは、django.httpモジュールに含まれる様々なクラスを使用して、クライアントに返すHTTPレスポンスを制御します。 主要なレスポンスクラスは以下の通りです:
  • HttpResponse: 標準的なテキストやHTMLを返す(ステータスコード200)
  • JsonResponse: Pythonの辞書オブジェクトをJSON形式で返す
  • HttpResponseRedirect / HttpResponsePermanentRedirect: リダイレクト処理(302 / 301)
  • HttpResponseNotFound: 404エラーを返す
  • StreamingHttpResponse: 大規模なデータやファイルをストリームとして出力する
以下は、基本的なHttpResponseの利用例です。
from django.http import HttpResponse

def basic_response_view(request):
    html_content = "<html><body><h1>Hello, Django</h1></body></html>"
    return HttpResponse(html_content, content_type="text/html", status=200)

renderとredirectによる効率化

文字列でHTMLを構築するのは非効率なため、通常はrenderショートカット関数を使用します。これにより、テンプレートファイルとデータを結合してレスポンスを生成できます。
from django.shortcuts import render

def profile_view(request):
    user_data = {'name': 'Taro', 'age': 25}
    return render(request, 'user_profile.html', context=user_data, status=200)
リダイレクトについても、redirect関数を使用することで、URL名やモデルオブジェクトを指定した柔軟な遷移が可能になります。
from django.shortcuts import redirect

def move_to_home(request):
    # 名前付きURLへのリダイレクト
    return redirect('home_index', permanent=False)

例外レスポンスのカスタマイズ

システムエラーやページ未検出時の挙動をカスタマイズするには、プロジェクトのurls.pyでハンドラーを指定します。
# urls.py
handler404 = 'myapp.views.custom_404_handler'
handler500 = 'myapp.views.custom_500_handler'

# views.py
def custom_404_handler(request, exception):
    return render(request, 'errors/404.html', status=404)
※この設定を有効にするには、settings.pyでDEBUG = Falseに設定されている必要があります。

高度なファイルダウンロード機能

Djangoでは、ファイルの提供方法として3つのアプローチがあります。
  1. HttpResponse: ファイル全体をメモリにロードして返す。小規模なファイル向き。
  2. StreamingHttpResponse: イテレータを使用してデータを分割して送信する。メモリ消費を抑えられる。
  3. FileResponse: StreamingHttpResponseをファイル向けに最適化したもの。
以下に、FileResponseを用いた実装例を示します。
import os
from django.http import FileResponse, Http404

def secure_file_download(request):
    storage_path = "/path/to/files/document.pdf"
    if not os.path.exists(storage_path):
        raise Http404("ファイルが存在しません")
    
    file_handle = open(storage_path, 'rb')
    response = FileResponse(file_handle, as_attachment=True, filename="downloaded_doc.pdf")
    return response

HTTPリクエストオブジェクトの解析

ビューの第一引数として渡されるrequestオブジェクト(WSGIRequestクラス)には、クライアントからの全ての情報が含まれています。 よく利用されるプロパティ:
  • request.method: リクエストの種類('GET', 'POST'など)
  • request.GET / request.POST: クエリパラメータやフォームデータ
  • request.FILES: アップロードされたファイルデータ
  • request.headers: HTTPヘッダー情報
  • request.user: 現在ログイン中のユーザーオブジェクト
def inspect_request(request):
    print(f"アクセス元ホスト: {request.get_host()}")
    print(f"プロトコル: {request.scheme}")
    
    if request.method == 'GET':
        query = request.GET.get('search_word', '')
        return HttpResponse(f"検索ワード: {query}")

ファイルのアップロード処理

フォームを介して送信されたファイルは、request.FILES経由でアクセスします。HTML側でenctype="multipart/form-data"を指定することが必須です。
# views.py
def upload_handler(request):
    if request.method == 'POST' and request.FILES.get('attachment'):
        target_file = request.FILES['attachment']
        
        # 保存先パスの設定
        save_path = os.path.join('uploads', target_file.name)
        
        with open(save_path, 'wb+') as destination:
            # チャンクごとに処理することでメモリ効率を維持
            for chunk in target_file.chunks():
                destination.write(chunk)
                
        return HttpResponse("アップロード完了")
    return render(request, 'upload_form.html')
InMemoryUploadedFile(小規模ファイル)またはTemporaryUploadedFile(大規模ファイル)として扱われるため、chunks()メソッドを使用して保存することで、サーバーのメモリ負荷を最小限に抑えることができます。

タグ: Django Python Backend http-request web-development

11月3日 17:32 投稿