LESSON 76 · ADVANCED4 min read

Django Fundamentals

Create a Django project and app, model data with migrations, and connect requests to views and templates.

Python 3.12+Free to readModule 17 of 19
YOUR NEXT SMALL WINS

By the end, you’ll be able to…

  • Explain Django's model-view-template architecture.
  • Create a project and app and register the app.
  • Define models and evolve the database with migrations.
  • Connect URLs to views that render templates or return responses.

01Django provides a full-stack contract

Django is a batteries-included web framework. A request arrives at a URL resolver, reaches a view, and produces a response. Models describe persistent data, views apply the workflow, and templates render the presentation. The separation is often called MVT: model, view, template.

The framework supplies an ORM, migrations, forms, authentication, an admin site, and security defaults. That breadth is useful when the domain fits its conventions. It is still your responsibility to validate input, authorize actions, and test the behavior users depend on.

start_project.txtShell
py -m pip install djangopy -m django startproject config .py manage.py startapp blogpy manage.py runserver

02Configure the project deliberately

A Django project is a package of settings and URL configuration. An app is a reusable unit of features. Add the app to INSTALLED_APPS before using its models or templates. Keep environment-specific values, especially SECRET_KEY and database credentials, outside source control.

The development server is not a production server. It is fine for local feedback and tests, but production needs a real WSGI or ASGI server, static file handling, and a reviewed settings module. Decide those boundaries before the first deployment, not after an incident. Keep DEBUG false and ALLOWED_HOSTS explicit in production; both are security boundaries, not optional polish.

settings.pyPython
import osfrom pathlib import PathBASE_DIR = Path(__file__).resolve().parent.parentSECRET_KEY = os.environ["DJANGO_SECRET_KEY"]DEBUG = os.environ.get("DJANGO_DEBUG") == "1"ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS", "").split(",")INSTALLED_APPS = [    "django.contrib.admin",    "django.contrib.auth",    "django.contrib.contenttypes",    "django.contrib.sessions",    "django.contrib.messages",    "django.contrib.staticfiles",    "blog",]

03Models and migrations define data

A model is a Python class that maps to a database table. Fields declare storage and basic validation. Relationships use ForeignKey, OneToOneField, or ManyToManyField. A __str__ method makes admin pages and logs readable.

makemigrations compares the models to the migration history and writes a migration file. migrate applies it. Review generated migrations before committing, especially data migrations and destructive changes. The ORM is a query interface, not a substitute for understanding the SQL and indexes behind a slow page.

models.pyPython
from django.db import modelsclass Post(models.Model):    title = models.CharField(max_length=200)    slug = models.SlugField(unique=True)    body = models.TextField()    published = models.BooleanField(default=False)    created_at = models.DateTimeField(auto_now_add=True)    def __str__(self):        return self.title

04Views and URLs connect requests

A view receives a request and returns a response. Function views are explicit and easy to read; class-based views reduce repetition for standard CRUD patterns. Start with functions when the workflow is custom. A URL pattern passes captured values to the view as arguments.

Use get_object_or_404 when a missing record should produce a 404 rather than a server error. Use render for templates and JsonResponse for JSON. Keep business rules in a service or model method when they are shared by multiple views; a view should orchestrate, not contain every rule.

views.pyPython
from django.http import JsonResponsefrom django.shortcuts import get_object_or_404, renderfrom .models import Postdef post_list(request):    posts = Post.objects.filter(published=True).order_by("-created_at")    return render(request, "blog/post_list.html", {"posts": posts})def post_detail(request, slug):    post = get_object_or_404(Post, slug=slug, published=True)    return JsonResponse({"title": post.title, "body": post.body})
LET IT CLICK

The ideas worth keeping.

  • Django connects URL resolution, views, models, and templates.
  • Models evolve through reviewed migrations, not manual table edits.
  • Views orchestrate a request and return a response; shared rules belong in models or services.
TURN UNDERSTANDING INTO SOMETHING YOU CAN DO

Make it yours.

Type and test your code right here in the interactive workspace. Run your solution, check the output, and compare with the worked guide when ready.

01

Create an article model

Define an Article model with title, slug, body, published, and created_at. Make slug unique and created_at automatic. Add a readable __str__.

your_turn_1.py🐍Python
Ctrl + ↵
Output
Click Run or press Ctrl+Enter
Output will appear here after you run the code.
Explore a worked solution
one_possible_solution.pyPython
from django.db import modelsclass Article(models.Model):    title = models.CharField(max_length=200)    slug = models.SlugField(unique=True)    body = models.TextField()    published = models.BooleanField(default=False)    created_at = models.DateTimeField(auto_now_add=True)    def __str__(self):        return self.title

The unique slug supports stable URLs. auto_now_add sets the timestamp once, when the row is created, rather than on every save.

02

Add a published list view and URL

Write a view that returns published posts ordered newest first, render a template, and map it to the empty path.

your_turn_2.py🐍Python
Ctrl + ↵
Output
Click Run or press Ctrl+Enter
Output will appear here after you run the code.
Explore a worked solution
one_possible_solution.pyPython
# views.pyfrom django.shortcuts import renderfrom .models import Postdef post_list(request):    posts = Post.objects.filter(published=True).order_by("-created_at")    return render(request, "blog/post_list.html", {"posts": posts})# urls.pyfrom django.urls import pathfrom . import viewsurlpatterns = [    path("", views.post_list, name="post_list"),]

Filtering in the view keeps unpublished drafts out of the public list. The named URL lets templates and redirects refer to the route without hard-coding the path.

A SMALL QUESTION. A USEFUL NEXT STEP.

What stayed with you?

Check the ideas while they’re fresh. Your answers stay in this page and feedback appears as you go.

A LITTLE ACTIVE RECALL0 / 3 answered
01What does MVT stand for?
02What creates or changes database tables from models?
03Why keep SECRET_KEY out of source control?
⚡CODING CHALLENGE
🔒Required to Mark Lesson Complete

Create an article model

Define an Article model with title, slug, body, published, and created_at. Make slug unique and created_at automatic. Add a readable __str__.

EXPECTED OUTPUT
[Process exited with code 0 - No output]
main.pyPython 3
Ctrl + ↵
Execution Console
Click "Run & Verify" (or press Ctrl + Enter) to test your code against the challenge.

Keep exploring.

The official references behind this lesson, when you want a second angle or the full details.

One lesson closer.

Reading is a start. Trying it yourself makes the connection.

Solve the hands-on coding challenge in the knowledge section to verify your code and unlock lesson completion.