Exercise 2: Why the Hash Is Assigned Directly, Not via set_password() — Possible Solution ==================================================================== WHAT set_password() ACTUALLY DOES ------------------------------ Per this chapter, set_password() takes a PLAINTEXT password as its argument and hashes it using Django's own configured hasher before storing the result. WHY IT CAN'T BE USED HERE ------------------------------ The value being imported here isn't a plaintext password at all - it's already a real, existing bcrypt hash ($2b$12$...) from the old site. Passing that already-hashed string into set_password() would cause Django to hash the hash a second time, producing a completely different, corrupted value that would never match the admin's real password on a future login attempt - the original working hash would effectively be destroyed. WHY DIRECT ASSIGNMENT IS CORRECT ------------------------------ Per this chapter, assigning the existing hash string directly to admin.password leaves it completely unchanged - exactly the same bcrypt hash the old PHP site was already using. This lets Django's own authentication compare a future login attempt against that untouched, original hash exactly as the old site would have, which is the entire point of preserving it without forcing a password reset. WHY THIS WORKS AS AN ANSWER ------------------------------ It correctly explains that set_password() hashes a plaintext input (which would corrupt an already-hashed value), and correctly explains that direct assignment preserves the existing hash unchanged, which is required for authentication against it to work correctly.