Red User, Blue User, MyUser, auth.User

Red User, Blue User, MyUser, auth.User

An exploration of one of the banner features of Django 1.5 -- Custom User models. Includes worked examples, a discussion of design decisions that must be made, and a look at the internal architecture that makes it all possible.

B91373320dbc3bc52fcd870d3b21748f?s=128

Russell Keith-Magee

September 04, 2013
Tweet

Transcript

  1. Red User, Blue User, MyUser, auth.User Dr Russell Keith-Magee DjangoCon

    US 2013
  2. None
  3. None
  4. Image Source: Amazon.com

  5. Why should we care?

  6. Login using email address

  7. Associating profile data with the User model

  8. What’s in a name?

  9. class User(Model): first_name = CharField(max_length=30) last_name = CharField(max_length=30)

  10. WTF?

  11. ⽑毛泽东 Mao Zedong Image Source: Wikipedia

  12. Yao Ming Image Source: Wikipedia

  13. Björk Guðmundsdóttir Image Source: IMDB

  14. Mahathir bin Mohamad Image Source: Wikipedia

  15. Mohd. Anwar El Sadat Image Source: Wikipedia

  16. Aránzazu Isabel María Sánchez Vicario Image Source: Wikipedia

  17. Ayrton Senna da Silva Image Source: Wikipedia

  18. Stilgherrian Image Source: stilgherrian.com/about; ©2009 Trinn (’Pong) Suwannaph; Used with

    permission
  19. www.w3.org/International/questions/qa-personal-names

  20. class User(Model): first_name = CharField(max_length=30) last_name = CharField(max_length=30)

  21. class User(Model): first_name = CharField(max_length=100) last_name = CharField(max_length=100) NOPE

  22. class User(Model): christian_name = CharField(max_length=10) middle_initial = CharField(max_length=1) last_name =

    CharField(max_length=10)
  23. Names are hard. Lets go shopping.

  24. Do you really need separate fields? Full name

  25. If you do, don’t use first/last name. Family name Other/Given

    names
  26. “How would you like to be addressed?”

  27. Other tips • Don’t assume a single letter is an

    initial • Be wary of name-part algorithms • Spaces, Apostrophes and Hyphens are all legal characters in names • Don’t require a “family name” • “Previous name”, not “Maiden name” • Honorifics even more complex
  28. On the subject of “do you need to ask”...

  29. http://www.tizag.com/phpT/examples/formex.php

  30. Kuzdu and the California Marriage Amendment http://linuxmafia.com/faq/Essays/marriage.html

  31. When it comes to questions of identity: You need to

    think
  32. Do I need to ask at all?

  33. Custom User Models

  34. This is all in the docs.

  35. 1. Define user model • 2 possible abstract base classes:

    • AbstractBaseUser • AbstractUser • Maybe with PermissionsMixin • Define USERNAME_FIELD • Define REQUIRED_FIELDS • Define get_full_name() and get_short_name()
  36. 2. Define your Manager • Need to describe: • How

    to create users • How to create superusers
  37. 3. Define forms • UserCreationForm • UserChangeForm • PasswordResetForm (maybe)

  38. 4. Register with admin • Only need to do this

    if you’re using admin • Subclass contrib.admin.UserAdmin • admin.site.register() • Don’t need to unregister default User
  39. 5. Register model • In settings, define: AUTH_USER_MODEL = ‘myapp.MyUser’

  40. 6. Update Foreign Keys • Before: • ForeignKey(User) • After:

    • ForeignKey(settings.AUTH_USER_MODEL)
  41. Documented Gotchas

  42. USERNAME_FIELD must be unique and not in REQUIRED_FIELDS

  43. Signal registration

  44. What isn’t in the docs?

  45. Reverse lookup naming

  46. Reverse lookup naming class Department(Model): ... class User(AbstractUser): full_name =

    CharField() department = ForeignKey(Department) department = Department.objects.get(...) print department.user_set.all()
  47. Reverse lookup naming class Department(Model): ... class MyUser(AbstractUser): full_name =

    CharField() department = ForeignKey(Department) department = Department.objects.get(...) print department.myuser_set.all()
  48. Reverse lookup naming class Department(Model): ... class MyUser(AbstractUser): full_name =

    CharField() department = ForeignKey(Department, related_name=‘user_set’) department = Department.objects.get(...) print department.user_set.all()
  49. Reverse lookup naming class Department(Model): ... class MyUser(AbstractUser): full_name =

    CharField() department = ForeignKey(Department) department = Department.objects.get(...) attr = “%s_set” % user._meta.object_name print getattr(department,attr).all()
  50. The User Contract

  51. Examples of use

  52. Email based login

  53. Email-based login • Define a user model with • email

    = EmailField(max_length=254) • USERNAME_FIELD = ‘email’ • Define forms, admin, etc • Set AUTH_USER_MODEL
  54. Better yet: Don’t reinvent the wheel!

  55. Ticket #20824

  56. API-based login

  57. Kerberos Single Sign-on

  58. Kerberos Single Sign-on • “username” is your Kereros token: username@domain

    • Define an authentication backend that converts credentials into users
  59. Authentication Backends • On login, you provide a credentials dict

    • Usually, Username and Password • Can be anything • Authentication backend turns credentials into a validated user • Can have multiple authentication backends.
  60. www.roguelynn.com /words/django-custom-user-models/

  61. Profile data

  62. Option 1 class User(AbstractUser): full_name = CharField() birth_date = DateField()

    avatar = FileField()
  63. Option 2: class User(AbstractUser): ... class UserProfile(Model): full_name = CharField()

    user = OneToOneField(User) birth_date = DateField() avatar = FileField()
  64. Option 2: class User(AbstractUser): ... class IdentityProfile(Model): user = OneToOneField(User)

    full_name = CharField() birth_date = DateField() class DisplayProfile(Model): user = OneToOneField(User) avatar = FileField()
  65. Option 3: Hybrid class User(AbstractUser): full_name = CharField() class UserProfile(Model):

    user = OneToOneField(User) birth_date = DateField() avatar = FileField()
  66. So which approach should you use?

  67. It depends.

  68. Broadly: Profiles are better architecture

  69. But: there’s a cost

  70. Where to draw the line for the hybrid models?

  71. One more thing...

  72. How does it all work?

  73. THE FOLLOWING SLIDES WILL SELF DESTRUCT AFTER THIS PRESENTATION

  74. How it works • No internal references to auth.User •

    auth.User has a Meta property: swappable = ‘AUTH_USER_MODEL’ • Defines the name of a setting • Inspected at runtime for the “real” class • generates Meta.swapped • The rest is just validation
  75. ForeignKeys + M2M • No new features in ForeignKey or

    M2M • ForeignKey(‘auth.User’) has always worked • Now, we’re just using a setting • Validation that ForeignKey doesn’t point at a “swapped” model.
  76. The dirty secret: You can make your own models swappable.

  77. None
  78. Questions? http://cecinestpasun.com russell@keith-magee.com @freakboy3742