Help us understand the problem. What is going on with this article?

【Django】ディレクトリ構成のプラクティス + 注意点

Djangoアプリケーションのディレクトリ

Djangoアプリケーションは1アプリごとにディレクトリを生成するので、
$ python manage.py startapp hogeでアプリを追加していくと、ルートディレクトリにどんどんフォルダが出来てしまう。

ディレクトリごとに機能を分離できるのは良いのだが、すべての機能が並列ではないので、アプリケーションが増えるたびに見通しが悪くなっていってしまう。

自分の場合、./app/sub_app/...とディレクトリをネストし、すっきりさせることが多い。

  • 並列にアプリケーションを作っていく場合の例
    機能は分離できるものの、urlと対応しておらず見通しが悪い。
.
├── account/     (/account/login etc)
├── auth_api/    (/api/auth/...)
├── config
│   └── settings.py
├── email/       (/account/email/...)
├── manage.py
├── password/    (/account/password/...)
└── polls_api/   (/api/polls/...)

  • アプリケーションをネストして作っていく場合の例
    urlとディレクトリが対応し、わかりやすい。
.
├── account/      (/account/login etc)
│   ├── email/    (/account/email/...)
│   └── password/ (/account/password/...)
├── api/
│   ├── auth/     (/api/auth/...)
│   └── polls/    (/api/polls/...)
├── config
│   └── settings.py
└── manage.py

しかし、躓く点が多いので注意点をまとめる。

環境

  • CentOS 7
  • Django 3.0.3
  • Python 3.7.4

前提

以下は、$ django-admin startproject config .とした後、python manage.py startapp accountとした場合のフォルダ構成。

.
├── account
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── config
│   ├── __init__.py
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── manage.py
├── poetry.lock
└── pyproject.toml
  • urls.pyの作成

urls.pyはよくアプリケーションディレクトリに作成するので、account/urls.pyを追加しておく。
TopViewというViewを作成したとする。

account/urls.py
from django.urls import path, include
from . import views

app_name = 'account'
urlpatterns = [
    path("top/", views.TopView.as_view(), name="top")
]

config/urls.pyaccount/urls.pyをincludeしておく。

config/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('account/', include('account.urls')), # 追加
]
  • settings.pyに登録
    最後に、accountアプリケーションをconfig/settings.pyに記入。
config/settings.py
INSTALLED_APPS = [
    # defaults
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    # 追加
    'account'
]
  • urlの参照

この場合、TopViewのurlは、/account/topである。
template内では、以下のようにurlを指定する。

<a href="{% url 'account:top'%}">トップぺージへのリンク</a>

HTMLがレンダーされる際、Djangoが以下のように展開してくれる。

<a href="/account/top">トップぺージへのリンク</a>

accountディレクトリ内にアプリケーションを作成

アプリを作成

accountフォルダの中に、パスワード関連機能をまとめたpasswordアプリを作成する。
python manage.py startapp password account/passwordとすると作成されそうなものだが、
残念ながらstartappで位置を指定する場合、ディレクトリを作成してくれない。

$ python manage.py startapp password account/password
CommandError: Destination directory '.../account/password' does not exist, please create it first.

先にディレクトリを作成しろと言われるので、作成。
そうすると、account/password内にアプリが作成される。

$ mkdir account/password
$ python manage.py startapp password account/password

現在のディレクトリ。

.
├── account
│   ├── ()
│   └── password
│        ├── __init__.py
│        ├── admin.py
│        ├── apps.py
│        ├── migrations
│        │   └── __init__.py
│        ├── models.py
│        ├── tests.py
│        └── views.py
├── config
│   └── ()
├── manage.py
├── poetry.lock
└── pyproject.toml

urlを登録

今までと同じように、account/password/urls.pyを作成する。
ViewにPassChangeViewというViewを作成した。

account/password/urls.py
from django.urls import path, include
from . import views

app_name = 'password'
urlpatterns = [
    path('change/', views.PassChangeView.as_view(), name='change'),
]

account/urls.pyurls.pyをincludeする。

この時、password.urlsをincludeすれば動きそうな気がするが、account.password.urlsとしなければ動かないので注意。

account/urls.py
from django.urls import path, include
from . import views

app_name = 'account'
urlpatterns = [
    path("top/", views.TopView.as_view(), name="top"),
    path("password/", include('account.password.urls'), name="password") # 追加
]

このとき、PassChangeViewのurlは/account/password/changeとなる。

urlの参照

template内では、以下のようにurlを指定する。

<a href="{% url 'account:password:change'%}">トップぺージへのリンク</a>

settings.pyにアプリケーションを登録

account/passwordにpasswordが作成されたが、config/settings.pyにアプリケーションを記入しなければマイグレーションができない。
INSTALLED_APPSに記入する際は、:ではなく.を使用する。

config/settings.py
INSTALLED_APPS = [
    # defaults
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'account',
    'account.password' # 追加
]

migrate

passwordアプリケーションのmigrateを行う場合も少し挙動が違うので注意。

$ python manage.py makemigrations password
    -> 〇
$ python manage.py makemigrations account.password
    -> ×
$ python manage.py makemigrations account:password
    -> ×
$ python manage.py makemigrations account/password
    -> ×

まとめ

パスとある程度対応させたディレクトリ構成のほうが把握しやすいのですが、最初はいろんなところで躓いたのでまとめました。
3階層までやるとかなりごちゃごちゃしていくのですが、2階層であればすっきりするのでおすすめです。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした