RizTech Academy logo
RizTech Academy
Getting StartedLesson 4 of 430 min

Apps, settings and project structure

Django projects are built from apps, and the way you divide a project into apps — and configure it through settings — is a structural decision you make early and live with for a long time. Get the division sensible and the codebase stays navigable as it grows; get it wrong and everything ends up in one giant module nobody can find their way around. This lesson explains the project/app distinction, how settings actually work, and how to structure Nidaan so it scales.

Project versus app — the distinction that confuses everyone first

Django has two levels, and the names are unfortunately similar:

  • A project is the whole thing — one deployable website. You have exactly one. It is the config package (settings, root URLs) plus everything around it. Nidaan is a project.
  • An app is a self-contained module within the project that does one job. A project is made of several apps. You create them as you go.

The rule of thumb: an app should do one thing, and be conceivably reusable. Django's own built-ins are apps — django.contrib.auth is the authentication app, django.contrib.admin is the admin app. For Nidaan, natural apps are patients (patient records), appointments (scheduling), reports (diagnostic test results), and perhaps billing. Each owns its models, views, URLs and templates for its slice of the domain.

Create one with:

python manage.py startapp appointments

This scaffolds an appointments/ directory with the standard files — and creating apps by feature, not by technical layer, is the decision that matters, which we come to below.

What is in an app

startapp appointments generates:

appointments/
  __init__.py
  admin.py         ← register models with the admin here
  apps.py          ← the app's configuration class
  models.py        ← this app's database models
  views.py         ← this app's views
  migrations/      ← this app's schema-change history
  tests.py         ← this app's tests

You typically add an app-level urls.py yourself (as we did for patients). Notice every file is this app's — the app is a coherent bundle of one feature's data, logic, URLs and tests. That locality is the point: to understand appointments, you look in one directory, not scattered across the project.

Registering an app: INSTALLED_APPS

An app does nothing until the project knows about it. You register it in config/settings.py:

# config/settings.py
INSTALLED_APPS = [
    "django.contrib.admin",       # the admin site
    "django.contrib.auth",        # authentication
    "django.contrib.contenttypes",
    "django.contrib.sessions",    # sessions
    "django.contrib.messages",    # the messages framework
    "django.contrib.staticfiles", # static file handling
    # your apps:
    "patients",
    "appointments",
]

The built-in django.contrib.* apps are why you got auth, sessions and the admin for free — they are apps, registered by default. Your app must appear in INSTALLED_APPS or Django ignores it — its models will not get tables, its admin registrations will not show, its templates will not be found. "Why isn't my model migrating?" is, nine times out of ten, an app missing from this list.

Settings: it is just a Python module

config/settings.py is not a special format — it is a plain Python module of module-level variables that Django reads. That is powerful (you can compute values, import, branch on environment) and a responsibility (a syntax error here breaks everything). The settings you meet first:

  • DEBUG — True in development (detailed error pages, auto-served static files), and must be False in production (detailed errors leak your code and configuration to attackers). This is the single most important setting to get right for a live site.
  • ALLOWED_HOSTS — the domain names your site is allowed to serve. Empty is fine with DEBUG=True; in production it must list your real domains, or Django refuses the request (a deliberate protection).
  • SECRET_KEY — a random string Django uses for cryptographic signing (sessions, password resets, CSRF). It must be secret and unique; a leaked key is a serious breach. It belongs in an environment variable, never in the committed code — the deployment module returns to this.
  • DATABASES — the database connection. SQLite by default in development; PostgreSQL in production.
  • INSTALLED_APPS, MIDDLEWARE, TEMPLATES — the wiring of apps, request layers and the template engine.

The generated settings.py ships with DEBUG=True and an insecure SECRET_KEY right in the file, clearly marked. That is fine for the first day and dangerous for production — managing settings safely across environments is important enough that it has its own lesson later.

Structure apps by feature, not by layer — the decision that ages well

The most consequential structural choice, and the one beginners most often get backwards: divide apps by feature (a slice of the domain), not by technical layer.

  • Wrong (by layer): a models app holding all models, a views app holding all views, a templates app. This feels tidy for a week and becomes unnavigable fast — to change appointments you touch three apps, and no app means anything on its own.
  • Right (by feature): a patients app with patients' models, views, URLs and templates together; an appointments app with appointments'; a reports app with reports'. To change a feature, you work in one directory. Each app is understandable, testable and, in principle, reusable in isolation.

This is the same locality principle as the app layout itself, applied one level up. A new engineer joining Nidaan can be told "billing lives in the billing app" and find everything about billing in one place — which is exactly what you want a codebase to allow, and exactly what "by layer" destroys.

Do not over-fragment either: a very small project can start as one or two apps and split later. The goal is apps that each represent a real, coherent piece of the domain — not one giant app, and not fifty tiny ones.

Check your work

Project versus app. A project is the whole deployable site (one, the config package); an app is a self-contained feature module within it (many). Nidaan is the project; patients/appointments are apps.

What an app contains. Its own models.py, views.py, admin.py, migrations/, tests.py (and usually a urls.py you add) — one feature's data, logic and tests bundled together.

What INSTALLED_APPS does. Registers apps with the project; an unregistered app is ignored (no tables, no admin, no templates) — the usual cause of "my model won't migrate".

Why the django.contrib.* apps matter. Auth, sessions, admin and more are themselves apps, registered by default — that is why they come free.

The settings that matter first. DEBUG (False in production, non-negotiable), ALLOWED_HOSTS, SECRET_KEY (secret, from the environment), DATABASES, and the app/middleware/template wiring.

By feature, not by layer. Divide apps into domain slices (patients, appointments) so each feature lives in one directory — not into models/views/templates apps, which scatter every change.

Practice

  1. In the nidaan project, create an appointments app and register it in INSTALLED_APPS. Run python manage.py check.
  2. Create an app but forget to register it; try to use it and observe what fails. Register it and confirm the fix — so the role of INSTALLED_APPS is concrete.
  3. Open config/settings.py and find DEBUG, ALLOWED_HOSTS, SECRET_KEY, INSTALLED_APPS. Read the comment above SECRET_KEY.
  4. Set DEBUG = False with ALLOWED_HOSTS = [], restart the server, load a page, and read the error. Restore DEBUG = True. You have seen why the pairing matters.
  5. Sketch Nidaan as apps: list four to six apps and, for each, one sentence on what it owns. Justify why you did not put it all in one app.
  6. Look at Django's django.contrib packages and note three that are apps you already benefit from.

Official documentation

Next: defining models and fields — the data layer.

Stuck on this lesson?

Being stuck is part of it — but being stuck alone for three days is not. Our internship programme pairs this curriculum with code review and one-to-one help from working developers, and it is free.

About the internship