django-admin startproject config .The trailing.avoids the classic nestedconfig/config/folder.★python manage.py startapp booksOne app per bounded concern. Then add it toINSTALLED_APPS— nothing works until you do.★python manage.py runserverDev only. It says so out loud since 5.2, and it means it.★python manage.py checkStatic checks without touching the DB.python manage.py shellA REPL with Django loaded. Where you'll live while learning the ORM.★python manage.py dbshellStraight into the database client.
models.CharField(max_length=200)max_lengthis mandatory.TextField()for unbounded prose.★models.DateTimeField(auto_now_add=True)Set once on create.auto_now=Trueupdates on every save.★models.DecimalField(max_digits=8, decimal_places=2)Money never goes in a FloatField.models.SlugField(unique=True)Also:EmailField,URLField,UUIDField,JSONField,BooleanField.models.ImageField(upload_to="covers/")Stores a path, not bytes. NeedsMEDIA_ROOTand Pillow.null=True vs blank=Truenull= database may hold NULL.blank= forms may leave it empty. They are unrelated. On text fields, useblank=Truealone.★
models.ForeignKey(Author, on_delete=models.CASCADE)Many books → one author.on_deleteis required — see the diagram below.★ForeignKey(..., related_name="books")Names the reverse accessor:author.books.all(). Without it you getbook_set.★models.ManyToManyField(Tag, blank=True)Django creates the join table. Addthrough=to own it yourself.models.OneToOneField(User, on_delete=models.CASCADE)The classic user-profile extension.class Meta: ordering = ["-created"]Default sort,db_table,constraints,indexes,unique_together.def __str__(self): return self.titleAlways define it. Your admin and shell become readable instantly.★
python manage.py makemigrationsReads your models, writes a migration file. Commit it — it's source code.★python manage.py migrateApplies pending migrations to the database.★python manage.py showmigrations[X]applied,[ ]pending. The first thing to check when things look wrong.★python manage.py sqlmigrate books 0002Print the SQL without running it. Review before you touch production.python manage.py migrate books 0001Roll backwards to an earlier migration.zerounapplies them all.python manage.py squashmigrations books 0012Collapse a long history into one.python manage.py migrate --fakeMarks migrations applied without running them. Lies to Django. Only for repairing a known-good schema.expert only
Book.objects.all()A lazy QuerySet. No SQL runs until you iterate it.★Book.objects.filter(year=2024)Returns a QuerySet (chainable)..exclude()is the inverse.★Book.objects.get(pk=7)Returns one object — or raisesDoesNotExist/MultipleObjectsReturned.★Book.objects.filter(...).first()ReturnsNoneinstead of raising. Often what you actually wanted.Book.objects.order_by("-created")Minus = descending."?"= random.Book.objects.filter(...).exists()Cheapest existence test. Never dolen(qs) > 0.★Book.objects.values_list("id", flat=True)A flat list of scalars — no model instances built.
filter(title__icontains="python")Case-insensitive substring.__containsis case-sensitive.★filter(year__gte=2020, year__lt=2025)Comma = AND. Also__gt,__lte,__range=(a, b).★filter(id__in=[1, 2, 3])SQLIN. Accepts another QuerySet — becomes a subquery.filter(author__country__name="India")Traverse relations with__. Django writes the JOINs. Any depth.★filter(cover__isnull=True)Also__startswith,__year,__date,__regex.filter(Q(a=1) | Q(b=2))Qobjects give you OR and NOT (~Q). Import fromdjango.db.models.★filter(sold__gt=F("stock"))F()compares two columns in the database, no Python round-trip.
Book.objects.create(title="…")Instantiate + save in one call.★book.save()INSERT if no pk, UPDATE if there is.save(update_fields=[...])writes fewer columns.Book.objects.get_or_create(isbn=x, defaults={...})Returns(obj, created). The idempotent workhorse.★Book.objects.bulk_create(objs)One INSERT for thousands of rows. Skipssave()and signals.★Book.objects.filter(...).update(stock=F("stock")-1)A single UPDATE. Bypassessave()and signals — that's the point, and the trap.with transaction.atomic():All-or-nothing. Wrap any multi-write operation.★Book.objects.all().delete()Deletes every row — and cascades to anything pointing at it.destructive
.select_related("author")One JOIN. For ForeignKey / OneToOne. Kills the N+1.★.prefetch_related("tags")A second query. For ManyToMany / reverse FK. Also kills the N+1.★.annotate(n=Count("reviews"))Adds a computed column per row. Thenbook.n.★.aggregate(Avg("price"))Collapses the whole QuerySet to one dict. Returns immediately..only("title") / .defer("body")Fetch fewer columns. Touching a deferred field costs another query.print(qs.query)See the SQL Django built..explain()asks the DB for its plan.★
path("books/", views.book_list, name="book-list")Always name your routes. Names are whatreverse()and{% url %}need.★path("books/<int:pk>/", views.detail, name="detail")Converters:int,str,slug,uuid,path. The capture becomes a view kwarg.★path("books/", include("books.urls"))Mount an app's URLconf under a prefix. Rooturls.pystays tiny.★app_name = "books"Namespaces the app. Reverse as"books:detail".reverse("books:detail", kwargs={"pk": 7})Build a URL from its name. Never hard-code a path.★def get_absolute_url(self):On the model. The admin and generic CBVs both pick it up for free.
render(request, "books/list.html", {"books": qs})Template + context →HttpResponse. The bread and butter.★get_object_or_404(Book, pk=pk)Fetch or raise 404. Use it instead of bare.get()in a view.★redirect("books:detail", pk=book.pk)Takes a view name, a model withget_absolute_url, or a raw path.★JsonResponse({"ok": True})Sets the content type for you.@login_requiredAnonymous users bounce toLOGIN_URL. Also@permission_required,@require_POST.★if request.method == "POST":The canonical FBV form shape: POST → validate → redirect; otherwise render an empty form.
ListViewmodel = Book→ templatebooks/book_list.html, contextobject_list. Addpaginate_by.★DetailViewExpectspkorslugin the URL →books/book_detail.html.★CreateView / UpdateView / DeleteViewSetfieldsorform_class, plussuccess_url. Full CRUD in ~6 lines.★def get_queryset(self):The hook you'll override most. Scope by user, addselect_related, filter.★def get_context_data(self, **kwargs):Callsuper()first, then add your extras.class BookList(LoginRequiredMixin, ListView):Mixins go first, left of the base view. MRO decides who runs.★Book.as_view()CBVs enter the URLconf asBookList.as_view(), never the bare class.
{{ book.title }}Dot lookup tries dict key → attribute → list index. Calls callables with no args.★{{ price|floatformat:2 }}Filters:date,length,default,truncatewords,linebreaks,safe.★{% for b in books %} … {% empty %} … {% endfor %}{% empty %}saves you an{% if %}. Alsoforloop.counter.★{% extends "base.html" %}Must be the first tag in the file. Then override{% block %}s.★{% url 'books:detail' book.pk %}Reverse a route by name, in the template.★{% load static %} … {% static 'css/app.css' %}{% load %}must come before you use the tag.{% csrf_token %}Inside every POST form, or Django rejects it with a 403.★
class BookForm(forms.ModelForm):Derives fields from the model.class Meta: model, fields.★form = BookForm(request.POST)Bound. Unbound isBookForm(). For file uploads addrequest.FILES.★if form.is_valid():Runs validation and populatesform.cleaned_data. Check it before you trust anything.★form.save(commit=False)Get the unsaved instance so you can setobj.owner = request.userfirst.★def clean_title(self):Per-field validation. Plainclean()validates across fields.fields = "__all__"Convenient — and a mass-assignment risk. Prefer an explicit list.
@admin.register(Book)Decorator form, above yourModelAdminclass.★list_display = ("title", "author", "year")Columns in the changelist. Can include methods.★list_filter = ("year",) · search_fields = ("title",)Sidebar filters and a search box, free.★list_select_related = ("author",)The admin N+1 fix. Without it, a 100-row page fires 100 extra queries.prepopulated_fields = {"slug": ("title",)}Auto-slug as you type.inlines = [ChapterInline]Edit children on the parent's page.
python manage.py createsuperuserYour way into/admin/.★get_user_model()Never importUserdirectly. And setAUTH_USER_MODELto your own model before the first migration.★login(request, user) / logout(request)Afterauthenticate(username=…, password=…).request.user.is_authenticatedA property, not a method. Works in templates too.★LoginRequiredMiddlewareDjango 5.1+: login required by default, everywhere. Opt a view out with@login_not_required.path("", include("django.contrib.auth.urls"))Login, logout, password reset — all wired up for free.
INSTALLED_APPS += ["books"]Without this, your models, templates and admin are invisible.★STATIC_URL · STATICFILES_DIRS · STATIC_ROOTThree different things. URL prefix · where you author · wherecollectstaticdumps.★python manage.py collectstaticGathers every app's static files intoSTATIC_ROOT. A deploy step, not a dev one.★MEDIA_ROOT / MEDIA_URLUser uploads. Separate from static, and never served by Django in production.DEBUG = TrueIn production this leaks your settings, SQL and stack traces to the world.never in prodpython manage.py check --deployRun before every deploy. Audits DEBUG, HSTS, cookies, SECRET_KEY, ALLOWED_HOSTS.★
class BookTests(TestCase):Each test runs in a transaction and is rolled back. A fresh DB every run.★self.client.get("/books/")A fake browser.assertEqual(r.status_code, 200),assertContains,assertRedirects.★python manage.py test books.tests.BookTestsNarrow the run to a module, class or single method.self.assertNumQueries(2)Assert the query count. The regression test for an N+1.★python manage.py dumpdata books > books.jsonloaddatareads it back. Handy for fixtures and seeds.python manage.py flushEmpties every table and re-runs the sync. Keeps the schema, destroys the data.destructive
from django.tasks import taskBackground Tasks (6.0). A built-in job framework — run work outside the request/response cycle, no Celery required.★@task · fn.enqueue(...)Decorate a function with@task, then.enqueue(...)to run it. Choose a backend via theTASKSsetting.★SECURE_CSP = {"default-src": [CSP.SELF]}Built-in CSP (6.0).from django.utils.csp import CSP; addContentSecurityPolicyMiddleware. UseSECURE_CSP_REPORT_ONLYto trial a policy.★{% partialdef card %}…{% partial card %}Template partials (6.0). Reusable inline fragments; load from anywhere as"page.html#card".AsyncPaginator · AsyncPageAsync pagination (6.0) forasyncviews —awaitthe page and object-count access.
models.pyBusiness rules about data. Validation, computed properties, custom managers. Fat models.★views.pyRequest handling only. Take a request, pick data, choose a response. Thin views.★forms.pyValidating user input. Not the model's job — untrusted data stops here.templates/Presentation only. If you need a loop with logic in it, do the work in the view.urls.pyRouting only. No imports from models. Just names and paths.