Hello! In this lesson, we'll explore some of Django's most powerful features. We'll start with the three types of model relationships that form the backbone of your database schema.
Then, we'll look at the famous Django Admin and how to customize it, how Django handles file uploads from users, how to prepare your app for a global audience with internationalization, and finally, how to break out of the simple request-response cycle with Django Channels for real-time features.
These three fields are the building blocks of your database relationships. They are how you tell Django (and the database) how your models are connected.
Analogy: Let's think about these in terms of people and their possessions.
This defines a one-to-one relationship. It means one record in a table is linked to exactly one record in another table.
This defines a one-to-many relationship. This is the most common relationship.
This defines a many-to-many relationship.
from django.contrib.auth.models import User
from django.db import models
# OneToOneField Example
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.TextField()
# ForeignKey Example
class Post(models.Model):
title = models.CharField(max_length=200)
author = models.ForeignKey(User, on_delete=models.CASCADE)
# ManyToManyField Example
class Topping(models.Model):
name = models.CharField(max_length=50)
class Pizza(models.Model):
name = models.CharField(max_length=50)
toppings = models.ManyToManyField(Topping)
The Django Admin is one of Django's most powerful "batteries-included" features. It's a fully-functional, secure, production-ready website for managing your site's data.
Django automatically builds this interface by reading your `models.py` files.
Analogy: If your `models.py` file is the blueprint for your database, the Django Admin is the instant, furnished control room that Django builds for you, with a dashboard for every table.
By default, your models don't show up in the admin. You have to "register" them in your app's `admin.py` file. This file is also where you customize how they look and behave.
You customize the admin by creating a `ModelAdmin` class.
# my_app/admin.py
from django.contrib import admin
from .models import Post
# This is the "Model Admin" class
class PostAdmin(admin.ModelAdmin):
# 1. Customize the list view
list_display = ('title', 'author', 'created_at')
# 2. Add filters to the sidebar
list_filter = ('author', 'created_at')
# 3. Add a search bar
search_fields = ('title', 'content')
# 4. Group fields in the edit/add form
fieldsets = (
(None, {
'fields': ('title', 'author', 'content')
}),
('Advanced options', {
'classes': ('collapse',),
'fields': ('slug', 'status'),
}),
)
# "Register" your model using your custom class
admin.site.register(Post, PostAdmin)
Django handles file uploads as a two-part process, cleanly separating the model definition from the form handling.
This process is for Media Files (user-uploaded content), not static files.
# 1. my_app/models.py
class Document(models.Model):
title = models.CharField(max_length=100)
# Files will be saved to 'MEDIA_ROOT/documents/2025/11/17/'
uploaded_file = models.FileField(upload_to='documents/%Y/%m/%d/')
# 2. my_app/forms.py
class DocumentForm(forms.ModelForm):
class Meta:
model = Document
fields = ('title', 'uploaded_file')
# 3. my_app/views.py
def upload_file_view(request):
if request.method == 'POST':
# We MUST pass request.FILES to the form
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
form.save() # Django handles the file saving
return redirect('success_url')
else:
form = DocumentForm()
return render(request, 'upload.html', {'form': form})
# 4. upload.html (Template)
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Upload</button>
</form>
These are two related concepts for making your application available to a global audience.
Analogy: Imagine you're building a car.
# 1. Internationalization (i18n) - The Developer's Job
# We mark our strings for translation.
# in my_app/views.py
from django.utils.translation import gettext as _
def my_view(request):
# This string is now marked for translation
output = _("Welcome to our site.")
return HttpResponse(output)
# in my_template.html
{% load i18n %}
<p>{% translate "Hello, world!" %}</p>
# 2. Localization (l10n) - The Translator's Job
# Django generates a .po file for each language:
# in locale/es/LC_MESSAGES/django.po
msgid "Welcome to our site."
msgstr "Bienvenido a nuestro sitio."
# When a user with the 'es' (Spanish) language
# preference visits the view, Django will
# automatically show "Bienvenido a nuestro sitio."
Django Channels is an add-on that extends Django to handle asynchronous, long-running connections, most notably WebSockets.
Standard Django is synchronous (blocking) and built for the classic HTTP request-response cycle: a user asks for a page, and the server sends it. The connection is then closed.
Analogy: Walkie-Talkies vs. Phone Calls
When is it used?
Channels integrates with Django's auth and session systems and uses an ASGI (Asynchronous Server Gateway Interface) server instead of the standard WSGI.
3 questions · no sign-up, nothing stored
Progress is stored in this browser only - no sign-up, nothing sent anywhere.