Getting Started with Django: Build Your First Web App
A step-by-step interactive tutorial for complete beginners
1. Introduction to Django
What is Django?
Django is a high-level Python web framework that encourages rapid development and clean, pragmatic design. It takes care of much of the hassle of web development, so you can focus on writing your app without needing to reinvent the wheel.
Django follows the "batteries-included" philosophy and provides almost everything developers might want to do "out of the box". Because everything you need is part of the one "product", it all works seamlessly together, follows consistent design principles, and has extensive and up-to-date documentation.
Why Django?
- Ridiculously fast - Django was designed to help developers take applications from concept to completion as quickly as possible.
- Reassuringly secure - Django takes security seriously and helps developers avoid many common security mistakes.
- Exceedingly scalable - Some of the busiest sites on the web use Django to handle their heaviest traffic demands.
- Incredibly versatile - Companies, organizations, and governments have used Django to build all sorts of things—from content management systems to social networks to scientific computing platforms.
Django's Architecture
Django follows the Model-View-Template (MVT) architectural pattern, a variant of the classic Model-View-Controller (MVC) pattern:
Data structure & database
Business logic & data processing
Presentation & display logic
Routing & mapping
Quick Quiz: Django Basics
Test your understanding of Django's basics:
Which architectural pattern does Django follow?
2. Setting Up Your Environment
Before we can start building our Django application, we need to set up our development environment. This includes installing Python, creating a virtual environment, and installing Django.
Install Python
Django is a Python framework, so we need to install Python first. Django 4.0+ requires Python 3.8 or higher.
- Download Python from python.org/downloads
- During installation, make sure to check "Add Python to PATH"
Verify your installation by opening a terminal or command prompt and typing:
python --version
You should see something like Python 3.10.0
(your version may differ).
Create a Virtual Environment
Virtual environments allow you to have isolated Python environments for different projects, so their dependencies don't interfere with each other.
Open a terminal and navigate to where you want to create your project:
cd path/to/your/projects/folder
Create a new directory for your project:
mkdir mynotes
cd mynotes
Create a virtual environment:
python -m venv venv
python3 -m venv venv
Activate the virtual environment:
venv\Scripts\activate
source venv/bin/activate
You'll know your virtual environment is active when you see (venv)
at the beginning of your command prompt.
Install Django
With your virtual environment activated, install Django:
pip install django
Verify the installation:
python -m django --version
You should see the Django version number, like 4.2.1
(your version may differ).
Quick Quiz: Virtual Environments
Why should you use a virtual environment for your Django projects?
3. Creating a Django Project and App
In Django, a project is the entire web application, while an app is a module within the project that handles a specific functionality. A project can contain multiple apps.
Create a Django Project
With your virtual environment activated, run:
django-admin startproject mynotes .
Note the dot .
at the end, which tells Django to create the project in the current directory instead of creating a new directory.
Create a Django App
Now, let's create an app within our project:
python manage.py startapp notes
Register the App
Open the mynotes/settings.py
file and add your app to the INSTALLED_APPS
list:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'notes', # Add this line
]
Run Initial Migrations
Django uses migrations to keep track of changes to your models and update the database schema accordingly. Let's run the initial migrations:
python manage.py migrate
This applies the built-in migrations for the default apps listed in INSTALLED_APPS
.
Start the Development Server
Let's verify everything is working by starting the development server:
python manage.py runserver
Open a web browser and navigate to http://127.0.0.1:8000/. You should see the Django welcome page.
Press CTRL+C
in the terminal to stop the server when you're done.
Quick Quiz: Projects vs Apps
What is the relationship between Django projects and apps?
4. Understanding Django Folder Structure
Let's explore the directory structure Django has created for us and understand what each file does.
Key Files and Their Purposes
- manage.py: A command-line utility that lets you interact with your Django project. You'll use it to run the server, create migrations, apply migrations, and more.
- settings.py: Contains all the project settings, including database configuration, installed apps, middleware, and more.
- urls.py: A "table of contents" for your Django site, mapping URLs to views.
- models.py: Defines your data models, which Django converts to database tables.
- views.py: Contains view functions or classes that process requests and return responses.
- admin.py: Configuration for the built-in Django admin interface.
mynotes/
). This can be confusing at first. The outer mynotes/
is your project container, while the inner mynotes/
is a Python package containing your project's settings.
Quick Quiz: Django Files
Which file defines the data models that Django will convert to database tables?
5. Creating a Model and Database Migration
Models are the single, definitive source of information about your data. They contain the essential fields and behaviors of the data you're storing. In our note-taking app, we need a model to represent a note.
Define the Note Model
Open notes/models.py
and add the following code:
from django.db import models
from django.utils import timezone
class Note(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
created_at = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.title
This code:
- Creates a
Note
model with title, content, and created_at fields - Sets the
created_at
field to default to the current date and time - Defines a
__str__
method that returns the title when the object is converted to a string
Create and Apply Migrations
Migrations are Django's way of propagating changes you make to your models into your database schema. First, we create a migration file:
python manage.py makemigrations notes
This creates a migration file in the notes/migrations/
directory. Now, apply the migration to update the database:
python manage.py migrate
Register the Model with Admin
Django comes with a built-in admin interface that we can use to manage our data. Let's register our model with it.
Open notes/admin.py
and add the following code:
from django.contrib import admin
from .models import Note
admin.site.register(Note)
Create a Superuser
To access the admin interface, we need to create a superuser account:
python manage.py createsuperuser
Follow the prompts to create a username, email, and password.
Explore the Admin Interface
Start the development server:
python manage.py runserver
Visit http://127.0.0.1:8000/admin/ and log in with the superuser credentials you just created.
You should see the Django admin interface with your Notes model listed. Try adding a few notes to test it out.
Model-Database Relationship
Define Note model
Create migration files
Apply to database
Tables created/updated
Quick Quiz: Django Models
After changing a model, what two commands do you need to run to update the database?
6. Creating Views, Templates, and URLs
Now that we have our model set up, we need to create views, templates, and URLs to display our notes to users.
Create Templates Directory
First, create a directory structure for your templates:
mkdir -p notes/templates/notes
Django looks for templates in a "templates" directory within each app. We add an extra "notes" directory inside the templates directory to namespace our templates and avoid conflicts with other apps.
Create Base Template
Create a base template at notes/templates/notes/base.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}My Notes App{% endblock %}</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container">
<a class="navbar-brand" href="{% url 'home' %}">My Notes</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="{% url 'home' %}">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'note_list' %}">All Notes</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'note_new' %}">New Note</a>
</li>
</ul>
</div>
</div>
</nav>
<div class="container mt-4">
{% block content %}
{% endblock %}
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
This base template includes Bootstrap for styling and defines blocks that child templates will fill in.
Create Home Template
Create notes/templates/notes/home.html
:
{% extends 'notes/base.html' %}
{% block title %}Home | My Notes App{% endblock %}
{% block content %}
<div class="jumbotron">
<h1 class="display-4">Welcome to My Notes App</h1>
<p class="lead">A simple Django application to manage your notes.</p>
<hr class="my-4">
<p>Get started by creating a new note or viewing your existing notes.</p>
<a class="btn btn-primary btn-lg" href="{% url 'note_new' %}" role="button">Create New Note</a>
<a class="btn btn-secondary btn-lg" href="{% url 'note_list' %}" role="button">View All Notes</a>
</div>
{% endblock %}
Create Note List Template
Create notes/templates/notes/note_list.html
:
{% extends 'notes/base.html' %}
{% block title %}All Notes | My Notes App{% endblock %}
{% block content %}
<h1>All Notes</h1>
{% if notes %}
<div class="row">
{% for note in notes %}
<div class="col-md-4 mb-4">
<div class="card">
<div class="card-body">
<h5 class="card-title">{{ note.title }}</h5>
<p class="card-text">{{ note.content|truncatechars:100 }}</p>
<p class="text-muted">Created: {{ note.created_at|date:"F j, Y" }}</p>
</div>
</div>
</div>
{% endfor %}
</div>
{% else %}
<p>No notes yet. <a href="{% url 'note_new' %}">Create one</a>!</p>
{% endif %}
{% endblock %}
Create Views
Open notes/views.py
and add the following code:
from django.shortcuts import render
from .models import Note
def home(request):
return render(request, 'notes/home.html')
def note_list(request):
notes = Note.objects.all().order_by('-created_at')
return render(request, 'notes/note_list.html', {'notes': notes})
This creates two views: one for the home page and one for the note list page.
Create App URLs
Create a new file notes/urls.py
:
from django.urls import path
from . import views
urlpatterns = [
path('', views.home, name='home'),
path('notes/', views.note_list, name='note_list'),
]
Include App URLs in Project URLs
Open mynotes/urls.py
and modify it:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('notes.urls')),
]
This includes our app's URLs in the project's URL configuration.
Test Your Views
Start the development server:
python manage.py runserver
Visit http://127.0.0.1:8000/ to see the home page and http://127.0.0.1:8000/notes/ to see the note list.
Note: The "New Note" link won't work yet because we haven't created the view for it. We'll do that in the next section.
Django's MVT Flow
User requests a URL
Processes the request
Interacts with database
Renders HTML
Returns to user
Quick Quiz: Django Templates
What template tag is used to inherit from a base template?
7. Adding Forms to Create New Notes
Now, let's create a form to allow users to add new notes to our application.
Create a Form
Create a new file notes/forms.py
:
from django import forms
from .models import Note
class NoteForm(forms.ModelForm):
class Meta:
model = Note
fields = ['title', 'content']
widgets = {
'title': forms.TextInput(attrs={'class': 'form-control'}),
'content': forms.Textarea(attrs={'class': 'form-control', 'rows': 5}),
}
This creates a form based on our Note model with fields for title and content. We also add Bootstrap classes to style the form.
Create a Template for the Form
Create notes/templates/notes/note_form.html
:
{% extends 'notes/base.html' %}
{% block title %}New Note | My Notes App{% endblock %}
{% block content %}
<h1>{% if form.instance.id %}Edit Note{% else %}New Note{% endif %}</h1>
<form method="post">
{% csrf_token %}
<div class="mb-3">
<label for="{{ form.title.id_for_label }}" class="form-label">Title</label>
{{ form.title }}
{% if form.title.errors %}
<div class="text-danger">{{ form.title.errors }}</div>
{% endif %}
</div>
<div class="mb-3">
<label for="{{ form.content.id_for_label }}" class="form-label">Content</label>
{{ form.content }}
{% if form.content.errors %}
<div class="text-danger">{{ form.content.errors }}</div>
{% endif %}
</div>
<button type="submit" class="btn btn-primary">Save</button>
<a href="{% url 'note_list' %}" class="btn btn-secondary">Cancel</a>
</form>
{% endblock %}
Add View for Creating Notes
Update notes/views.py
to add a view for creating notes:
from django.shortcuts import render, redirect
from .models import Note
from .forms import NoteForm
def home(request):
return render(request, 'notes/home.html')
def note_list(request):
notes = Note.objects.all().order_by('-created_at')
return render(request, 'notes/note_list.html', {'notes': notes})
def note_new(request):
if request.method == "POST":
form = NoteForm(request.POST)
if form.is_valid():
form.save()
return redirect('note_list')
else:
form = NoteForm()
return render(request, 'notes/note_form.html', {'form': form})
This adds a new view that:
- Shows an empty form when the page is first loaded (GET request)
- Processes the form data when it's submitted (POST request)
- Redirects to the note list page after successfully saving the note
Update URLs
Update notes/urls.py
to add the URL for creating notes:
from django.urls import path
from . import views
urlpatterns = [
path('', views.home, name='home'),
path('notes/', views.note_list, name='note_list'),
path('notes/new/', views.note_new, name='note_new'),
]
Test the Form
Start the development server:
python manage.py runserver
Visit http://127.0.0.1:8000/notes/new/ to see the form for creating a new note.
Try creating a new note and verify that it appears in the note list.
{% csrf_token %}
in our form template is important for security. It adds a Cross-Site Request Forgery token that helps protect against certain types of attacks.
Quick Quiz: Django Forms
When creating a form based on a model, which class should you inherit from?
8. Styling with Bootstrap
We've already included Bootstrap in our base template, but let's enhance the styling a bit more to make our app look more polished.
Update the Base Template
Let's add some custom CSS to our base template. Update notes/templates/notes/base.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}My Notes App{% endblock %}</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
body {
padding-bottom: 2rem;
background-color: #f8f9fa;
}
.navbar {
margin-bottom: 2rem;
box-shadow: 0 2px 4px rgba(0,0,0,.1);
}
.card {
box-shadow: 0 2px 5px rgba(0,0,0,.1);
transition: all 0.3s ease;
}
.card:hover {
transform: translateY(-5px);
box-shadow: 0 5px 15px rgba(0,0,0,.15);
}
.jumbotron {
background-color: #ffffff;
border-radius: 0.5rem;
padding: 2rem;
box-shadow: 0 2px 5px rgba(0,0,0,.1);
}
.footer {
margin-top: 3rem;
padding-top: 1.5rem;
padding-bottom: 1.5rem;
background-color: #343a40;
color: #ffffff;
}
</style>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container">
<a class="navbar-brand" href="{% url 'home' %}">
<i class="fas fa-sticky-note me-2"></i>My Notes
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="{% url 'home' %}">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'note_list' %}">All Notes</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'note_new' %}">New Note</a>
</li>
</ul>
</div>
</div>
</nav>
<div class="container mt-4">
{% block content %}
{% endblock %}
</div>
<footer class="footer mt-auto">
<div class="container text-center">
<p>My Notes App - Built with Django</p>
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.15.4/js/all.min.js"></script>
</body>
</html>
Update the Note List Template
Enhance notes/templates/notes/note_list.html
:
{% extends 'notes/base.html' %}
{% block title %}All Notes | My Notes App{% endblock %}
{% block content %}
<div class="d-flex justify-content-between align-items-center mb-4">
<h1>All Notes</h1>
<a href="{% url 'note_new' %}" class="btn btn-primary">
<i class="fas fa-plus me-2"></i>New Note
</a>
</div>
{% if notes %}
<div class="row">
{% for note in notes %}
<div class="col-md-4 mb-4">
<div class="card h-100">
<div class="card-header bg-light d-flex justify-content-between align-items-center">
<span class="text-muted">{{ note.created_at|date:"F j, Y" }}</span>
</div>
<div class="card-body">
<h5 class="card-title">{{ note.title }}</h5>
<p class="card-text">{{ note.content|truncatechars:100 }}</p>
</div>
</div>
</div>
{% endfor %}
</div>
{% else %}
<div class="alert alert-info">
<i class="fas fa-info-circle me-2"></i>No notes yet. <a href="{% url 'note_new' %}" class="alert-link">Create one</a>!
</div>
{% endif %}
{% endblock %}
Update the Home Template
Enhance notes/templates/notes/home.html
:
{% extends 'notes/base.html' %}
{% block title %}Home | My Notes App{% endblock %}
{% block content %}
<div class="jumbotron text-center">
<h1 class="display-4 mb-4">Welcome to My Notes App</h1>
<p class="lead">A simple Django application to manage your notes</p>
<hr class="my-4">
<div class="row mt-5 justify-content-center">
<div class="col-md-4 mb-4">
<div class="card text-center h-100">
<div class="card-body">
<i class="fas fa-plus-circle fa-4x mb-3 text-success"></i>
<h3 class="card-title">Create</h3>
<p class="card-text">Create new notes with titles and content</p>
<a href="{% url 'note_new' %}" class="btn btn-success">New Note</a>
</div>
</div>
</div>
<div class="col-md-4 mb-4">
<div class="card text-center h-100">
<div class="card-body">
<i class="fas fa-list-ul fa-4x mb-3 text-primary"></i>
<h3 class="card-title">View</h3>
<p class="card-text">View all your saved notes in one place</p>
<a href="{% url 'note_list' %}" class="btn btn-primary">View Notes</a>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
Update the Form Template
Enhance notes/templates/notes/note_form.html
:
{% extends 'notes/base.html' %}
{% block title %}New Note | My Notes App{% endblock %}
{% block content %}
<div class="card">
<div class="card-header">
<h2>{% if form.instance.id %}Edit Note{% else %}New Note{% endif %}</h2>
</div>
<div class="card-body">
<form method="post">
{% csrf_token %}
<div class="mb-3">
<label for="{{ form.title.id_for_label }}" class="form-label">Title</label>
{{ form.title }}
{% if form.title.errors %}
<div class="text-danger">{{ form.title.errors }}</div>
{% endif %}
</div>
<div class="mb-3">
<label for="{{ form.content.id_for_label }}" class="form-label">Content</label>
{{ form.content }}
{% if form.content.errors %}
<div class="text-danger">{{ form.content.errors }}</div>
{% endif %}
</div>
<div class="d-flex mt-4">
<button type="submit" class="btn btn-primary me-2">
<i class="fas fa-save me-2"></i>Save
</button>
<a href="{% url 'note_list' %}" class="btn btn-secondary">
<i class="fas fa-times me-2"></i>Cancel
</a>
</div>
</form>
</div>
</div>
{% endblock %}
Test the Styled App
Start the development server:
python manage.py runserver
Visit http://127.0.0.1:8000/ to see your beautifully styled app.
<style>
section of the base template or in a separate CSS file.
9. Running and Testing the App
Let's make sure our application is working correctly and test all the features we've implemented.
Run the Development Server
Start the development server:
python manage.py runserver
The server will start at http://127.0.0.1:8000/
Test the Home Page
Visit the home page and verify that it displays correctly with links to create and view notes.
Ensure that the "New Note" and "View Notes" buttons work correctly.
Test Creating a Note
Click on "New Note" and create a note with a title and content.
Submit the form and verify that you are redirected to the note list page and that your new note appears in the list.
Test the Note List
Visit the note list page and verify that all your notes are displayed correctly.
Create multiple notes and ensure they all appear in the list.
Test the Navigation
Verify that the navigation links in the header work correctly and take you to the appropriate pages.
Test Form Validation
Try submitting the note form with empty fields to ensure validation works correctly.
Verify that error messages are displayed appropriately.
10. Deployment Options (Overview)
Once you've built and tested your Django application, you might want to deploy it to make it accessible to others. Here's a brief overview of deployment options.
Preparation for Deployment
Before deploying, you need to make some changes to your settings:
# In settings.py
# Set DEBUG to False in production
DEBUG = False
# Set ALLOWED_HOSTS to your domain(s)
ALLOWED_HOSTS = ['yourdomain.com', 'www.yourdomain.com']
# Configure a production database (e.g., PostgreSQL)
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'your_database_name',
'USER': 'your_database_user',
'PASSWORD': 'your_database_password',
'HOST': 'localhost',
'PORT': '',
}
}
# Set a secure SECRET_KEY
SECRET_KEY = 'your-secret-key' # Use environment variables for this in practice
# Configure static files
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATIC_URL = '/static/'
Deployment Platforms
PythonAnywhere
A beginner-friendly platform specifically designed for Python and Django applications.
- Free tier available
- Easy to set up
- Good for beginners
Heroku
A platform as a service (PaaS) that enables developers to build, run, and operate applications.
- Free tier available (with limitations)
- Good scaling options
- Extensive documentation
DigitalOcean
Cloud infrastructure provider that offers Droplets (virtual machines) and App Platform.
- More control over your server
- Requires more setup knowledge
- Affordable pricing
AWS, Google Cloud, Azure
Major cloud platforms offering various services for deploying web applications.
- Extensive feature sets
- Highly scalable
- Steeper learning curve
Various options available
General Deployment Steps
- Set up a production database (e.g., PostgreSQL)
- Configure your settings for production
- Collect static files:
python manage.py collectstatic
- Choose and set up a web server (e.g., Gunicorn, uWSGI)
- Configure a reverse proxy (e.g., Nginx, Apache)
- Set up HTTPS using a certificate (e.g., Let's Encrypt)
- Deploy your code to the server
- Start your application
11. Final Project Summary and Checklist
What We've Built
Congratulations! You've successfully built a simple Django web application that allows users to:
- View a styled home page with links to create and view notes
- Create new notes with a title and content
- View a list of all notes
Along the way, you've learned:
- How to set up a Django development environment
- How to create a Django project and app
- How to define models and work with databases
- How to create views, templates, and URLs
- How to handle forms and user input
- How to style your application with Bootstrap
- How to test your application
- An overview of deployment options
Project Checklist
Use this checklist to make sure you've completed all the necessary steps:
Next Steps
You've built a basic Django application, but there are many ways you can expand it:
Add User Authentication
Allow users to register, log in, and have their own private notes.
Add CRUD Operations
Implement functionality to update and delete notes.
Add Categories/Tags
Allow users to categorize notes and filter by category.
Add Rich Text Editing
Implement a rich text editor for note content.
Add Search Functionality
Allow users to search through their notes.
Add API
Create a REST API for your notes app using Django REST framework.
Resources for Further Learning
- Django Official Documentation - Comprehensive reference and tutorials
- Django Download Page - Get the latest version of Django
- Python Documentation - Python language reference
- GeeksforGeeks Django Tutorial - Additional tutorials and examples
- Bootstrap Documentation - Learn more about styling with Bootstrap
Congratulations!
You've completed the Django tutorial and built your first web application!
Continue exploring Django and building more complex applications to enhance your skills.