Opened 18 years ago
Closed 12 years ago
#3011 closed New feature (fixed)
Allow for extendable auth_user module
Reported by: | nowell strite | Owned by: | nobody |
---|---|---|---|
Component: | contrib.auth | Version: | |
Severity: | Normal | Keywords: | auth_user |
Cc: | say4ne@…, bram@…, mike.lopez@…, osborn.steven@…, michael@…, simon@…, treborhudson@…, goliath.mailinglist@…, hanne.moa@…, michal@…, Marinho Brandão, ville@…, sylvaintersideral@…, David Larlet, dan@…, waylan@…, albrecht.andi@…, nreilly@…, tomasare@…, youngj@…, richard@…, Sergio Oliveira, Alexander Koshelev, Simon Law, Robin, ramusus@…, stv@…, tinodb@…, Dan Fairs, miracle2k, msaelices@…, mmitar@…, anball@…, remco@…, tom@…, Francis Devereux, Walter Doekes, German M. Bravo, tgecho, hwaara@…, chris+django@…, alex@…, lancelotj, drdee, jeverling@…, honyczek@…, j.arnds@…, mindsocket, sergzach, jeroen@…, Ivan Virabyan | Triage Stage: | Accepted |
Has patch: | yes | Needs documentation: | yes |
Needs tests: | yes | Patch needs improvement: | yes |
Easy pickings: | no | UI/UX: | no |
Description
I have been using the AUTH_PROFILE_MODULE setting paired with the get_profile() feature of the Django auth system and have run into many cases where it would be nice to directly access extra arbitrary user information without having to call get_profile() for each record.
I have patched my Django installation (with the attached .diff) to allow the developer to provide their own auth_user module, with the requirement that any developer created user model contains the base fields provided by the default auth_user model. This not only allows you to continue to use the build-in Django admin modules that rely on the auth_user system, but it allows you to store information like a users address, or override the username field to accept emails, etc.
My solution to this problem involves a few things
- Adding a settings AUTH_USER_MODULE that specifies the path to the custom auth_user model. (i.e. 'myproj.apps.users.models.User')
- Moving the existing User class out of the ./django/contrib/auth/models.py into a subdirectory './django/contrib/auth/users/models.py' that will not automatically be registered as a model when someone adds the 'django.contrib.auth' module to their INSTALLED_APPS. The AUTH_USER_MODULE setting in global settings points to this class by default 'django.contrib.auth.users.models.DefaultUser'
- Creating a UserTemplate class that every user auth system must inherit from. This ensures that the default functions (like check_password, has_permission, etc.) are available (all of which can be overridden in the custom User class.
Attachments (16)
Change History (139)
comment:1 by , 18 years ago
Type: | defect → enhancement |
---|
by , 18 years ago
Attachment: | auth_user_module.diff added |
---|
by , 18 years ago
Attachment: | auth_user_module2.diff added |
---|
updated patch, fixes typo in previous file
by , 18 years ago
Attachment: | auth_user_module3.diff added |
---|
Bugfix: This version plays nicely with syncdb and works with the django.db.models.loading.get_model(....)
comment:3 by , 18 years ago
Has patch: | set |
---|---|
Needs documentation: | set |
Needs tests: | set |
Patch needs improvement: | set |
Triage Stage: | Unreviewed → Accepted |
Cool, I didn't know this ticket existed. This was something I have been wanting to do but never found the time.
Thanks for the patch, I think you are headed in the right direction. I would say most of the existing methods that were left in UserTemplate should move along with the User model though. Take set_password
for example, this would only work for a user model with a password
attribute. By default, set_password
should do nothing. Other methods like get_absolute_url
and is_authenticated
could stay since they would be sensible defaults the way they exist now.
Marking this as accepted as this has been a highly desired feature for quite a while.
comment:5 by , 17 years ago
Cc: | added |
---|
by , 17 years ago
Attachment: | 3011.3.diff added |
---|
oh sorry, my previous patch was against newforms-admin branch, here's the patch against trunk [6023]
comment:7 by , 17 years ago
Cc: | added |
---|
Email, rather than username, certainly seems to be the standard these days for web authentication. Problem is, the User model only gives us a 30 character primary key field to work with.
I'm a big +1 for any improvement that would allow us to easily use our own model in place of the User model.
comment:8 by , 17 years ago
Cc: | added |
---|
I'm +1 on this. It would be extremely useful to have custom user models especially when dealing with things like openid.
comment:9 by , 17 years ago
Cc: | added |
---|
+1. This would be great. What does it need to be included? Tests? Docs? How can we help?
comment:11 by , 16 years ago
Cc: | added |
---|
Funny I found this ticket (again). This is something I wanted to add to django for ages now, but going an rather radical approach. Instead of just being able to plug another User-model in I decided it would be nice to create a modular auth-framework, which lets you replace the permission-system as well, as I think "auth" are two parts: AUTHentication (who is requesting a page) and AUTHorization (may he request that page).
I filed a bug about this, too (#3669)...but it got closed (duplicate of this here). So - because it looks like things are getting forward here - I just wanted to get some discussion up again about this.
What do you think about going one step further and also create a modular permission system? What I implemeneted so far is a simple hook-system, using some ideas of the generic-auth-branch.
Would it be possible to make it a user-choice to include (or exclude) thinks like the existing permission, group and message-models in auth or even replace this parts, too?
Perhaps there can be shared some code or ideas? Some outdated code is available at https://svn.webmasterpro.de/django-auth-rewrite/
Anyway, I'm +1 for getting this integrated of course. ;-)
comment:12 by , 16 years ago
+1
I'd like abstract models for permissions, groups and the admin stuff (is_superuser, is_staff, ..). Don't require any particular fields (auth backends may provide suitable mixins).
Something like the following would then be equivalent to the current User
implementation:
from django.contrib.admin import AdminUserMixin from django.contrib.authorization import UserWithGroupMixin, UserWithPermissionsMixin from django.contrib.auth.backends.model import ModelBackendUserMixin class User(UserWithPermissionsMixin, UserWithGroupMixin, AdminUserMixin, ModelBackendUserMixin): first_name = models.CharField(_('first name'), max_length=30, blank=True) last_name = models.CharField(_('last name'), max_length=30, blank=True) email = models.EmailField(_('e-mail address'), blank=True) last_login = models.DateTimeField(_('last login'), default=datetime.datetime.now) date_joined = models.DateTimeField(_('date joined'), default=datetime.datetime.now) ...
(Not thought through:
ModelBackendUserMixin
could be a factory: class User(ModelBackendUserMixin(identity='email', password='password'))
, or would a metaclass solution be nicer ..)
comment:13 by , 16 years ago
Cc: | added |
---|
by , 16 years ago
Attachment: | 3011.4.diff added |
---|
Brought proposed patch up to trunk and moved some methods around; added stub documentation.
by , 16 years ago
Attachment: | 3011.5.diff added |
---|
Last patch didn't include django/contrib/auth/default_user.py, which is where the, er, well, default user lives. Kind of important.
comment:15 by , 16 years ago
Cc: | added |
---|
by , 16 years ago
Attachment: | 3011.6.diff added |
---|
Patch against [7832] and added a quick fix so that apps like contenttypes wouldn't think that the imported module was part of contrib.auth.
comment:16 by , 16 years ago
So there are several major issues here, probably the largest being how we can make this integrate with the admin interface (perhaps we should be doing this on newforms-admin?) and current generic apps.
I would like to find a way to make it dynamic rather than just saying, "Oh, you're using your own user model, sorry you're SOL if you want to use this and this and this."
I'm also in now way sure that the current method of doing it is the proper one, but now that the diff is current we can at least figure out where to go from here.
Anybody volunteering or have any ideas?
comment:17 by , 16 years ago
Cc: | added |
---|
comment:18 by , 16 years ago
I like the idea of duck typing. If your provided user model has x, y, and z fields or properties, and X, Y, and Z methods, then the default admin and other apps will accept it and use it as if it were the default. That way, if you want your own model to be used by the admin, you make sure those properties and methods are available and work. We can even provide an AuthUserTemplate that have stubs that raise a NotImplementedError. (I don't know what you normally do for the properties though.) Similar to how the HttpResponse method has checks for _is_string, I can imagine that the user module loading mechanism checks these properties and fields and adds a _is_auth (or something) that the various other subsystems can check against.
comment:19 by , 16 years ago
So, this one will get a little shorter, I way right through with my comment when firefox crashed...great.
What I did, when trying to solve this (see #comment:11) was to strip down django.contrib.auth to only provide some generic API for all common auth-related stuff. So django.contrib.auth would only provide some API, which functions/methods just wraping the real functions/methods provided by the module(s) defined in django.settings. Additionally I was able to split the rest of django.contrib.auth into separate applications, so django got independent modules for users (auth_user) and permissions (auth_model_perm), but is not limited to this applications (for example groups could get its own application or the whole auth-backends-system could get its own user-application, removing the need of supporting backends in the main auth_user-application). Users could then use the django-users in combination with some self-written permission-system (supporting object-level-permissions for example), or do it the other way round (thats what the current patch provides).
However my code was never ready and did not solve every problem, first of all when dealing with backwards compability. I tried to set sane defaults (current applications as default selected modules) and provide support for old code, like imports (from django.contrib.auth.models import User), but thats only the tip of the iceberg.
But I think the direction my approach went was not all bad, it provided the developer with an API for all auth-related stuff and supported him with sane defauls (thats what the current auth-application does). Anyway someone could replace this with its own implementation while keeping third-party applications supported (google code lists many projects, many of them use django.contrib.auth some way), even for permission tasks (thats something generic-auth tried to solve).
Of course there needs to be some work done to provide some defaults (e.g. users should at least be displayable in templates using {{ user|escape }}), but not everything is really needed. For example the message-system is nice, but most applications won't use it. Perhaps a cleanup of the auth-application could make this optional and provide some simple way to test for message-support in third-party-applications (if hasattr(request.user, 'send_message')?). But that would be post-1.0. ;-)
(And btw: I really like the idea of using mixins here)
comment:20 by , 16 years ago
Cc: | added |
---|
comment:21 by , 16 years ago
Cc: | added |
---|
comment:22 by , 16 years ago
patch number 6 won't work if you don't override the user model. I guess it needs to conditionally delete the entry.
comment:24 by , 16 years ago
Cc: | added |
---|
comment:25 by , 16 years ago
My current change includes making UserTemplate abstract, and setting db_table = "auth_user" on DefaultUser. This should ensure that this patch doesn't change default installation table names. I haven't verified that yet though.
comment:26 by , 16 years ago
Cc: | added |
---|
comment:27 by , 16 years ago
Cc: | added |
---|
comment:28 by , 16 years ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
This is great. Just what I've been looking for. Can we change the name of the settings variable, though? I think good naming is really important, and calling it AUTH_USER_MODULE when it doesn't name a module is a bad idea. Can we call it AUTH_USER_MODEL instead?
comment:29 by , 16 years ago
Uh oh... I just submitted a comment and left everything else set to the defaults, which appears to have inadvertently changed the ticket state. Can someone undo that?
comment:30 by , 16 years ago
Cc: | added |
---|
comment:31 by , 16 years ago
Cc: | added |
---|
comment:32 by , 16 years ago
Cc: | added |
---|
comment:33 by , 16 years ago
Cc: | added |
---|
comment:34 by , 16 years ago
Cc: | added |
---|
comment:35 by , 16 years ago
Cc: | added |
---|
comment:36 by , 16 years ago
Cc: | added |
---|
comment:37 by , 16 years ago
After reviewing your patch, I just wonder why don't you put default fields and methods in the abstract TemplateUser class? This way, you don't have to copy/paste most of the content of User class in your custom one and you can still override some of them with your own if you want. Make sense?
ps: maybe AbstractUser is more descriptive than TemplateUser?
comment:38 by , 16 years ago
Cc: | added |
---|
follow-up: 40 comment:39 by , 16 years ago
Cc: | added |
---|
comment:40 by , 16 years ago
comment:41 by , 16 years ago
Too bad that it has been rejected for "too many potential downsides" from 1.1 roadmap http://code.djangoproject.com/wiki/Version1.1Features
What's the status of the latest patch? Is there somebody still active on this feature?
follow-up: 43 comment:42 by , 16 years ago
Strange development, that. I thought I was paying close attention to the 1.1 process, this feature getting +0 and then one -1 so I expected it to be deferred. I can't find any list of the many potential downsides anywhere, and the comment to the guy who set it -1 seemed like a comment to a -0-feature so I thought it was just a goof...
The "many potential downsides" ought to be listed here, anyway.
follow-up: 44 comment:43 by , 16 years ago
Replying to HM:
Strange development, that. I thought I was paying close attention to the 1.1 process, this feature getting +0 and then one -1 so I expected it to be deferred.
More than one -1 now (from http://spreadsheets.google.com/ccc?key=pSqnCvef6OXmGWQ9qbEVMeA):
- AH: Any sort of framework-in-the-framework like this makes me suspicious, and the implementation and design would have to be incredibly solid.
- JB: Doesn't affect me one way or another.
There's also one +1, from GW.
But from this to "too many potential downsides"? *scratches head*
comment:44 by , 16 years ago
Replying to HM:
But from this to "too many potential downsides"? *scratches head*
You might want to take a look at this #django-dev IRC channel log for a related discussion: http://oebfare.com/logger/django-dev/2008/11/25/1/#17:32-977590
follow-up: 48 comment:45 by , 16 years ago
Cc: | added |
---|
So, what's going to happen with this ticket? It's on the list of ideas for Summer of Code 2009.
We really need this feature and we'd like to have an officially supported API for this. Django's default user comes with first_name and last_name which is too specific for us. We only have full_name and calculated @property for first_name and last_name. Also, we don't have usernames. In a lot of cases email is sufficient, so why should the user bother about inventing a username? Of course, this means that in our case email should be a required and unique field.
Moreover, code that uses get_profile() is just more annoying to write and you have to call select_related(). It's much easier to have all user fields in the User model. Our code has definitely become easier to work with since we eliminated the profile model and put everything into the User.
In our app-engine-patch project (a Django port to App Engine) we have something similar:
http://code.google.com/p/app-engine-patch/wiki/CustomUserModel
We also allow for overriding the AnonymousUser (which sometimes needs additional attributes, too).
Now that I think about it, the AUTH_ADMIN_MODULE stuff isn't necessary because you can easily register this in some other app's admin.py.
comment:46 by , 16 years ago
One thing I'll note for this is that with the new managed option it's very easy to make these pure python changes in your own code.
comment:47 by , 16 years ago
And how would I replace the User model using that managed option without modifying the auth app?
follow-up: 49 comment:48 by , 16 years ago
Replying to wkornewald:
We really need this feature and we'd like to have an officially supported API for this. Django's default user comes with first_name and last_name which is too specific for us. We only have full_name and calculated @property for first_name and last_name. Also, we don't have usernames. In a lot of cases email is sufficient, so why should the user bother about inventing a username? Of course, this means that in our case email should be a required and unique field.
Moreover, code that uses get_profile() is just more annoying to write and you have to call select_related(). It's much easier to have all user fields in the User model. Our code has definitely become easier to work with since we eliminated the profile model and put everything into the User.
There are more fundamental flaws in the current approach. For example one might need to have AnonymousUser saved in the database, which normalized the way permission control works (permissions for the AnonymousUser can be saved to the database).
One bit problem I see with the current contrib.auth-module is, that it combines different things. There is no need to put code for authorization (who is accessing the page?) and authentication (is someone allowed to access something?) into the same app. I would prefer having these things in different applications so they could be replaced separately. contrib.auth could provide some kind of generic API for accessing these new applications. Having all of these different apps combined in contrib.auth makes redesigning these thing much more complicated. Perhaps a first step might be creating independent apps here.
comment:49 by , 16 years ago
Replying to David Danier <goliath.mailinglist@gmx.de>:
There are more fundamental flaws in the current approach. For example one might need to have AnonymousUser saved in the database, which normalized the way permission control works (permissions for the AnonymousUser can be saved to the database).
One bit problem I see with the current contrib.auth-module is, that it combines different things. There is no need to put code for authorization (who is accessing the page?) and authentication (is someone allowed to access something?) into the same app. I would prefer having these things in different applications so they could be replaced separately. contrib.auth could provide some kind of generic API for accessing these new applications. Having all of these different apps combined in contrib.auth makes redesigning these thing much more complicated. Perhaps a first step might be creating independent apps here.
I like that. Moving out the permission system would also be very useful for an App Engine port because the current Permission model complicates queries unnecessarily. You can as well just store a string like "auth.can_delete" (or a whole list of such strings) which allows for much more efficient querying on non-relational DBs. This works very well in app-engine-patch.
comment:50 by , 16 years ago
Design discussion in bug tickets is a really bad place, since you won't reach the right audience. We have a mailing list (django-dev) for that, please use it. be aware, though, that now (as we're entering the push to get 1.1 out the door) is not a great time for getting a lot of attention on new designs, so be prepared to raise it again in the ealry 1.2 period.
follow-up: 52 comment:51 by , 16 years ago
Cc: | added; removed |
---|
What about the new proxy Meta attribute? Did someone try to extends a User for real with it? http://docs.djangoproject.com/en/dev/topics/db/models/#proxy-models
comment:52 by , 16 years ago
Replying to david:
What about the new proxy Meta attribute?
I think this may help with some of the problems described here, at least some of the problems that are avoidable in pure python. Many of these things can be worked around using the advantages a dynamic language like python provides, too. For example someone could just import User and then do somethink like:
User.my_new_method = lambda self: self.something_i_want_to_do_here
This may not be as clean as using some proxy-class, but works fine and has the advantage of not needing to import some "other" user.
As said above I see more fundamental flaws in current contrib.auth. One might be that you have no clean way to replace AnonymousUser (and put it into the database for example). Another is the combination of four or five different applications into contrib.auth (authentication, authorization, groups, messages, permissions) which goes against everything you try to teach new django-users when creating applications and makes creation of new applications for only parts of this more complicated.
There are other tickets adressing some of these issues, see #4604 for example. You may also notice, that the current patch tries to put a combination of session and user-based messages into the template context. This really would not be necessary if you could just choose between two decoupled message-apps.
@mtredinnick: I'm not sure if restructuring the whole contrib.auth-app would be appropriate in 1.x anyway, so perhaps this is something that needs to be done for some 2.x-version. I will perhaps raise this issue on the mailinglist again, when 1.2 is released.
comment:53 by , 16 years ago
Cc: | added |
---|
comment:54 by , 16 years ago
Cc: | added |
---|
follow-up: 56 comment:55 by , 16 years ago
Cc: | added |
---|---|
Owner: | changed from | to
Status: | assigned → new |
The patch above implements the UserTemplate keeping the original User but using an abstract model. This implementation it's not so flexible but it keeps the compatibility with 1.0 versions. Even if this patch it's not what we are looking for I'd like to the this ticket.
follow-up: 57 comment:56 by , 16 years ago
Status: | new → assigned |
---|
Replying to seocam:
The patch above implements the UserTemplate keeping the original User but using an abstract model. This implementation it's not so flexible but it keeps the compatibility with 1.0 versions. Even if this patch it's not what we are looking for I'd like to the this ticket.
to get this ticket*
follow-up: 58 comment:57 by , 16 years ago
Replying to seocam:
Replying to seocam:
Even if this patch it's not what we are looking for I'd like to the this ticket.
to get this ticket*
I like to have some fix for this in Django, too....but I see one major downside on the approach of patching everything together to support these things: If you look at my proposal above you may agree, that - for example - having AUTH_BACKENDS is not neccessary to support different backends. One could just implement some kind of LdapUser-Model (which only has fields, that are really needed for LDAP) and use this. You can say similar things about AUTH_PROFILE_MODULE, which would be not neccessary any more.
So perhaps instead of creating an continuous growing contrib.auth-module it would be a good idea to concentrate on replacing it by something that reduces the overall overhead (in code and management). For me it looks like currently many things get patched in whithout getting down to the real problems and by providing many half-ready solutions on the road down to a flexible authentication system.
Why half-ready? AUTH_PROFILE_MODULE is a good example here. You may use user.get_profile() to load the profile for a particular user. But there is no way to auto-create the profile for new users (like get_or_create()). So you have to write your own register-view to get this working, or use some other way to work around this (I think there is some closed ticket for this, too).
follow-up: 60 comment:58 by , 16 years ago
I like to have some fix for this in Django, too....but I see one major downside on the approach of patching everything together to support these things: If you look at my proposal above you may agree, that - for example - having AUTH_BACKENDS is not neccessary to support different backends. One could just implement some kind of LdapUser-Model (which only has fields, that are really needed for LDAP) and use this. You can say similar things about AUTH_PROFILE_MODULE, which would be not neccessary any more.
So perhaps instead of creating an continuous growing contrib.auth-module it would be a good idea to concentrate on replacing it by something that reduces the overall overhead (in code and management). For me it looks like currently many things get patched in whithout getting down to the real problems and by providing many half-ready solutions on the road down to a flexible authentication system.
Why half-ready? AUTH_PROFILE_MODULE is a good example here. You may use user.get_profile() to load the profile for a particular user. But there is no way to auto-create the profile for new users (like get_or_create()). So you have to write your own register-view to get this working, or use some other way to work around this (I think there is some closed ticket for this, too).
I agree that the AUTH_PROFILE_MODULE is a half-ready solution, and I know that the patch I'm proposing it's not a final solution as well, but I can't see any solution which don't break the backwards compatibility and would fix everything here.
Also add a feature that we already know it's going to be deprecated it's not a good idea either.
So the idea here is have a long term solution which provides more much flexibility. I'll try to create a draft spec based on what I've read until now, and as soon as a have something I'll send in the list.
comment:59 by , 16 years ago
I'd also love to see a username option with this. ie The ability to use the email as username.
follow-up: 61 comment:60 by , 16 years ago
Replying to seocam:
[...] , but I can't see any solution which don't break the backwards compatibility and would fix everything here.
I would suggest adding some kind of contrib.newauth (like newforms) and keeping the old contrib.auth for some time (until 2.0?). One problem I see with this would be foreign keys, but perhaps we could provide some (hackish) workaround for this.
So the idea here is have a long term solution which provides more much flexibility. I'll try to create a draft spec based on what I've read until now, and as soon as a have something I'll send in the list.
Perhaps we could put up a wiki-page to work on this proposal. I would like to write down some ideas, too. ;-)
comment:61 by , 16 years ago
Replying to David Danier <goliath.mailinglist@gmx.de>:
I'm using the patch (might have tweaked it slightly), and without setting an override Django works as before. I'm just about to put the patch on GitHub git://github.com/thepian/django.git
I've been thinking that a general model override mechanism would be preferable, I'm not sure what the best approach would be.
I'll be at Euro DjangoCon if you want to discuss this.
comment:62 by , 16 years ago
Cc: | added |
---|
comment:63 by , 16 years ago
comment:64 by , 16 years ago
Cc: | added |
---|
comment:65 by , 15 years ago
Cc: | added |
---|
comment:67 by , 15 years ago
Cc: | added |
---|
comment:68 by , 15 years ago
Cc: | added |
---|
Maybe you can inspire in the API design of authentication and authorization module in Nette Framework. I think, it's designed enough abstract and with huge practical view http://api.nettephp.com/0.9/li_Nette-Security.html and http://api.nettephp.com/0.9/Nette-Web/User.html However, storage for credentials, permissions, user profile etc. is not implemented in this API. It could be in database or anywhere else.
comment:69 by , 15 years ago
Cc: | added |
---|
comment:71 by , 15 years ago
I use the function get_user_model() which reads from a setting what user-model to use. Then instead of
from django.contrib.auth.models import User ... user = models.ForeignKey(User...
I do
User = get_user_model() ... user = models.ForeignKey(User...
The apps using the user-model must not have conflicting needs of course, but we are after all using Python and are all consenting adults, right? No need for handcuffs and bullet-proof contracts.
comment:72 by , 15 years ago
Cc: | added |
---|
comment:73 by , 15 years ago
Cc: | added |
---|
follow-up: 75 comment:74 by , 15 years ago
How about doing exactly what the contrib.comments
app does?
Provide:
contrib.auth.get_model
contrib.auth.get_registration_form
- etc.
comment:75 by , 15 years ago
Replying to patrys:
How about doing exactly what the
contrib.comments
app does?
Provide:
contrib.auth.get_model
contrib.auth.get_registration_form
- etc.
I tried extending contrib.comments
as per those functions and etc., and wound up writing my own from scratch. When one does not want, under any circumstance whatsoever until the heat-death of the universe, a non-authenticated non-authorized person to ever leave a comment, it just can't be built around.
Better to remove complexity than pile on another layer.
comment:76 by , 15 years ago
HM:
Should be as easy as pointing get_form_target
to the classic view decorated with @login_required
or even @user_passes_test
.
comment:77 by , 15 years ago
Cc: | added |
---|
comment:78 by , 14 years ago
Cc: | added |
---|
comment:79 by , 14 years ago
Cc: | added |
---|
comment:80 by , 14 years ago
Cc: | added |
---|
comment:81 by , 14 years ago
Cc: | added |
---|
comment:82 by , 14 years ago
Component: | Contrib apps → contrib.auth |
---|
comment:83 by , 14 years ago
Severity: | normal → Normal |
---|---|
Type: | enhancement → New feature |
by , 14 years ago
Attachment: | #3011-extendable auth_user.diff added |
---|
comment:84 by , 14 years ago
I found the current patch produces a bug if used alongside the contrib.admin
app under certain circumstances when the new User model has foreign key fields with lazy relations to other app models. This problem arises since those models are still unresolved when django later attempts to import the INSTALLED_APP
modules, while fetching the locales during the creation of the languages translation object, at that point, while importing the admin
app, contrib/admin/__init__.py
tries to import contrib.admin.sites
, which results in the importing of AuthenticationForm
... __new__()
then tries to use formfield()
on the User's available fields for the User model, but since those foreign key fields still contain unresolved strings, it throws an exception (AttributeError: 'str' object has no attribute '_default_manager'
). I'm attaching a new patch which fixes this issue.
comment:85 by , 14 years ago
Easy pickings: | unset |
---|
Kronuz: I too ran into this. Kept hitting the error, cannot import name 'actions' in the admin whenever running createsuperuser, or custom mgmnt commands that relied on User.
Your patch resolved this issue for me, but I had to change one line. Specifically the getattr(auth_user_module, auth_user_module_parts[0]) was failing because the attribute couldn't be found.
Importing the '.modules' resolved it:
auth_user_module = __import__(auth_user_module_parts[0] + '.models', fromlist=['dummy'])
comment:86 by , 14 years ago
Easy pickings: | set |
---|
follow-up: 88 comment:87 by , 14 years ago
Easy pickings: | unset |
---|
With all due respect, this isn't easy at all.
comment:88 by , 14 years ago
Replying to jezdez:
With all due respect, this isn't easy at all.
I thought I unset it on accident, it's definitely not easy.
comment:89 by , 13 years ago
Owner: | changed from | to
---|---|
Status: | assigned → new |
UI/UX: | unset |
comment:90 by , 13 years ago
Cc: | added |
---|
comment:91 by , 13 years ago
Cc: | added |
---|
comment:93 by , 13 years ago
Cc: | added |
---|
comment:94 by , 13 years ago
Cc: | removed |
---|
comment:95 by , 13 years ago
Cc: | removed |
---|
comment:96 by , 13 years ago
Cc: | removed |
---|
comment:97 by , 13 years ago
Cc: | added |
---|
comment:98 by , 13 years ago
Cc: | added |
---|
comment:99 by , 13 years ago
Cc: | removed |
---|
comment:100 by , 13 years ago
Cc: | removed |
---|
comment:101 by , 13 years ago
Cc: | removed |
---|
comment:102 by , 13 years ago
There are problems some times when you need to import the UserTemplate
(circular imports) ...for this reason, I split the file to put the models in a new file called base.py
(perhaps abstract.py
could be a better name) and left the model.py
file to be only for the creation of the default User
from the template, or loading of the custom User
model class from some other module (as set up in AUTH_USER_MODULE
, which should be a string in the form: custom_auth.models.User
) The custom user model could (and maybe should) have the abstract contrib.auth.base.UserTemplate
model as its base. I believe we could also have a BaseUserAbstractModel
in addition to (or instead of) `UserTemplate.
I'm attaching the patch now.
by , 13 years ago
Attachment: | #3011-extendable_auth_user.diff added |
---|
comment:103 by , 13 years ago
This solution it's not perfect... I know, but it works well for me and others... so I updated it to work with both django 1.3 and 1.4. What I currently changed from the past versions of the patch is that AUTH_USER_MODULE
now works more like AUTH_PROFILE_MODULE
, where you supply the app_label
and model
, and not the full python import to the model (i.e. it now expects custom_auth.User
instead of custom_auth.models.User
). Custom User
models should still have contrib.auth.base.UserTemplate
as its base (note UserTemplate
must be loaded from contrib.auth.base.UserTemplate
, not contrib.auth.models.UserTemplate
, to avoid possible circular imports where nasty things happen).
It'd probably be cleaner if the patch used models.get_model()
instead of importing it using __import__()
, but for some reason (most likely more circular imports) I couldn't make it work reliably.
comment:104 by , 13 years ago
Cc: | added |
---|
comment:105 by , 13 years ago
Cc: | added |
---|
comment:106 by , 13 years ago
Cc: | added |
---|
Here's a fork of 1.4rc1 that allows for pluggable auth apps using the strategy some have already suggested in this ticket, namely, defining User at run-time to be either the default implementation or a user-provided implementation:
https://github.com/claymation/django/compare/pluggable-auth-apps
In addition to User, all of the companion models, forms, backends, decorators, and middleware classes that depend on User are similarly defined at run-time. The complete set of objects defined in this manner represents what I consider to be the public interface to the existing auth.User model:
models: User, UserManager, AnonymousUser, Group, Permission, SiteProfileNotAvailable admin: UserAdmin, GroupAdmin backends: ModelBackend, RemoteUserBackend decorators: user_passes_test, login_required, permission_required middleware: RemoteUserMiddleware forms: AuthenticationForm, UserCreationForm, UserChangeForm, AdminPasswordChangeForm, PasswordChangeForm, PasswordResetForm, SetPasswordForm
Developers are free to define their own pluggable auth apps, by setting AUTH_APP and adding the app to INSTALLED_APPS, following the COMMENTS_APP pattern. Here is one such pluggable auth app, which provides a User model with no username field and forms/backends/middleware that allow users to login with their email address:
https://github.com/claymation/django_email_auth
Is this the same approach that has been rejected for inclusion in core previously, and if so, why?
comment:107 by , 13 years ago
Cc: | added |
---|
comment:108 by , 13 years ago
Cc: | added |
---|
comment:109 by , 13 years ago
Cc: | removed |
---|
comment:110 by , 13 years ago
There was recently a lengthy thread on the django-developers mailing list about this issue. The proposed solution that was eventually selected by the BDFLs was essentially a swappable User model, as summarized in option 2a in ContribAuthImprovements.
comment:111 by , 13 years ago
Cc: | added |
---|
comment:112 by , 12 years ago
I've just added a draft branch implementing the BDFL-approved solution: https://github.com/freakboy3742/django/tree/t3011
comment:113 by , 12 years ago
Cc: | added |
---|
comment:114 by , 12 years ago
Cc: | added |
---|
by , 12 years ago
Attachment: | t3011_swappable_validation.diff added |
---|
Make model validation more robust (checks that swappable referred to in setting exists)
comment:116 by , 12 years ago
First time contributor, so please be firm but gentle :)
Attached a patch (applies on to Russell's t3011 branch) to make model validation and get_user_model function fail more gracefully if swappable setting is malformed or referenced model does not exist. Feedback welcome. In particular I'm conscious that there isn't a unit test for this addition (though not sure if that's applicable in this case)
comment:117 by , 12 years ago
Cc: | added |
---|
comment:118 by , 12 years ago
Cc: | added |
---|
comment:119 by , 12 years ago
Cc: | added |
---|
comment:120 by , 12 years ago
Cc: | added |
---|
comment:121 by , 12 years ago
Cc: | removed |
---|
comment:122 by , 12 years ago
Cc: | added |
---|
comment:123 by , 12 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
auth_user_module patch