Nobody has started this yet — be first.
Business impact
Email is how support, billing, and any future "forgot your password" flow identify an account. If two different people (or one person twice, by accident) can register with the same email, there is no way to know which account an email-based action -- a password reset, a notification, a support lookup -- is supposed to act on. This is exactly the kind of gap that looks harmless until the first support ticket titled "I reset my password but I still can't log in to MY account" shows up, because the reset silently touched the wrong one of two accounts sharing an email.
Problem
RegisterSerializer validates password (via Django's password validators) but has no validation on email at all. Django's AbstractUser.email field (which accounts.models.User inherits) is not unique by default, so nothing at the database or serializer level stops a second POST /api/auth/register/ from reusing an email that already belongs to another account.
Current behavior
Registering a brand-new account with an email address that already belongs to an existing user succeeds with 201 instead of being rejected -- two accounts now share one email.
Expected behavior
POST /api/auth/register/ rejects a registration whose email is already in use by another account, with a 400 and a clear field-level error message under "email" in the response body -- the same shape DRF already uses for other field errors on this endpoint.
Steps to reproduce
curl -s -X POST http://127.0.0.1:8000/api/auth/register/
-H 'Content-Type: application/json'
-d '{"username":"frank","email":"shared@example.com","password":"a-strong-password-123"}'
curl -s -X POST -H 'Content-Type: application/json' -d '{"username":"georgia","email":"","password":"another-strong-pw-1"}'
Why this matters
This has to be enforced in the serializer (or the database), not "by convention," because nothing else in the request path checks it -- create() just calls User.objects.create_user(**validated_data), which doesn't care whether the email is already taken.
Suggested approach
Look at how DRF's CharField/EmailField support per-field validate_<fieldname> methods -- there's already a working example of a serializer-level validate() override to model the style on, in LoginSerializer right below RegisterSerializer in the same file, though that one validates the whole payload rather than a single field. You'll need to look up whether an account with that email already exists.
Acceptance criteria
Verification
python manage.py test practicetickets.ticket03_duplicate_email_registration -v 2
Hints (0/2)
Try it without hints first — the reading is the exercise.
Working on this ticket
Work on a branch named for the ticket — that's what you'll submit.
Branch off your fork
$git checkout -b feat/duplicate-email-registrationFix it and commit
Meet every acceptance criterion, and add a test that would have caught this.
Push the branch
$git push -u origin feat/duplicate-email-registrationSubmit it below
Paste your fork URL and the branch name, with a short write-up of the root cause.
Questions
Ask about anything unclear in the ticket — the maintainer and anyone who has solved it can answer. Please don't post full solutions.
Sign in to ask a question or reply.
Sign in.envhttp://127.0.0.1:8000/api/http://127.0.0.1:8000/admin/To run against Postgres via Docker instead:
docker compose up --build # postgres + web, migrations run automatically on startup
Work the tickets in practicetickets/ (TICKET_01 through TICKET_07); each names one dedicated test, addressed by its explicit dotted label since these modules are deliberately named so Django's default test*.py discovery never picks them up:
python manage.py test practicetickets.ticket01_login_credential_swap -v 2 # a single ticket
./practicetickets/run_tickets.sh # all 7, clean pass/fail summary
Two of the seven bugs (tickets 01 and 06) are real enough to also break the project's own pre-existing suite (python manage.py test) -- fixing them correctly makes those pass again too, with zero changes needed inside accounts/tests.py or applications/tests.py.
Level 2
Implement a feature
Extend the system within its own patterns.