Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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.

Russell Keith-Magee

September 04, 2013
Tweet

More Decks by Russell Keith-Magee

Other Decks in Technology

Transcript

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

    View full-size slide

  2. Image Source: Amazon.com

    View full-size slide

  3. Why should we care?

    View full-size slide

  4. Login using
    email address

    View full-size slide

  5. Associating profile data
    with the User model

    View full-size slide

  6. What’s in a name?

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  9. Yao Ming
    Image Source: Wikipedia

    View full-size slide

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

    View full-size slide

  11. Mahathir bin Mohamad
    Image Source: Wikipedia

    View full-size slide

  12. Mohd. Anwar El Sadat
    Image Source: Wikipedia

    View full-size slide

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

    View full-size slide

  14. Ayrton Senna da Silva
    Image Source: Wikipedia

    View full-size slide

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

    View full-size slide

  16. www.w3.org/International/questions/qa-personal-names

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  20. Names are hard.
    Lets go shopping.

    View full-size slide

  21. Do you really need
    separate fields?
    Full name

    View full-size slide

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

    View full-size slide

  23. “How would you like
    to be addressed?”

    View full-size slide

  24. 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

    View full-size slide

  25. On the subject of
    “do you need to ask”...

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  28. When it comes to
    questions of identity:
    You need to think

    View full-size slide

  29. Do I need to ask at all?

    View full-size slide

  30. Custom User Models

    View full-size slide

  31. This is all in the docs.

    View full-size slide

  32. 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()

    View full-size slide

  33. 2. Define your Manager
    • Need to describe:
    • How to create users
    • How to create superusers

    View full-size slide

  34. 3. Define forms
    • UserCreationForm
    • UserChangeForm
    • PasswordResetForm (maybe)

    View full-size slide

  35. 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

    View full-size slide

  36. 5. Register model
    • In settings, define:
    AUTH_USER_MODEL = ‘myapp.MyUser’

    View full-size slide

  37. 6. Update Foreign Keys
    • Before:
    • ForeignKey(User)
    • After:
    • ForeignKey(settings.AUTH_USER_MODEL)

    View full-size slide

  38. Documented Gotchas

    View full-size slide

  39. USERNAME_FIELD
    must be unique
    and not in
    REQUIRED_FIELDS

    View full-size slide

  40. Signal registration

    View full-size slide

  41. What isn’t in the docs?

    View full-size slide

  42. Reverse lookup naming

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  45. 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()

    View full-size slide

  46. 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()

    View full-size slide

  47. The User Contract

    View full-size slide

  48. Examples of use

    View full-size slide

  49. Email based login

    View full-size slide

  50. Email-based login
    • Define a user model with
    • email = EmailField(max_length=254)
    • USERNAME_FIELD = ‘email’
    • Define forms, admin, etc
    • Set AUTH_USER_MODEL

    View full-size slide

  51. Better yet:
    Don’t reinvent the
    wheel!

    View full-size slide

  52. Ticket #20824

    View full-size slide

  53. API-based login

    View full-size slide

  54. Kerberos Single Sign-on

    View full-size slide

  55. Kerberos Single Sign-on
    • “username” is your Kereros token:
    username@domain
    • Define an authentication backend that
    converts credentials into users

    View full-size slide

  56. 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.

    View full-size slide

  57. www.roguelynn.com
    /words/django-custom-user-models/

    View full-size slide

  58. Profile data

    View full-size slide

  59. Option 1
    class User(AbstractUser):
    full_name = CharField()
    birth_date = DateField()
    avatar = FileField()

    View full-size slide

  60. Option 2:
    class User(AbstractUser):
    ...
    class UserProfile(Model):
    full_name = CharField()
    user = OneToOneField(User)
    birth_date = DateField()
    avatar = FileField()

    View full-size slide

  61. 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()

    View full-size slide

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

    View full-size slide

  63. So which approach
    should you use?

    View full-size slide

  64. Broadly:
    Profiles are better
    architecture

    View full-size slide

  65. But: there’s a cost

    View full-size slide

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

    View full-size slide

  67. One more thing...

    View full-size slide

  68. How does it all work?

    View full-size slide

  69. THE FOLLOWING
    SLIDES WILL SELF
    DESTRUCT AFTER
    THIS PRESENTATION

    View full-size slide

  70. 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

    View full-size slide

  71. 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.

    View full-size slide

  72. The dirty secret:
    You can make your
    own models swappable.

    View full-size slide

  73. Questions?
    http://cecinestpasun.com
    [email protected]
    @freakboy3742

    View full-size slide