| 237 | == Solution 5: Profile-based single user model |
| 238 | |
| 239 | After reviewing proposals 1-4 on this list, Jacob indicated that he was uncomfortable with the idea of 'swappable' models (driven at least in part by lessons learned from Django's own history), and so he came up with an alternate proposal. This proposal suggests migrating towards a single, absolutely minimalist User model, with Profile objects being used to store any additional information. The full proposal is laid out in detail here https://gist.github.com/2245327 , but as a brief summary: |
| 240 | |
| 241 | The user model becomes something like: |
| 242 | {{{ |
| 243 | class User(models.Model): |
| 244 | identifier = models.CharField() |
| 245 | password = models.CharField() |
| 246 | }}} |
| 247 | |
| 248 | `identifier` is included because it's required by 99% of User models; `password` is included as an active discouragement to people reimplementing (badly) their own password authentications schemes. There is still some discussion as to whether identifier should be unique and/or indexed by default. |
| 249 | |
| 250 | Other user information -- name, staff/admin flags, permissions and so on -- are stored on profile models that are linked 1-1 with the User model. In order to make it easier to transition to the new user model, and to avoid coupling to specific profile models, the User model may also implement a delegate pattern for other user attributes. For example, the 'display name' for a user won't be defined by the User object itself; it will be serviced by one of the profile objects associated with the User, but you'll be able to request user.display_name to retrieve the name. |
| 251 | |
| 252 | Along the way, we'll also deprecate AUTH_USER_PROFILE and user.get_profile(), reflecting the fact that there isn't a single "profile" anymore. |
| 253 | |
| 254 | === Advantages === |
| 255 | |
| 256 | * There is a single canonical user model. There's no need for a swappable anything, or Foreign keys that point to dynamic models. This means the properties of the User object are reliable and consistent between projects. Inconsistencies only arise between uses of Profile objects. |
| 257 | |
| 258 | * It makes almost no judgements about what a User should have on it. All such decisions are made by the developer by implementing an appropriate Profile object. |
| 259 | |
| 260 | === Problems === |
| 261 | |
| 262 | * There is a *huge* migration task, since all existing User tables need to be migrated to the new profile-based format. However, we would be moving from one known format (old auth.User) to another well known format (new auth.User plus admin.!UserProfile), so the migration script will be reasonably predictable. When combined with delegated attributes, it should be possible to have a migration path that has all the usual warnings etc. |
| 263 | |
| 264 | * It requires joins to get to anything other than the core User data. There is some argument as to whether this is primarily a technical limitation or a social one. Mailing list discussions have indicated a preference by some people for a monolithic User object, avoiding the need for joins when retrieving user data. Although technical reasons are usually given for this preference (usually, "joins are evil"), it isn't clear that this is a a problem in practice -- at least to the extent that we should be basing the entire design around accommodating sites that area actually experiencing those problems. |
| 265 | |
| 266 | * If a new profile model is added to an existing project, new profile objects need to be instantiated for any existing User object. This is the analog of the problem in the "swappable-user" case; if the User model is modified, there is a migration task to make sure that the database User matches the code definition. |
| 267 | |
| 268 | * There are still some issues to resolve around the handling of the delegate attributes: |
| 269 | - Should profiles be auto-select-related? |
| 270 | - Should profiles be auto-created if they are missing? If a profile has a required field and it is auto-created, how will that field be filled in? |
| 271 | - How do we determine which profile will service an attribute if both provide an implementation (e.g., two profiles define a display_name attribute -- which display name is used? First registered? Last registered? How is the registration determined? etc) |
| 272 | |
| 273 | * Form handling for the new User object -- especially !ModelForm handling -- hasn't been fully elaborated. |
| 274 | |