Premier League Predictor: Django & MySQL — Chapter 5, Exercise 1 ==================================================== TASK Explain why unique_key evaluates to NULL for a guest prediction but a real string for every other source, and why that specific choice is what makes the UniqueConstraint on unique_key behave correctly for both cases. SOLUTION unique_key is defined as a Django GeneratedField whose expression is a Case/When: when source equals 'guest', it evaluates to Value(None) — a real SQL NULL; for every other source (user/expert/ai) it evaluates to Concat(fixture_id, '-', source), a real, deterministic string like "42-expert". This split matters because of one specific, universal SQL rule that has nothing to do with Django itself: a unique index or unique constraint never treats two NULL values as equal to each other. Any number of rows can share a NULL in a unique-constrained column without the database ever raising a conflict. So every guest prediction row, regardless of how many guests predicted a given fixture, gets NULL in unique_key — the UniqueConstraint on that column simply never has anything to compare those rows against, and they all coexist freely. For a user, expert, or ai row, unique_key is a real, non-null string built from that specific fixture and that specific source. Two rows for the same fixture and the same source (e.g. two "expert" predictions on fixture 42) would both compute to the identical string "42-expert" — and because neither value is NULL, the UniqueConstraint does apply here, and the second insert is rejected as a genuine duplicate. So the NULL-vs-string split is exactly what lets one single UniqueConstraint enforce two different rules at once: "unlimited guest predictions allowed" and "at most one prediction per real source per fixture" — without any conditional WHERE clause on the index at all, which MySQL doesn't support in the first place. WHY THIS WORKS AS AN ANSWER ---------------------------- It identifies the specific SQL rule (NULL is never unique-equal to NULL) that the whole mechanism depends on, and explains concretely why that rule produces the correct behavior for both the guest case and the non-guest case under one single UniqueConstraint.