Django
python3

Django ベスト・プラクティス

最終:2018/10/13
追記予定

参考

メンテナンスしやすいディレクトリ構成

<デフォルト、チュートリアルの問題点>

  • プロジェクト名と設定ディレクトリ名が同一で分かりにくい
  • プロジェクト名=メインアプリケーション名が個人的にしっくり

→ 設定ディレクトリを分かりやすくする

設定ディレクトリを分かりやすくする

$ mkdir <projectName>
$ cd <projectName>
$ django-admin.py startproject config . # 第1引数:設定ディレクトリ名 第2引数:Djangoの起点
出来上がるディレクトリ構成
<projectName>/
             |-- manage.py
+            `-- config/
                       |-- __init__.py
                       |-- settings.py
                       |-- urls.py
                       `-- wsgi.py

※プロジェクト作成後にディレクトリ名を変えると色々動かなくなる
以下の変更で、既存のプロジェクトで設定ディレクトリ名を変更しても動作する。

settings.py
ROOT_URLCONF = 'config.urls'

まとめる

<デフォルト、チュートリアルの問題点>

  • アプリケーションごとにstaticファイルやテンプレートを配置すると煩雑

→ staticファイルをベースディレクトリ直下にまとめる

staticファイルをベースディレクトリ直下にまとめる

目的のディレクトリ構成
<projectName>/
             |-- config/
             |         |-- __init__.py
             |         |-- settings.py
             |         |-- urls.py
             |         `-- wsgi.py
+            |-- static/
             |         |-- app1/
             |         |       `-- images/
             |         |                 :
             |         |-- app2/
             |         |        `-- images/
             |         |                  :
             |         |-- js/
             |         |     |-- jquery.*
             |         |     :
             |         |-- css/
             |         |      |-- base.css
             |         :      :
+            |-- templates/
             |            |-- base.html
             |            |-- app1/
             |            |       |-- tmplt.html
             |            |       :
             |            |-- app2/
             |            |       |-- tmplt.html
             |            :       :
             |-- app1/
             |       |-- __init__.py
             |       |-- admin.py
             |       |-- apps.py
             |       |-- models.py
             |       |-- tests.py
             |       |-- views.py
             |       `-- migrations/
             |                      |-- __init__.py
             |                      |-- <migrateファイル>
             |                      :
             |-- app2/
             :       |-- __init__.py
                     |-- admin.py
                     |-- apps.py
                     |-- models.py
                     |-- tests.py
                     |-- views.py
                     `-- migrations/
                                    |-- __init__.py
                                    |-- <migrateファイル>
                                    :

上記ディレクトリ構成を用いるには以下の設定が必要。

settings.py
  BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
  PROJECT_NAME = os.path.basename(BASE_DIR)
  :
  TEMPLATES = [
      {
          'BACKEND': 'django.template.backends.django.DjangoTemplates',
+         'DIRS': [os.path.join(BASE_DIR, 'templates')],
          'APP_DIRS': True,
          'OPTIONS': {
              'context_processors': [
                  'django.template.context_processors.debug',
                  'django.template.context_processors.request',
                  'django.contrib.auth.context_processors.auth',
                  'django.contrib.messages.context_processors.messages',
               ],
           },
       },
  ]
  :
  STATIC_URL = '/static/'
+ STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
  STATIC_ROOT = '/var/www/{}/static'.format(PROJECT_NAME)

分ける

<デフォルト、チュートリアルの問題点>

  • 複数モデル、複数ビュー、複数urlがそれぞれ1ファイルにまとめられていて分かりにくい
  • テーブルごとのmodelや機能ごとのビューに分けたい

→ 適切に分ける

model、ビューの分割

アプリケーションディレクトリの中身
|-- app1/
:       |-- __init__.py
        |-- admin.py
        |-- apps.py
+       |-- models/
        |         |-- __init__.py
        |         |-- model1.py
        |         :
        |-- tests.py
+       |-- views/
        |        |-- __init__.py
        |        |-- view1.py
        |        :       
         `-- migrations/

以下の設定が必要。

models/__init__.py
from .models.model1 import Model # model1.pyで定義しているモデルクラス
:
views/__init__.py
from .views/view1 from View # view1で定義しているクラスまたはメソッドのビュー
:

viewを分割した場合はURLとビューの紐づけ指定もポイント。

config/urls.py
urlpatterns = [
    path('/hoge/', アプリケーション名.views.ファイル名.メソッド名),         # メソッドベースのビュー
    path('/fuga/', アプリケーション名.views.ファイル名.クラス名.asView()), # メソッドベースのビュー
    :
]

urls.pyの分割

上記を実行すると、ビューが分割された分urls.pyに記述する項目が多くなり、管理が難しくなる。
 そこで、urls.pyもアプリケーションごとに分散させる。

目的のディレクトリ構成(一部省略)
<projectName>/
             |-- config/
             |         |-- __init__.py
             |         |-- settings.py
             |         |-- urls.py
             |         `-- wsgi.py
             :
             |-- app1/
             |       |-- __init__.py
             |       |-- admin.py
             |       |-- apps.py
             |       |-- models.py
             |       |-- tests.py
             |       |-- views.py
+            |       |-- urls.py
             |       `-- migrations/
             |-- app2/
             :       |-- __init__.py
                     |-- admin.py
                     |-- apps.py
                     |-- models.py
                     |-- tests.py
                     |-- views.py
+                    |-- urls.py
                     `-- migrations/
config/urls.py
+ from django.urls import include

  urlpatterns = [
      path('admin/', admin.site.urls),
      path('', views.index, name='index),
+     path('app1/', include('app1.urls'),
+     path('app2/', include('app2.urls'),
  ]

includeしたapp1/urls.py、app2/urls.pyは以下の感じで記述する。

app1/urls.py
# '/app1/'まではconfig/urls.pyで解析済みなので、それ以降のURLをここで解析する。
urlpatterns = [
    path('login/', admin.site.urls),            # '/app1/login/'
    path('logout', views.index, name='index'),  # '/app1/logout/'
    path('register/', include('app1.urls'),     # '/app1/register/'
]