Django Best Practices: Projects vs Apps
Tags: django, python, tutorial, beginners
Published: 2020-02-21 14:09:02

Django's definition of an "app" is often confusing to newcomers. In this post we'll examine the four major concepts of Django architecture by building out a basic blog web application.

The first step, always, is to install Django within a dedicated virtual environment. Let's assume we're creating a `code` directory on our Desktop (I'm using a Mac). The commands would be as follows:

```
$ cd ~/Desktop
$ mkdir code && cd code
$ pipenv install django==3.0.3
$ pipenv shell
(code) $
```

We're now working within a virtual environment shell with Django installed.

## Project

A **project** is a web application using Django. There is only ever one project and many "apps" within it. So for our blog web application, we need to create it and assign a name like `config`.

```
(code) $ django-admin startproject config .
(code) $ tree
.
├── Pipfile
├── Pipfile.lock
├── config
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── manage.py
```

Note I've add the optional period `.` at the end of the command so the files are included in the current directory. Otherwise Django would automatically create an additional directory with our project name and then add the starter files within that directory, which seems redundant to me, but some developers like that approach.

## INSTALLED_APPS

Within the newly created `settings.py` file is a configuration called `INSTALLED_APPS` which is a list of Django apps within a project. Django comes with six built-in apps that we can examine.

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

## Apps

A Django app is a small library representing a discrete part of a larger project. For example, our blog web application might have an app for `posts`, one for static pages like an About page called `pages`, and another app called `payments` to charge logged-in subscribers.

We can add an app by using the `startapp` command so let's add the `posts` app now. Using the `tree` command we can then see our complete updated structure.

```
(code) $ python manage.py startapp posts
(code) tree
.
├── Pipfile
├── Pipfile.lock
├── config
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── manage.py
└── posts
    ├── __init__.py
    ├── admin.py
    ├── apps.py
    ├── migrations
    │   └── __init__.py
    ├── models.py
    ├── tests.py
    └── views.py
```

The `posts` app has been created and comes with its own associated files. Often you'll want to also add a `urls.py` file here, too.

We **also** must add the app to our `INSTALLED_APPS` setting or else the Django project won't recognize it.

```python
# config/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'post.apps.PostsConfig', # new
]
```

Deciding on what constitutes an "app" is necessarily subjective. Could we combine all the logic for our posts and payments into one app? Yes, we could. Does that make it easier to reason about as our project grows in size? I'd argue no but, again, it's subjective. You'll see various approaches to app design out in the wild but the general best practice is the same: each Django app should do one thing, and one thing alone.

## 3rd Party Packages

A [3rd party package](https://github.com/wsvincent/awesome-django/blob/master/README.md#third-party-packages) is a plain old Django application that has been designed to be pluggable into any existing project with the Python packaging tools. You can see a [tutorial on this here](https://docs.djangoproject.com/en/dev/intro/reusable-apps/). It takes just a few additional steps.

This is a case where we can see the power of separating out functionality into smaller apps. It's far easier to share them either within a larger project, within a company, or to make public like a 3rd Party Package.

## App naming conventions

An app's name should follow [Pep 8 Guidelines](https://www.python.org/dev/peps/pep-0008/#package-and-module-names), namely it should be short, all-lowercase and not include numbers, dashes, periods, spaces, or special characters. It also, in general, should be the plural of an app's main model, so our `posts` app would have a main model called `Post`.

## Conclusion

Django apps may seem like overkill when you're starting out but they provide much needed structure and flexibility to any Django web application. Further the ability to separate one out completely, if desired, has led to a robust ecosystem of Django 3rd Party Packages that improve the overall community immensely.