A step-by-step interactive tutorial for complete beginners
Beginner Estimated time: 90 minutesDjango 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.
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
Test your understanding of Django's basics:
Which architectural pattern does Django follow?
What we'll build: In this tutorial, we'll create a simple note-taking application where users can create, view, and list notes. Each note will have a title and body content.
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.
Django is a Python framework, so we need to install Python first. Django 4.0+ requires Python 3.8 or higher.
Verify your installation by opening a terminal or command prompt and typing:
python --versionYou should see something like Python 3.10.0 (your version may differ).
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/folderCreate a new directory for your project:
mkdir mynotes
cd mynotesCreate a virtual environment:
python -m venv venvpython3 -m venv venvActivate the virtual environment:
venv\Scripts\activatesource venv/bin/activateYou'll know your virtual environment is active when you see (venv) at the beginning of your command prompt.
With your virtual environment activated, install Django:
pip install djangoVerify the installation:
python -m django --versionYou should see the Django version number, like 4.2.1 (your version may differ).
Pro Tip: Always activate your virtual environment before working on your project. If you close your terminal and come back later, you'll need to activate it again.
Why should you use a virtual environment for your Django projects?
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.
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.
Now, let's create an app within our project:
python manage.py startapp notes
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
]
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.
Let's verify everything is working by starting the development server:
python manage.py runserverOpen 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.
Note: Never use the development server in a production environment. It's not designed to be particularly secure, stable, or efficient.
What is the relationship between Django projects and apps?
Let's explore the directory structure Django has created for us and understand what each file does.
Project vs. App Directory: Notice that Django created a directory with the same name as your project (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.
Which file defines the data models that Django will convert to database tables?
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.
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:
Note model with title, content, and created_at fieldscreated_at field to default to the current date and time__str__ method that returns the title when the object is converted to a stringMigrations 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 migrateDjango 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)
To access the admin interface, we need to create a superuser account:
python manage.py createsuperuserFollow the prompts to create a username, email, and password.
Start the development server:
python manage.py runserverVisit 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.
Define Note model
Create migration files
Apply to database
Tables created/updated
After changing a model, what two commands do you need to run to update the database?
Now that we have our model set up, we need to create views, templates, and URLs to display our notes to users.
First, create a directory structure for your templates:
mkdir -p notes/templates/notesDjango 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 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 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 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 %}
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 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'),
]
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.
Start the development server:
python manage.py runserverVisit 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.
User requests a URL
Processes the request
Interacts with database
Renders HTML
Returns to user
What template tag is used to inherit from a base template?
Now, let's create a form to allow users to add new notes to our application.
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 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 %}
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:
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'),
]
Start the development server:
python manage.py runserverVisit 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.
Django Forms Security: The {% 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.
When creating a form based on a model, which class should you inherit from?
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.
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>
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 %}
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 %}
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 %}
Start the development server:
python manage.py runserverVisit http://127.0.0.1:8000/ to see your beautifully styled app.
Styling Tip: Bootstrap provides many components and utilities out of the box, but you can always add custom CSS to tailor the appearance to your specific needs. Add your custom styles in the <style> section of the base template or in a separate CSS file.
Let's make sure our application is working correctly and test all the features we've implemented.
Start the development server:
python manage.py runserverThe server will start at http://127.0.0.1:8000/
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.
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.
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.
Verify that the navigation links in the header work correctly and take you to the appropriate pages.
Try submitting the note form with empty fields to ensure validation works correctly.
Verify that error messages are displayed appropriately.
Django Admin: Don't forget that you can also use the admin interface at http://127.0.0.1:8000/admin/ to manage your notes. Log in with the superuser credentials you created earlier.
Testing in Different Browsers: It's a good practice to test your application in different browsers to ensure compatibility. Try opening your app in Chrome, Firefox, Safari, or Edge to verify that it looks and works correctly across different browsers.
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.
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/'
A beginner-friendly platform specifically designed for Python and Django applications.
A platform as a service (PaaS) that enables developers to build, run, and operate applications.
Cloud infrastructure provider that offers Droplets (virtual machines) and App Platform.
Major cloud platforms offering various services for deploying web applications.
Various options available
python manage.py collectstaticDeployment Recommendation: For beginners, PythonAnywhere or Heroku are good choices due to their simpler setup processes and good documentation. As you become more experienced, you might want to explore other options that give you more control over your environment.
Congratulations! You've successfully built a simple Django web application that allows users to:
Along the way, you've learned:
Use this checklist to make sure you've completed all the necessary steps:
You've built a basic Django application, but there are many ways you can expand it:
Allow users to register, log in, and have their own private notes.
Implement functionality to update and delete notes.
Allow users to categorize notes and filter by category.
Implement a rich text editor for note content.
Allow users to search through their notes.
Create a REST API for your notes app using Django REST framework.
You've completed the Django tutorial and built your first web application!
Continue exploring Django and building more complex applications to enhance your skills.