The only way to learn modeling is by modeling. Implement the v1 model and then tackle the challenges. Don't look at solutions.md until you've submitted.
Setup:
cd ~/dev/ticketflow && source .venv/bin/activateExercise 1 — Implement the v1 model
Create in events/models.py the classes from the lesson: TimeStampedModel, User, Event, Seat, Reservation, ReservationItem and Payment (with their TextChoices).
Register the app in settings.py (INSTALLED_APPS), and declare in settings.py:
AUTH_USER_MODEL = "events.User"Do this before the first migration. Changing
AUTH_USER_MODELmid-project is one of Django's most painful migrations; that's why we decide it now (Lesson 11 pulled forward: schema decisions are made before data exists).
Then run:
python manage.py makemigrations
python manage.py migrateDeliverable: the list of models python manage.py makemigrations --dry-run -v2 prints (or simply confirm it migrated without errors and paste the summary).
Exercise 2 — Prove invariant I1 in the shell
Open python manage.py shell and try to break the invariant: two active reservations with the same seat.
from events.models import *
u1 = User.objects.create(email="ana@example.com")
u2 = User.objects.create(email="beto@example.com")
ev = Event.objects.create(title="Concert", venue="Hall X", starts_at="2027-03-01T21:00:00Z", state=EventState.PUBLISHED, organizer=u1)
s1 = Seat.objects.create(event=ev, row="A", number=1)
s2 = Seat.objects.create(event=ev, row="A", number=2)
r1 = Reservation.objects.create(user=u1, event=ev, status=ReservationState.PENDING_PAYMENT, expires_at="2026-10-01T12:00:00Z")
ReservationItem.objects.create(reservation=r1, seat=s1, price_at_purchase="50.00")
r2 = Reservation.objects.create(user=u2, event=ev, status=ReservationState.PENDING_PAYMENT, expires_at="2026-10-01T12:00:00Z")
ReservationItem.objects.create(reservation=r2, seat=s1, price_at_purchase="50.00") # ← should this explode?- Which exception does the last line raise, and with what message?
- Temporarily remove the two conditional
UniqueConstraints from the model, remake the migration and repeat the experiment. Does the second reservation get created? What does that mean for the business? - Restore the constraints. Write down in 2 lines what you just demonstrated (this is the proof you'll tell in an interview).
Exercise 3 — Availability query
Write (in the shell, or in events/services.py if you're brave) a function available_seats(event_id) that returns the event's seats without an active or confirmed reservation.
- Write it without raw SQL (hint: subquery or
excludeover the reverse relation). - Print the number of queries it runs with
django.db.connection.queriesor django-debug-toolbar… or simplylen(connection.queries)after calling it twice. - Does it run 1 query or N? (Keep your answer: we'll revisit it in Lesson 09 with
EXPLAIN.)
Exercise 4 — State machine in the model
Add to Reservation the methods with legal transitions:
def confirm(self, when):
...
def cancel(self, when):
...Rules: only a PENDING_PAYMENT reservation with an unexpired expires_at and a SUCCEEDED payment can be confirmed; only a non-cancelled reservation can be cancelled (cancelling something cancelled must be idempotent: it doesn't fail, it changes nothing).
- Implement both methods raising
ValueError(or a domain exception of your own) on illegal transitions. - In the shell: create an expired reservation (
expires_atin the past) and tryconfirm(). What happens? - Run
cancel()twice. Is the second a silent no-op or does it raise? Justify your choice.
Exercise 5 — Design what v1 left out (discussion)
Answer reasoning about trade-offs (2-3 sentences each, no code needed):
- The organizer wants "the whole VIP row A" as a separate product with a different price. What would you change in the model? Is it worth it for v1?
- TicketFlow wants to allow "up to 4 seats per user per event". Where does that rule live: a DB constraint, a serializer validation, or a model method? Why?
- A competitor sells "general admission tickets without an assigned seat" (capacity only). Would you reuse
Seator model a different ticket type? What does each option break?
Exercise 6 — Senior reflection (5 minutes)
Imagine that in 6 months TicketFlow has 500 events and 2M seats. With the v1 model:
- Which query worries you the most? (hint: the one everyone makes every second)
- Which index or table do you feel will hurt first?
- What would you do today — cheap to do now, very expensive later — to prepare?
Submission
Paste your results in the chat (code, exceptions and answers). I'll grade them one by one, and with that we close 00b and mark it mastered. Next: Lesson 01 — HTTP in depth if you haven't done it, or Lesson 02 — Networking if you already submitted 01.