◀ 2.

djangoの関数ベースビュー作り方とviewの分割方法

▶

関数ベースビューを機能別ファイルへ分け、URLとの接続を確認する手順です。FBVとCBVはどちらも使える方式で、どちらが主流かではなく処理と再利用の必要性で選びます。

projectのURL設定からapp1のURL設定を経て関数またはas_viewで分割ビューへ接続する流れ

この記事の要点
  • Django の関数ベースビュー (Function-Based View)の作り方と分割
  • 基本: views.py に def index(request): return render(...) 形式で書く
  • URL ディスパッチ: urls.py で path("", views.index) 形式で対応付け
  • 関数が増えてきたら views/ ディレクトリ + 機能別ファイルに分割

 

以下、デフォルトのディレクトリ構造

プロジェクト名/
    db.sqlite3
    manage.py
   
プロジェクト名/
        __init__.py
        settings.py
       
urls.py
        wsgi.py
   
アプリケーション名/
        __init__.py
        __pycache__/
        admin.py
        apps.py
        migrations/
        models.py

        views.py

1アプリケーションに1ビューという制限はありません。標準のviews.pyはPythonの1モジュールで、複数の関数やクラスを置けます。短い処理なら無理に分割せず、機能別の責務やテストの読みやすさで分割を決めます。旧図はASGI等を省いた構成例で、Djangoが全ファイルを自動生成するという意味ではありません。

それを以下のように修正する。

 プロジェクト名/
    db.sqlite3
    manage.py
   
プロジェクト名/
        __init__.py
        settings.py
       
urls.py
        wsgi.py

  アプリケーション名/
        __init__.py
        __pycache__/
        admin.py
        apps.py
        migrations/
        models.py
       
urls.py
        views

                __init__.py
                index.py
                test.py

既存のviews.pyを内容ごと削除しないでください。変更前のコードを版管理や別の退避先へ保存し、既存関数・クラス・import・デコレーター・URL名を棚卸しします。処理をviews/内の各モジュールへ移してimportを更新し、確認後に切り替えます。同じapp1にviews.pyとviews/を残してどちらが読まれるかに依存せず、切替後はviews/へ一本化します。この記事の例で既存プロジェクトのファイルを丸ごと上書きしません。

その中に分割したviewファイル(上記の例では index.py および test.py)と__init__.pyファイルを作成する。

更にアプリケーション名ディレクトリ直下にurls.pyを作成してルーティング処理を記載する。

プロジェクト名ディレクトリ直下のurls.pyを修正する必要もある。

以下、それぞれのファイルの詳細を記述する。

今回のアプリケーション名は「app1」とします。

 

動かす前に揃える設定

追加例はPython 3.12 / Django 5.2系の独立した学習用プロジェクトです。プロジェクトのPythonパッケージ名をproject、アプリ名をapp1とします。manage.pyのあるディレクトリを基準に配置し、project/__init__.py・app1/__init__.py・app1/views/__init__.pyは空で用意します。__pycache__は手で作りません。既存設定は保持して必要箇所だけ照合します。

次は新しい学習用構成の断片です。既存のINSTALLED_APPSやTEMPLATESをこの短いリストで置き換えず、既存アプリ・loader・context_processors・MIDDLEWAREのCSRF/認証設定は保持してください。

ROOT_URLCONF = "project.urls"
INSTALLED_APPS = ["app1"]
TEMPLATES = [{
    "BACKEND": "django.template.backends.django.DjangoTemplates",
    "DIRS": [],
    "APP_DIRS": True,
    "OPTIONS": {"context_processors": []},
}]

これはsettings.pyへ照合する断片で、秘密鍵・許可Host・DB・認証等を含む本番設定一式ではありません。ROOT_URLCONFはファイルパスでなくimport可能なPythonモジュール名です。APP_DIRS=Trueは登録したアプリのtemplates/を探します。INSTALLED_APPSへapp1を追加するだけではURLへ接続されないため、project.urlsのincludeも必要です。表示だけの例なのでmigrateや実DBの更新は不要です。

分割したviewファイル

index.py

from django.http import HttpResponse

def page(request):

    return HttpResponse("index view.")

 

test.py

from django.http import HttpResponse

def page(request):

    return HttpResponse("test view.")

 

追加例:明示的なimportで使う2つのビュー

app1/views/index.py

from django.http import HttpResponse
from django.views.decorators.http import require_safe


@require_safe
def page(request):
    return HttpResponse("index view.")

app1/views/test.py

from django.http import HttpResponse
from django.views.decorators.http import require_safe


@require_safe
def page(request):
    return HttpResponse("test view.")

2つのモジュールに同名のpage関数があってもindex.pageとtest.pageで区別できます。require_safeはGETとHEADを許可し、それ以外は405にします。旧例はメソッドを制限しないため、この追加例とは受け付けるメソッドが異なります。HEADは本文なしで確認します。POSTで保存する処理へ変える場合は、メソッド許可だけでなくCSRF・認証・権限・入力検証を別に実装します。

__init__.py

この節の旧2行は追加例へコピーしません。from .index import pageの後にfrom .test import pageを書くと、パッケージのpageは後者で上書きされます。旧コードはサブモジュールも読み込むのでviews.index.page/views.test.pageは参照でき、一律に動かないという意味ではありません。追加例は__init__.pyを空にし、urls.pyでfrom .views import index, testと明示します。空に変えるだけで旧urls.pyを残すのではなく、importも一緒に切り替えます。

from .index import page

from .test import page

 

アプリケーション名直下のurls.py

from django.urls import path

from . import views

urlpatterns = [

    path('', views.index.page, name='index'),

    path('test/', views.test.page, name='test'),

]

 

追加例:app1/urls.py

from django.urls import path
from .views import index, test

app_name = "app1"
urlpatterns = [
    path("", index.page, name="index"),
    path("test/", test.page, name="test"),
]

app_nameとnameによりreverse("app1:index")は/app1/、reverse("app1:test")は/app1/test/を返します。ファイルを分割しても公開パスは維持できます。ただし既存のindex等を名前空間なしで逆引きしているプロジェクトへapp_nameを後付けする場合は、呼出し側のURL名も更新・確認します。パス維持とURL名の互換性は別です。

プロジェクト名直下のurls.py

追加例のproject/urls.pyは次の通りです。既存の管理画面や他アプリのパターンを消さず、app1へのincludeだけを追加・確認します。includeは一致したapp1/を除く残りのパスをアプリ側へ渡します。

from django.urls import include, path

urlpatterns = [
    path("app1/", include("app1.urls")),
]

保存用の旧project URLconfも残しています。上書き用の完全な既存設定ではありません。

from django.contrib import admin

from django.urls import include, path

urlpatterns = [

    path('app1/', include('app1.urls')),

]
 

 

以上で以下のURLをアクセスすることで異なるviewにアクセスすることができます。

http://127.0.0.1:8000/app1/

http://127.0.0.1:8000/app1/test/

切替後の確認と、開けない場合の調べ方

  1. 対象プロジェクトの仮想環境でpython manage.py checkを実行し、importとURL定義のエラーを確認します。checkの成功だけでは実際の応答や権限を保証しません。
  2. 開発用の127.0.0.1で/app1/と/app1/test/のGET、別URLの404、HEADとPOSTを個別に確認します。本番公開やroot起動は行いません。
  3. 404ならproject.urlsのinclude、app側のパスと末尾スラッシュ、実際の開始URLを照合します。APPEND_SLASHのリダイレクトでPOST本文が保たれると仮定しません。
  4. ImportError/AttributeErrorならPythonの配置とimport対象、views.pyとviews/の混在や循環importを確認します。__init__.pyで全ビューを一括importして依存を増やさないようにします。
  5. TemplateDoesNotExistならtemplate_name、アプリ登録、APP_DIRS/DIRSと実ファイル位置を確認します。403はCSRF/権限、405はHTTPメソッドの受け付けを切り分け、csrf_exemptでエラーを隠しません。
  6. 旧URL・名前付き逆引き・デコレーター/認証・応答本文のテストを通してから切り替えます。ファイル移動だけで既存のログイン/権限処理が移るとは限りません。

公開データの更新や認証・フォーム保存はこの表示用例の対象外です。自作のパッケージをdjango.pyやhttp.pyと命名して標準/外部モジュールを隠さないことも確認します。関数とクラスを混在させても構いません。

関連する既存ページ

ビューの親ページ、URLディスパッチャー、クラスベースビュー、CBVのGET/POST、開発サーバーの待受とポートを目的に合わせて選んでください。

根拠と検証範囲(2026年10月26日)

Django公式:ビュー、CBVの導入、URLの接続と名前空間、View/TemplateView、テンプレート探索を確認しました。追加例はPython3.12.10/Django5.2.18の隔離環境でURL解決/逆引き・実際の表示/HEAD/POST・CSRF・テンプレート探索・同名関数の上書きを検査しています。実DBへの書込み・本番配備・認証/全middleware・他の版・ASGI非同期処理は未検証です。

子ページ

子ページはありません

同階層のページ
  1. クラスベースビューの作り方とviewの分割
  2. 関数ベースビューの作り方とviewの分割
  3. URLディスパッチャー(ルーティング処理)
  4. GETとPOSTパラメータ受け取り
  5. クラスベースビューでGET/POSTリクエストの受け取り方
  6. クラスベースビューでテンプレートに値を渡す方法
  7. ビューでリダイレクト
  8. cookieの値の設定と取得
  9. HTTPステータスコードの返し方

最近更新/作成されたページ