Day 8 · 1 Hour
Django ORM
Python code that writes SQL for you — filter, annotate, aggregate without a single SQL string.
🔥 Real-World Hook (0–5 min)
Writing raw SQL for every database operation is like assembling IKEA furniture without the instructions — possible but painful.
Django's ORM translates Python into SQL automatically. Student.objects.filter(dept="CS", gpa__gt=3.5) — that is your SQL query. No string building, no injection risk, no connection management. Used by every Django company in India.
🔎 ORM = Object-Relational Mapping (5–25 min)
💡 Analogy
The ORM is a translator. You speak Python, it speaks SQL. Student.objects.all() → SELECT * FROM students. You never need to write SQL directly — but understanding what SQL it generates helps you write faster queries.
💻 Live Coding — ORM Query Toolkit (25–45 min)
from students.models import Student # ── Basic CRUD ────────────────────────────────────────────────────────────── # CREATE s = Student.objects.create(name="Priya", email="p@mail.com", dept="CS", gpa=3.9) # READ all_students = Student.objects.all() # SELECT * cs_students = Student.objects.filter(dept="CS") # WHERE dept='CS' one = Student.objects.get(pk=1) # WHERE id=1 (raises if not found) first = Student.objects.first() # LIMIT 1 # UPDATE Student.objects.filter(name="Priya").update(gpa=3.95) # DELETE Student.objects.filter(gpa__lt=2.0).delete() # ── Advanced Filters ──────────────────────────────────────────────────────── # __ (double underscore) = "lookup" — maps to SQL operators passing = Student.objects.filter(gpa__gte=3.5) # gpa >= 3.5 cs_pass = Student.objects.filter(dept="CS", gpa__gt=3.5) # AND with_a = Student.objects.filter(name__icontains="a") # LIKE '%a%' case-insensitive top3 = Student.objects.order_by("-gpa")[:3] # ORDER BY gpa DESC LIMIT 3 # ── Aggregation ────────────────────────────────────────────────────────────── from django.db.models import Count, Avg, Max stats = Student.objects.aggregate( total=Count("id"), avg_gpa=Avg("gpa"), max_gpa=Max("gpa") ) print(stats) # {'total': 8, 'avg_gpa': 3.5, 'max_gpa': 3.9} # Per-department stats dept_stats = (Student.objects .values("dept") .annotate(count=Count("id"), avg=Avg("gpa")) .order_by("-avg")) for d in dept_stats: print(f"{d['dept']}: {d['count']} students, avg GPA {d['avg']:.2f}")
🎯 You Code It (45–55 min)
- Open your Django project from Day 7 in the shell:
python manage.py shell - Create 8 students covering CS, IT, EC, ME departments with varied GPAs
- Query: All CS students with GPA > 3.5, ordered by GPA descending
- Query: Count of students per department using
values()+annotate() - Query: Update all students with GPA below 2.0 to have
gpa = 2.0(floor correction) - Query: Get the student with the highest GPA in each department
- Show: Run all queries in shell, show instructor the output
📄 Day 8 Cheat Sheet — Django ORM
QuerySet Methods
| .all() | All rows |
| .filter(**kwargs) | WHERE condition |
| .exclude(**kwargs) | WHERE NOT |
| .get(**kwargs) | One row (raises if 0 or >1) |
| .first() .last() | First / last row |
| .count() | COUNT(*) |
Lookup Operators
| field__exact=v | = v (default) |
| field__gt=v | > v |
| field__gte=v | >= v |
| field__lt=v | < v |
| field__icontains=v | LIKE %v% (case-insensitive) |
| field__in=[a,b,c] | IN (a,b,c) |
Create / Update / Delete
| Model.objects.create(**data) | INSERT + save |
| obj.save() | INSERT or UPDATE |
| qs.update(field=val) | UPDATE all in qs |
| obj.delete() | DELETE one |
| qs.delete() | DELETE all in qs |
| get_or_create(**kwargs) | Find or create |
Aggregation
| from django.db.models import Count,Avg | Import |
| .aggregate(total=Count("id")) | Single stat |
| .values("dept") | GROUP BY dept |
| .annotate(c=Count("id")) | Add agg to each group |
| .order_by("-avg") | Sort groups |
| .select_related("fk") | JOIN in one query |