auth.User: The abstract base class idea

347 views
Skip to first unread message

Alex Ogier

unread,
Mar 20, 2012, 11:25:10 AM3/20/12
to django-d...@googlegroups.com
There have been various proposals about replacing the User class with
an abstract base class. Ian Lewis has a semi-workable version at
http://ianlewis.bitbucket.org/django-newauth/index.html but its
proposal met with resistance in part because there's not a great
migration path from existing apps. I recently attended a Boston-area
python meetup, and met James Sullivan and Max Thayer, two of the guys
behind www.matchbox.net. We came up with a similar solution to Ian's,
but with a better path away from the status quo. Here's our flavor of
the abstract base class, based on the needs we see in other threads.

Starting from a basic set of premises:

1. People want to rip out auth.User’s authentication strictures
(username, email, password)
2. People want to plug in fields via distribution of apps, not just in
one project-wide user table
3. People want to depend on auth.User, by foreign key mostly
4. For the foreseeable future, by default auth.User has to map to its
old DB table

Here’s the clear winner for me: Make auth.User a subclass of an
abstract base class. It seems no one minds the whole auth permissions
thing sticking around even if it goes unused (if it ain’t broke don’t
fix it), so leave all that on auth.User and move everything else to
auth.DefaultUser, which is a class with Meta.abstract = True. Have
auth.User inherit from DefaultUser by default, with a setting to
override that with your own class(es). Languages like Ruby do this
with mixins, we do it with
https://docs.djangoproject.com/en/dev/topics/db/models/#multiple-inheritance

There are definitely some cons:

1. Requiring classes and settings to be available at the time of
definition of auth.User means circular dependencies are a problem.
2. Multiple inheritance is wonky and confusing in python, and only a
hackish sort of standin for mixins.
3. In the absence of a way to override fields (something that might be
added later?), you can’t subclass DefaultUser hoping to change a
default field, you can only add fields or reimplement the whole thing.
Thankfully that would be much easier.

But still the benefits are pretty large:

1. No changes to existing applications.
2. The common case of adding fields to users is easier even than
profiles: subclass DefaultUser, add your stuff, change a setting. No
get_profile() or select_related mumbo-jumbo.
3. The second use-case of ripping out auth.User’s broken assumptions
is possible: rewrite DefaultUser in your project.
4. The third use-case of plugging app mixins into the User model is easy.
5. The migration path is easy. You can incrementally step away from
the default user model, and (assuming running your migration framework
on a django.contrib app doesn’t blow up somehow) you can take
advantage of migrations without requiring them.
6. When you change fields, you break only the stuff that depends on
them. If you remove the username field, then half the default forms
stop working, but there’s no reason for auth middleware to break, etc.

Anyways, asides for circular dependency edge cases I think the rest of
the downsides can be mitigated by good docs. What do you guys think?

-Alex Ogier

P.S. I hear you are accepting GSOC applications.

Donald Stufft

unread,
Mar 20, 2012, 11:27:23 AM3/20/12
to django-d...@googlegroups.com
--
You received this message because you are subscribed to the Google Groups "Django developers" group.
To post to this group, send email to django-d...@googlegroups.com.
To unsubscribe from this group, send email to django-develop...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.
This is pretty much exactly what django-primate does, except it includes a special metaclass to allow
overriding of default fields.

Alex Ogier

unread,
Mar 20, 2012, 12:00:59 PM3/20/12
to django-d...@googlegroups.com
> This is pretty much exactly what django-primate does, except it includes a
> special metaclass to allow
> overriding of default fields.

Yeah, that is the basic idea. I think that permissions and associated
code should be moved from UserBase to live directly on auth.User or in
a mixin of their own (they are mostly orthogonal to authentication,
yes?) so that writing one's own base user is easier, but the
monkey-patch looks like it is implemented in a nice way. So long as
writing your own base is easy enough, the extra special-case metaclass
and field overriding isn't strictly necessary, and can wait until
explicitly overriding fields has proper support in core (something I
think will be generally useful).

-Alex Ogier

Alex Ogier

unread,
Mar 21, 2012, 10:33:19 PM3/21/12
to django-d...@googlegroups.com
I made a topic branch and refactored everything I thought was nicely reusable from auth.User into abstract models in django/contrib/auth/mixins.py. There are some good reusable pieces inside auth.User, even if you want to entirely scrap Django's notion of identity and the username and/or email fields. The change is transparent to Django's test suite, and I did my best to leave the existing API identical.

My hope is that we can make, for example, contrib.admin only dependent on a class implementing PermissionsMixin. Whether we do late binding to auth.User with some jiggery-poker as described in the recent auth.User reboot thread, load time plugging into the auth.User inheritance list as I proposed in the first email in this thread, or just punt on the whole thing and ask people to implement their own concrete classes, I think the refactoring is a nice backwards-compatible way to expose pieces of auth.User for people to reuse and/or depend on.


Does anyone have any opinions?

-Alex Ogier

bhuztez

unread,
Mar 22, 2012, 8:56:25 AM3/22/12
to Django developers
Maybe we could make every model pluggable. so User model could be
defined like this:

class User(models.Model):
__mixins__ = load_available_mixins(settings.AUTH_MODEL_MIXINS)


But AFAICS, Django will suffer from the same issue as PHP
register_globals / Rails mass-assignment, because of ModelForm. and
Django must provide schema migration tools.

Mateusz Marzantowicz

unread,
Mar 22, 2012, 12:49:21 PM3/22/12
to django-d...@googlegroups.com
It looks OK, but there is one really big issue with your approach - database blowup.
You can easily choose mixins to compose your User model, but once it's done your database layout is fixed.
If you then decide to use different mixins - it would be impossible without very smart db schema migration tool.


Mateusz Marzantowicz

Alex Ogier

unread,
Mar 22, 2012, 1:04:43 PM3/22/12
to django-d...@googlegroups.com
It looks OK, but there is one really big issue with your approach - database blowup.
You can easily choose mixins to compose your User model, but once it's done your database layout is fixed.
If you then decide to use different mixins - it would be impossible without very smart db schema migration tool.

Any schema migration tool that reuses django's ORM *should* be OK. For example, South works just fine. Adding or removing a mixin is exactly like adding or removing the fields in that mixin as far as the ORM is concerned. If we end up patching the User model in-place, then the tool will have to be able to operate on models in contrib apps which might be in read-only locations or shared locations, but this has been on the radar of most migration tools for a while already. For example, South has the SOUTH_MIGRATION_MODULES setting to handle this.

-Alex Ogier

Matteius

unread,
Mar 23, 2012, 6:53:57 PM3/23/12
to Django developers
I agree on both this point and your future point about using a
migration tool such as South (and South is truly the only one I can
think of that will do this painlessly). We definitely suffer from
these User model problems at our Company as does everyone I think that
really uses Django's authentication system for that. These
suggestions seem the most sound all things considered and the original
list of points makes a strong argument for it. I would like to see
this sooner than later. How many more releases go by? Hopefully its
in by 1.5 ,,,
Reply all
Reply to author
Forward
0 new messages