Dynamic AUTH_USER_MODEL based on modules or routes

880 views
Skip to first unread message

Burak Emre Kabakcı

unread,
Oct 8, 2013, 6:16:58 PM10/8/13
to django-d...@googlegroups.com
It would be nice if you allow using two different models for django.contrib.auth module. The current User model is great for admin panel users but in frontend it may become extra overhead for some cases. People try to create another user attribute models and use extra joins to be able to keep extra attributes (city, ip, locale etc.) for their users.

It seems there are a lot of improvements in Django 1.5 I think there are more thing that may be revised. For example I think we should be able to set AUTH_USER_MODEL setting per module basis or namespaced routes basis.

In order to solve this issue I needed to create a middleware class to change settings.AUTH_USER_MODEL; however I know that this is not the ideal solution because in each request I need to re-set one of the static Django settings. Here is the middleware class:

class ChangeBaseUser(object):
    def process_request(self, request):  
        match = resolve(request.path)
        if match.app_name == "myapp":
            settings.AUTH_USER_MODEL = 'myapp.Customer'
        else:
            settings.AUTH_USER_MODEL = 'auth.User'

Andre Terra

unread,
Oct 8, 2013, 7:50:46 PM10/8/13
to django-d...@googlegroups.com
Hi, Burak,

I'm not sure if you're problem is one of too much cruft in *frontend-related code* or in *user-facing content* but, in any case, it seems to me that "there should be one-- and preferably only one --obvious way to do it." [0]

Moreover, If you're having to deal with complex models for simple tasks in frontend code, you can use proxy models[1] and/or custom managers[2]. If OTOH you're problem is exposing too much functionality to users, then it would be up for you to refactor your code (especially forms) to better target your users' needs.

Finally, Django shouldn't try to provide every feature for every use case, lest it becomes flexible at the expense of "excellency", for the lack of a better word. I'm not sure this is a problem for most Django users, so the cost of having an extra middleware for a fringe use-case seems non-trivial to me.

With all this in mind, I respectfully propose that this issue be handled at the project/app level rather than by the framework as a whole.


Cheers,
AT



--
You received this message because you are subscribed to the Google Groups "Django developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/bd88babe-684e-4b5a-8b90-86963c40ffd5%40googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Russell Keith-Magee

unread,
Oct 8, 2013, 7:59:19 PM10/8/13
to Django Developers
 Hi Burak,

Thanks for the suggestion, but I think you need to think through the consequences of this a little more. AUTH_USER_MODEL isn't just a setting -- it controls the way that foreign keys are constructed in the database. Once a foreign key is constructed, it can't be (easily) pointed at a completely different table. It *certainly* can't switch between tables on a per-request basis.

It sounds to me that what you have is *two* different applications, using two different user models. Those two applications might share a lot of other logic, including models, views, and so on -- but that's why Django promotes the idea of reusable apps. You can write two apps, deployed at two different paths on the same domain, that share 95% of their logic, and only vary on a small number of settings or additional apps - like an AUTH_USER_MODEL setting.

Yours,
Russ Magee %-)

Burak Emre Kabakcı

unread,
Oct 9, 2013, 6:00:15 PM10/9/13
to django-d...@googlegroups.com
Thanks for the suggestions.

@Andre Terra I figured out that my solution doesn't work actually. Custom managers is not useful in my case because underlying auth system is still same, it means it will also use same same session tables, cookies etc.

@Russell Keith-Magee  Sorry, I couldn't understand what you mean in your second paragraph. What I'm trying to do is exactly what you're suggesting, in the example there is an app called "myapp" and I resolve the url and if the request is routed to a view in "myapp" app I change AUTH_USER_MODEL setting because AFAIK all applications use a shared settings.py file. If there's a way to use different settings for each application, please let me know.
Otherwise if you're suggesting that I should start new project that has its manage.py and settings.py I think it would be much more painful.

Sincerely,
Burak Emre 

Russell Keith-Magee

unread,
Oct 9, 2013, 8:09:22 PM10/9/13
to Django Developers
Yes - I mean having two separate projects, with two separate settings files, etc. 

As for being "more painful" -- more painful than what? You haven't proposed an alternative that will actually work - your middleware-based solution is fundamentally flawed, for the reasons I described in the first paragraph of my original response.

It's not like we're talking about a lot of code here. You need to have 2 different settings files. However, those two settings files can share a common base -- at a bare minimum, it only needs to say:

---
from common_settings import *

AUTH_USER_MODEL = 'project1.User'
---

where common_settings is a file that contains the settings common between the two projects. Yes, there's some complexity here. But then, you're the one with a project with two different concepts of User. It doesn't matter *what* you do, there's going to be complexity. 

It's also worth pointing out the other alternatives:

* Use a *single* user model, but have *profiles* to cover the different "types" of user. If you need a foreign key, use a foreign key to the *profile*, not the User.

* Write your own authentication backend. Django's auth backend is pluggable, and isn't bound to auth.User at all. 

Yours
Russ Magee %-)

Burak Emre Kabakcı

unread,
Oct 9, 2013, 9:06:22 PM10/9/13
to django-d...@googlegroups.com
Again, thanks for the other alternatives.

Today, I have worked with auth.backends.ModelBackend and it seems it would be possible to separate user resources (like if the route namespace is "myapp", then go with Customer table) if get_user(self, user_id) method is called with request parameter. It's only called by auth.get_user(request) which already has the request parameter in order to obtain backend session key. I had to change original Django source code to send extra request parameter to ModelBackend.get_user (which is really embarrassing, I know). Then I used monkey patching technique in my application code to keep Django source code original. (which is also embarrassing)

The reason that I really want to do is the database will be used by another framework in Java and my teammates insist on keeping customers data on another table (It also seems reasonable to me).

I think your separated project solution is the legit way to to something like that but the problem is I have to run two python instances in server and it will become harder to manage these instances. Also AFAIK they will have to use different ports I will have to use reverse proxy to attach the other project to a path.

Sincerely,
Burak Emre

Russell Keith-Magee

unread,
Oct 9, 2013, 9:18:09 PM10/9/13
to Django Developers
On Thu, Oct 10, 2013 at 9:06 AM, Burak Emre Kabakcı <emrek...@gmail.com> wrote:
Again, thanks for the other alternatives.

Today, I have worked with auth.backends.ModelBackend and it seems it would be possible to separate user resources (like if the route namespace is "myapp", then go with Customer table) if get_user(self, user_id) method is called with request parameter. It's only called by auth.get_user(request) which already has the request parameter in order to obtain backend session key. I had to change original Django source code to send extra request parameter to ModelBackend.get_user (which is really embarrassing, I know). Then I used monkey patching technique in my application code to keep Django source code original. (which is also embarrassing)

The reason that I really want to do is the database will be used by another framework in Java and my teammates insist on keeping customers data on another table (It also seems reasonable to me).

I think your separated project solution is the legit way to to something like that but the problem is I have to run two python instances in server and it will become harder to manage these instances. Also AFAIK they will have to use different ports I will have to use reverse proxy to attach the other project to a path.

No, they wont. Apache can trivially set up different subpaths under a single domain. 

However, we're now well outside the domain of a Django Developers thread -- you're back into Django-users territory.

Yours,
Russ Magee %-)

gavi...@gmail.com

unread,
Oct 10, 2013, 5:45:29 PM10/10/13
to django-d...@googlegroups.com
> The current User model is great for admin panel users but in frontend it may become extra overhead for some cases. People try to create another user attribute models and use extra joins to be able to keep extra attributes (city, ip, locale etc.) for their users.

Use the user-profile pattern to attach extra data to users. Your different user types can use different profiles. 

farh...@gmail.com

unread,
May 24, 2016, 8:54:05 AM5/24/16
to Django developers (Contributions to Django itself)
The original post was in 2013 and today is 2016.
I had the same problem as yours and I managed to find a solution. 
In case anyone is still wondering on how to tackle this problem, here is my solution. 

from django.apps import apps

User = apps.get_model(app_label=yourapplabel, model_name=yourmodelname)

now you can use the generic User model without settings.AUTH_USER_MODEL 
Reply all
Reply to author
Forward
0 new messages