59

I have a Django project, let's say "project1". Typical folder structure for applications is:

/project1/
         /app1/
         /app2/
         ...
         __init__.py
         manage.py
         settings.py
         urls.py

What should I do if I want to hold all of my applications in some separate folder, 'apps' for example? So that structure should look like the following:

/project/
         apps/
              app1/
              app2/
              ...
         __init__.py
         manage.py
         settings.py
         urls.py
ikostia
  • 7,395
  • 6
  • 30
  • 39

9 Answers9

63

You can add your apps folder to your python path by inserting the following in your settings.py:

import os
import sys

PROJECT_ROOT = os.path.dirname(__file__)
sys.path.insert(0, os.path.join(PROJECT_ROOT, 'apps'))

Then you can use all the apps in this folder just in the same way as they were in your project root!

Bernhard Vallant
  • 49,468
  • 20
  • 120
  • 148
25

You can do this very easily, but you need to change the settings.py to look like this:

INSTALLED_APPS = (
    'apps.app1',
    'apps.app2',
    # ...
)

And your urls.py to look like this:

urlpatterns = patterns('', 
    (r'^app1/',include('apps.app1')),    
    (r'^app2/',include('apps.app2')),    
)

.. and modify any imports to point to the app location

Gabi Purcaru
  • 30,940
  • 9
  • 79
  • 95
  • 4
    I recommend against using this method, as it might lead to other apps not being able to reference your own application, and will require you to change all imports in your apps to point to the new directory. I think the right way is in [Bernhard Vallant's answer](http://stackoverflow.com/a/3948821/1057102). – sleblanc Aug 26 '13 at 21:37
  • This same pattern is followed in [django-oscar](https://github.com/django-oscar/django-oscar) project. – Dineshs91 Jun 17 '17 at 17:19
  • I downvoted for the same reason as sleblanc - especially thinking about reusable models, where you might relate to a model using e.g. `ForeignKey('appname.ModelName', ...)` being upset by this – thclark Apr 08 '18 at 14:25
  • If you plan to use this convention in the mid of the development note that your migrations will create new tables in the database and won't map to the data you were working with. – Akarsh Jain May 05 '21 at 08:48
20

How about you utilize the BASE_DIR variable already present in the settings.py.

Just add the following:

import sys
sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))

Hope this helps.

anshuman
  • 335
  • 3
  • 8
7

As a slight variant to Berhard Vallant's or Anshuman's answers, here is an alternative snippet to place in settings.py

import os
import sys  # Insert this line

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# Insert the two lines below
APPS_DIR = os.path.join(BASE_DIR, '<your_project_dir_name>/apps/')
sys.path.insert(0, APPS_DIR)

Doing it in this way has the added benefit that your template directories are cleaner as they will look like below. Without the APPS_DIR variable, there will be a lot of repitition of <your_project_dir_name>/apps/ within the DIRS list of the TEMPLATES list.

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
            os.path.join(APPS_DIR, '<app_name>/templates/<app_name>'),
            os.path.join(APPS_DIR, '<app_name>/templates/<app_name>'),
            ...
        ],
        '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',
            ],
        },
    },
]

You can list the apps within the INSTALLED_APPS list as normal with either the short-form name given in apps.py or by using the long-form syntax of appname.apps.AppnameConfig replacing appname with your app's name.

Wayne Lambert
  • 576
  • 5
  • 9
2

It's easy and simple you need to add to settings.py

import os
import sys

PROJECT_ROOT = os.path.dirname(__file__)
sys.path.insert(0, os.path.join(PROJECT_ROOT, 'apps'))

and edit your app config for example

old app config:

    class MyappConfig(AppConfig):
          default_auto_field = 'django.db.models.BigAutoField'
          name = 'myapp'

to new app config:

    class MyappConfig(AppConfig):
        default_auto_field = 'django.db.models.BigAutoField'
        label='myapp'
        name = 'apps.myapp'

than installed apps example:

INSTALLED_APPS = [
     ...
     'apps.myapp.apps.MyappConfig'
     ...
]

I think it's very usefull and helpfull.Good luck :)

Muhammadalive
  • 648
  • 5
  • 5
1

If you're using virtualenv/virtualenvwrapper (which is a bit dated but still valid), you can use the included add2virtualenv command to augment your python path:

mkdir apps
cd apps
pwd
[/path/to/apps/dir]

Copy that path to clipboard, then:

add2virtualenv /path/to/apps/dir
shacker
  • 14,712
  • 8
  • 89
  • 89
1

Just add __init__.py (4 underscores in total) in your apps folder. Now you can just do

urlpatterns = [
        path('polls/',include('apps.polls.urls')),
        path('admin/', admin.site.urls)
]
Aniket Thakur
  • 66,731
  • 38
  • 279
  • 289
0

In my case, my project folder structure is the following:

/project/
   /apps/
      /app1/
      /app2/
   /src/
      /settings.py
      ...

So I've solved it with these two lines on my settings.py:

BASE_DIR = os.path.dirname(os.path.dirname(__file__))
sys.path.insert(0, os.path.join(BASE_DIR, '../apps'))

No need to alter urls.py.

C. S. F. Junior
  • 341
  • 1
  • 3
  • 20
0

The following worked for me.

This is the folder structure:

/project1
    /apps
        /myapp

inside apps.py under /myapp:

class MyAppConfig(AppConfig):
    name = "apps.myapp"

In the settings.py:

INSTALLED_APPS = [
    ...
    "apps.myapp.apps.MyAppConfig",
]
Whale
  • 49
  • 4