How to Create a Django Project and App

Blog / Django · January 11, 2023 · Updated June 10, 2026 · 8 min read
How to Create a Django Project and App

If you are new to Django, the first thing to get straight is the difference between a project and an app — it trips up almost every beginner.

  • A Django project is the whole website: its settings, database configuration, and the root URL map. You create it once with django-admin startproject.
  • A Django app is a single, self-contained feature inside that project — a blog, a payments module, user accounts. You create as many as you need with python manage.py startapp.

So the rule is simple: one project holds many apps. A project without apps does nothing useful; an app only runs when it is plugged into a project.

This guide walks through both, end to end, on modern Django 5.x and Python 3.11+ — from a virtual environment to a working page you can open in your browser. If you are still deciding on a stack, see our take on Python web development first.

Prerequisites

You need Python 3.11 or newer. Django 5.x requires Python 3.10+, and Django 5.2 LTS officially supports Python 3.10 through 3.13 — so 3.11+ keeps you safely in range. Check what you have:

python --version
# or, on systems where python points to Python 2:
python3 --version
# Expected: Python 3.11.x (or newer)

If the version is older than 3.10, install a current Python from python.org (or via pyenv/Homebrew) before continuing. You do not install Django globally — that comes next, inside an isolated environment.

Step 1: Create and activate a virtual environment

Always start a Django project in a virtual environment (venv). A venv is a private, per-project folder of Python packages, so the Django version and dependencies for this project never collide with another project or your system Python. This is the single biggest habit that keeps Python projects reproducible.

# macOS / Linux
python3 -m venv venv
source venv/bin/activate

# Windows (PowerShell)
python -m venv venv
venv\Scripts\Activate.ps1

# Your shell prompt now shows (venv)

With the venv active, install Django and pin your dependencies to a requirements.txt so anyone can recreate the exact environment later:

python -m pip install --upgrade pip
python -m pip install Django
python -m django --version      # e.g. 5.2.x
pip freeze > requirements.txt

Step 2: Create the Django project

Now generate the project. Note the trailing dot at the end of the command:

django-admin startproject myproject .

Why the trailing dot? Without it, Django creates an extra wrapper directory (myproject/myproject/...), which confuses beginners. The . tells Django to put manage.py in your current folder and the settings package one level down — a flatter, cleaner layout that most teams prefer.

Here is what was generated:

myproject_root/
|-- manage.py            # your command-line entry point
|-- requirements.txt
|-- venv/
`-- myproject/           # the project's Python package
    |-- __init__.py      # marks this folder as a package
    |-- settings.py      # all configuration (apps, DB, etc.)
    |-- urls.py          # the root URL map
    |-- asgi.py          # entry point for async servers
    `-- wsgi.py          # entry point for traditional WSGI servers

The files you will touch most are:

  • manage.py — a thin wrapper around django-admin that you run for every project task (runserver, migrate, startapp, and more).
  • settings.py — your project's control panel: installed apps, database, templates, static files, time zone.
  • urls.py — the root URL configuration that routes requests into your apps.
  • asgi.py / wsgi.py — server entry points; ASGI for async/WebSockets, WSGI for classic deployments. You rarely edit these early on.

Step 3: Run the development server

Apply Django's built-in migrations (these set up the default auth, sessions, and admin tables in a SQLite database), then start the server:

python manage.py migrate
python manage.py runserver

Open http://127.0.0.1:8000/ and you will see Django's welcome page with a small rocket — confirmation that your project runs. SQLite is built into Python, so there is nothing else to install to get started. Stop the server any time with Ctrl+C.

Step 4: Create your first app

A fresh project has no features yet. Create an app — we will build a small blog. Make sure you are in the same folder as manage.py:

python manage.py startapp blog

Django scaffolds the app folder:

blog/
|-- __init__.py
|-- admin.py         # register models for the admin site
|-- apps.py          # the app's configuration class
|-- models.py        # your database tables, as Python classes
|-- tests.py         # write tests here
|-- views.py         # request -> response logic
`-- migrations/      # generated DB schema changes
    `-- __init__.py

A few things to notice: startapp does not create a urls.py or a templates/ folder — you add those yourself when the app needs routes and pages (we do both below). The apps.py file holds an AppConfig class (here, BlogConfig) that you reference when registering the app.

Step 5: Register the app in INSTALLED_APPS

This is the number-one beginner gotcha: creating an app is not enough — Django ignores it until you list it in INSTALLED_APPS. If your models never appear, migrations do nothing, or templates cannot be found, this is almost always why. Add your app using its AppConfig path:

# myproject/settings.py
INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "blog.apps.BlogConfig",   # <-- your new app
]

Step 6: Build a complete vertical slice

Let's wire one feature all the way through: model -> migration -> admin -> view -> URL -> template. Keep it minimal but complete, so you finish with a real working page.

Define a model

A model is a Python class that maps to a database table. Edit blog/models.py:

# blog/models.py
from django.db import models


class Post(models.Model):
    title = models.CharField(max_length=200)
    body = models.TextField()
    published = models.DateField(auto_now_add=True)

    def __str__(self):
        return self.title

Create and run the migration

makemigrations turns model changes into a migration file; migrate applies it to the database:

python manage.py makemigrations blog
python manage.py migrate

Register the model in the admin and create a superuser

Expose the model in Django's built-in admin so you can add data through a UI. Edit blog/admin.py:

# blog/admin.py
from django.contrib import admin

from .models import Post


@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
    list_display = ("title", "published")
python manage.py createsuperuser

Run python manage.py runserver again, log in at http://127.0.0.1:8000/admin/, and add a couple of posts.

Write a view

A view takes a request and returns a response. Edit blog/views.py:

# blog/views.py
from django.shortcuts import render

from .models import Post


def post_list(request):
    posts = Post.objects.order_by("-published")
    return render(request, "blog/post_list.html", {"posts": posts})

Map URLs

Create blog/urls.py (it does not exist yet) to route requests to the view:

# blog/urls.py
from django.urls import path

from . import views

app_name = "blog"

urlpatterns = [
    path("", views.post_list, name="post_list"),
]

Then plug the app's URLs into the project's root URLconf with include():

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

urlpatterns = [
    path("admin/", admin.site.urls),
    path("", include("blog.urls")),
]

Add a template

With the default APP_DIRS template setting, Django looks for templates inside each app's templates/ folder. Create the file blog/templates/blog/post_list.html (the nested blog/ folder namespaces the template):

<!-- blog/templates/blog/post_list.html -->
<h1>Latest posts</h1>
<ul>
  {% for post in posts %}
    <li>{{ post.title }} - {{ post.published }}</li>
  {% empty %}
    <li>No posts yet.</li>
  {% endfor %}
</ul>

Restart the server and open http://127.0.0.1:8000/ — your posts render on the page. That is a full Django feature, front to back.

Project vs app: quick reference

Project App
What it is The whole website and its configuration A single feature module
Created by django-admin startproject myproject . python manage.py startapp blog
How many One per site Many per project
Holds Settings, root URLconf, WSGI/ASGI Models, views, templates, migrations
Examples myproject, shop_site blog, accounts, payments

Project layout best practices

A few conventions pay off as the project grows:

  • Templates and static files live inside each app (blog/templates/blog/, blog/static/blog/) so apps stay portable. Use project-level folders only for site-wide assets.
  • Split settings once configuration grows — keep base.py, development.py, and production.py instead of one large settings.py, and read secrets from environment variables, never from committed code.
  • Keep apps small and focused. One app per cohesive feature is easier to test and reuse than one giant app.
  • Add a .gitignore so you never commit the virtual environment, caches, the SQLite file, or secrets:
# .gitignore
venv/
__pycache__/
*.pyc
db.sqlite3
.env
/media/

Where to go next

You now have a Django project, an app, a model, the admin, a view, a URL, and a template — the core loop of every Django site. From here:

MicroPyramid has built and maintained Django applications for 12+ years across 50+ delivered projects, from MVPs to high-traffic platforms. If you want an experienced team to architect or accelerate your Django build, explore our Django development services.

Frequently Asked Questions

Django project vs app: what is the difference?

A project is the entire website — its settings, database config, and root URL map — created once with django-admin startproject. An app is a single feature module (a blog, accounts, payments) created with python manage.py startapp. One project contains many apps, and an app only runs once it is added to the project's INSTALLED_APPS.

Do I really need a virtual environment?

Yes. A virtual environment isolates this project's Django version and dependencies from your system Python and other projects, so upgrades in one place never break another. Combined with a pinned requirements.txt, it makes your setup reproducible on any machine or server. Skipping it is the most common source of "works on my machine" problems.

Why is my app not working or my template not found?

The usual cause is that the app is not registered in INSTALLED_APPS. Until you add it (for example "blog.apps.BlogConfig") in settings.py, Django ignores its models, migrations, and templates. Also confirm templates live at yourapp/templates/yourapp/ so the default APP_DIRS loader can find them.

What does the trailing dot in startproject do?

django-admin startproject myproject . places manage.py in your current directory and the settings package one level below it. Without the dot, Django adds an extra wrapper folder (myproject/myproject/), giving you a deeper, more confusing layout. The dot produces the flatter structure most teams prefer.

Which Python version do I need for Django 5?

Django 5.x requires Python 3.10 or newer. Django 5.2 LTS supports Python 3.10 to 3.13. Using Python 3.11+ is a safe, well-supported choice. Check your version with python --version before installing Django.

What is the difference between startproject and startapp?

startproject scaffolds the overall site once (settings, root URLs, WSGI/ASGI). startapp scaffolds an individual feature inside that project (models, views, admin, migrations) and can be run many times. You run startproject first, then create one or more apps with startapp.

Share this article