Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

Image Source: Amazon.com

Slide 5

Slide 5 text

Why should we care?

Slide 6

Slide 6 text

Login using email address

Slide 7

Slide 7 text

Associating profile data with the User model

Slide 8

Slide 8 text

What’s in a name?

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

WTF?

Slide 11

Slide 11 text

⽑毛泽东 Mao Zedong Image Source: Wikipedia

Slide 12

Slide 12 text

Yao Ming Image Source: Wikipedia

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

Mahathir bin Mohamad Image Source: Wikipedia

Slide 15

Slide 15 text

Mohd. Anwar El Sadat Image Source: Wikipedia

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

Ayrton Senna da Silva Image Source: Wikipedia

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

Names are hard. Lets go shopping.

Slide 24

Slide 24 text

Do you really need separate fields? Full name

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

“How would you like to be addressed?”

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

Do I need to ask at all?

Slide 33

Slide 33 text

Custom User Models

Slide 34

Slide 34 text

This is all in the docs.

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

Documented Gotchas

Slide 42

Slide 42 text

USERNAME_FIELD must be unique and not in REQUIRED_FIELDS

Slide 43

Slide 43 text

Signal registration

Slide 44

Slide 44 text

What isn’t in the docs?

Slide 45

Slide 45 text

Reverse lookup naming

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

The User Contract

Slide 51

Slide 51 text

Examples of use

Slide 52

Slide 52 text

Email based login

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

Better yet: Don’t reinvent the wheel!

Slide 55

Slide 55 text

Ticket #20824

Slide 56

Slide 56 text

API-based login

Slide 57

Slide 57 text

Kerberos Single Sign-on

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

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.

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

Profile data

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

So which approach should you use?

Slide 67

Slide 67 text

It depends.

Slide 68

Slide 68 text

Broadly: Profiles are better architecture

Slide 69

Slide 69 text

But: there’s a cost

Slide 70

Slide 70 text

Where to draw the line for the hybrid models?

Slide 71

Slide 71 text

One more thing...

Slide 72

Slide 72 text

How does it all work?

Slide 73

Slide 73 text

THE FOLLOWING SLIDES WILL SELF DESTRUCT AFTER THIS PRESENTATION

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

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.

Slide 76

Slide 76 text

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

Slide 77

Slide 77 text

No content

Slide 78

Slide 78 text

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