--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.
I'm convinced that such an idea is ultimately a bad idea: it allows apps exert action at a distance over other apps. It would allow the idea of a user to completely change without any warning simply by modifying a setting.
+1 from me.
One minorish nit: I think that "in the face of ambiguity, refuse the
temptation to guess" should apply equally to reading or writing
user.data, and that there shouldn't be an awkward discrepancy between
reading and writing. Thus, if you've got multiple profiles with
overlapping attributes (the less-common case), you need to be explicit
with AUTH_PROFILES in order to either read or write the overlapping keys
via user.data (but writing is then allowed). In the common case of no
overlapping keys, of course, you don't have to worry about AUTH_PROFILES.
Carl
> Hi folks --
>
> I've written up a proposal for how *I* would like to address refactoring auth.user: https://gist.github.com/2245327.
>
> In essence, this does two things:
>
> * Vastly "prunes" the required fields on auth.user. The only things left are an "identifier" (which could be username, email, url, uuid, whatever), and a password.
> * Introduces a new "profile" system that provides a way to contribute extra related fields. Multiple profiles are supported, along with some syntactic sugar for dealing with multiple profiles in a reasonably reusable way.
>
> And that's about it. I'm deliberately trying to find a middle ground between "do the minimum to allow people to move on" and "throw out and rewrite django.contrib.auth entirely". I'm not expecting everyone to be thrilled by this idea, but I'm hoping that this is "Good Enough" for almost everyone.
>
> For more please see the document. Please do try to read the whole thing: I've had a few rounds of feedback incorporated already, and there's even an FAQ at the end.
I've added a summary of this option to the wiki:
https://code.djangoproject.com/wiki/ContribAuthImprovements#Solution5:Profile-basedsingleusermodel
As always, feel free to correct/update as necessary.
From my reading of the proposal, here are some questions/edge cases. For some of these questions, I fully expect the answer may be "You just can't do that"; however, given that they're plausible edge cases, it's worth being explicit about what we're aiming at.
* Auto-profile creation:
What if my profile is:
class MyProfile(Profile):
first_name = CharField(max_length=100)
last_name = CharField(max_length=100)
i.e., first_name and last_name are both required fields. How does the profile get automatically instantiated in this case? Doesn't the auto-instantiation of profiles essentially mean that there can be no required fields on a profile (or, at least, on an auto-instantiated profile)?
* Regarding AUTH_PROFILE and collisions:
What if I have 2+ profiles, but no clear order of precedence? e.g.,
class MyProfile1(Profile):
name = CharField()
email = EmailField()
color = CharField()
class MyProfile2(Profile):
name = CharField(unique=True)
email = EmailField()
age = IntegerField()
Lets say that for some internal logic reason for profile processing, I need both email and age on MyProfile2, but name from MyProfile1. Under these circumstances, there's no way I can specify a single AUTH_PROFILE ordering that will satisfy my requirements. Is this a case where I have to resort to explicit naming?
Or, alternatively, should we be treating AUTH_PROFILE as a mechanism for purely specifying the resolution to specific lookup problems? i.e., instead of just specifying an order, we specify which model we want ambiguous fields to come from:
AUTH_PROFILE_LOOKUP = {
'name': 'myapp1.MyProfile1',
'email': 'myapp1.MyProfile2',
'color': 'myapp1.MyProfile2',
}
That way, if a field is unambiguous, it's returned from whatever model provides it; if a field is ambiguous, we return the one specified; and if the ambiguity isn't resolved, we return a KeyError (or catch this case as a validation error on startup).
* Required fields and AUTH_PROFILE
Combining the previous two points; what if MyProfile2 has a required field, but it isn't a field selected by data[]? e.g, in the previous example, MyProfile2.name is a required unique field; but if it isn't instantiated with useful data, the profile instances can't exist.
== Commentary ==
For me, the previous three edge cases essentially point to the fact that there can ultimately only be 1 profile for "core" user information. There will almost certainly be uses for multiple profiles (e.g., to store OpenID credentials) -- but then, this is already the case (I've got more than one project in the wild with multiple "UserProfile" objects, without using AUTH_USER_PROFILE). However, as soon as there are overlaps between profiles, you're going to end up with partially populated profiles, and eventually someone will write a 'unified' profile model for each project that doesn't have the overlap ...
... at which point, we've essentially arrived at a swappable User model, just with a required join to get profile data, and a bunch of magic attributes and ORM properties to hide the fact that the join exists.
I understand Django's history has examples where swappable models caused problems that we don't want to revisit. However, as I understand it, these problems were largely caused by the fact that it was *easy* to accidentally swap out a model, and that change wouldn't be effectively communicated to other developers on the same codebase until the magic smoke escaped.
It's also worth pointing out that the problems with swappable models aren't really avoided by the profile-based approach. If I've got a project with N user profile models, grabbing user.data['name'] from one of them, another developer can very easily modify the order of AUTH_PROFILES, or modify the apps in INSTALLED_APPS to add to or change the user profiles that are currently in effect, or alter the precedence in AUTH_PROFILES to override the attribute we need. If the objection to swappable user models is that it's easy to swap out models, then it's just as easy to change the expectations for User models via a profile -- possibly easier, because you aren't modifying a single "AUTH_USER_MODEL" setting; you're changing one of several settings whose consequences *may* include changing the operation of the User model. AUTH_USER_MODEL at least has the consequences written on the box.
(User models are hard. Lets go shopping. :-)
One possible way to avoid this problem would be to make it harder to make these sorts of changes -- i.e., add project/install-level tracking for certain key settings. So, when you do a syncdb, we set a key-value pair in the database for the current value of AUTH_USER_MODEL (or whatever mechanism needs to be persisted). Django checks this value against the current settings.AUTH_USER_MODEL value on startup; if the setting value doesn't match the installation value, we can throw an error on startup.
Would this approach temper your objection to swappable models?
At the end of the day, I'm happy to go with a BDFL judgement on this. However, it's interesting to note that almost every time this problem arises, a "swappable" model of some sort is usually the initially proposed solution. That's because it's an obvious solution -- an obvious solution with problems, but an obvious solution, nonetheless. The alternative being proposed here isn't *clearly* better -- it's really just a matter of making a strategic choice to pick a different set of pain points.
To make matters works, it seems to me that it will require a lot more work to execute -- far from being "minimalist", it's invasive on auth code, ORM code, and (in the long term) the internals of every app that uses User.
For example, any code written against the fields on the existing auth.User will need to be updated to use the new data[] access mechanism. Yes, this will be introduced gradually over releases, but it doesn't change the fact that every app that currently accesses user.is_staff will need to update to user.data['is_staff'] at some point in the next few releases. By comparison, the swappable user approach generally means no changes to app code (or just modifying ForeignKey(User) to LazyForeignKey(User), or ForeignKey(settings.USER_MODEL)), and documenting that is_staff is a required attribute on User for using the app (a property that can be validated as a project integration requirement by a test suite).
There are also some aspects about this proposal that make my teeth itch -- filter(data__...), for example, strikes me as code that will be hard to write, hard to debug, and a PITA to maintain. And if you can filter(data__...), then you need to be able to order_by('data__...') as well. But all this complexity is required if you want to maintain decoupling of profiles. It also requires adding a feature to the ORM to support a specific use case in User, rather than a generic problem (although I suppose we could implement it in such a way as to make "profiles" an option for any other model that needs them).
If we're going to make a choice to avoid the "obvious" solution, I think we need to be very clear (both now, and for posterity) why we made the choices we have made, rather than trying to address or ameliorate the problems with the "obvious" solution.
Yours
Russ Magee %-)
--
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.
Identity doesn't have anything to do with automatically dispatching users. All it is is a unique identifier. That's all this proposal honestly enforces that your users have. Some single piece of identifiable data that can be used to differentiate. This could be a username, or an email address. It could be a random string. Anything you want.In your example you might have a TwitterProfile that provides 2 fields, "authenticated_by_twitter" and "twitter username". Then if you want to check how a person authenticated to your site, you'd merely check if user.data["authenticated_by_twitter"] was True. The identifier doesn't need to have that data codified in it, (but it could!) and I honestly do not think the statement "all users must have 1 single string of any length that uniquely identifies them" is that big of a burden.
I like this proposal because I am a big fan of a stripped down `User` model which is basically just an ID, whic provides a common hook into groups/permissions and other django and 3rd party profiles.
What I don't like is the magical `data` bag (accessing `User.data` and filter lookups), the new `AUTH_PROFILES` setting, and the idea of Django automagically or lazily creating profiles for me. I would rather see Django rely solely on its `OneToOneField` field to access user profile data.
Any pluggable app (app1) will know what fields it's own profile model has and how to access them, relative to the central `User` object.
If app1 relies on fields defined by another app (app2), that other app should be a requirement of app1 and app1 would know how to access app2's fields.
I am happy to use project-level signals for everything else (syncing common profile data from app1 and app2, or auto-creating user profiles), because project-level signals give me explicit control over what is going to happen and when. I don't need any more magic here.
Cheers.
Tai.
On Tuesday, 3 April 2012 10:35:41 UTC+10, Jacob Kaplan-Moss wrote:Hi folks --I've written up a proposal for how *I* would like to address refactoring auth.user: https://gist.github.com/2245327.In essence, this does two things:* Vastly "prunes" the required fields on auth.user. The only things left are an "identifier" (which could be username, email, url, uuid, whatever), and a password.* Introduces a new "profile" system that provides a way to contribute extra related fields. Multiple profiles are supported, along with some syntactic sugar for dealing with multiple profiles in a reasonably reusable way.And that's about it. I'm deliberately trying to find a middle ground between "do the minimum to allow people to move on" and "throw out and rewrite django.contrib.auth entirely". I'm not expecting everyone to be thrilled by this idea, but I'm hoping that this is "Good Enough" for almost everyone.For more please see the document. Please do try to read the whole thing: I've had a few rounds of feedback incorporated already, and there's even an FAQ at the end.I'm not using BDFL fiat here, at least not yet. This is a proposal, and I very much want to hear feedback, objections, and alternatives. I'm particularly interested in hearing from people who've got complicated auth needs and think this absolutely won't work for them.I *have* reviewed all the other proposals and I'm between -0 and -1 on all of them. This means that if you don't like my proposal, you'll probably have to come up with a complete *new* idea to have any chance of getting my vote.Thanks!Jacob
--
You received this message because you are subscribed to the Google Groups "Django developers" group.
To view this discussion on the web visit https://groups.google.com/d/msg/django-developers/-/PMpcPCKgTuoJ.
Thanks for taking the time to tackle this issue!
On Tue, Apr 3, 2012 at 2:35 AM, Jacob Kaplan-Moss <ja...@jacobian.org> wrote:
> Hi folks --
>
> I've written up a proposal for how *I* would like to address refactoring
> auth.user: https://gist.github.com/2245327.
>
> In essence, this does two things:
>
> * Vastly "prunes" the required fields on auth.user. The only things left are
> an "identifier" (which could be username, email, url, uuid, whatever), and a
> password.
> * Introduces a new "profile" system that provides a way to contribute extra
> related fields. Multiple profiles are supported, along with some syntactic
> sugar for dealing with multiple profiles in a reasonably reusable way.
I very much like the idea of stripping down the user fields. I am
currently using an approach that's very similar to your proposal in
all my projects, except that instead of creating several profiles, I
directly add fields to the User model using this snippet:
https://gist.github.com/1283969 (I am not the initial author)
With this, adding a field to the user model is as simple as:
class MyUser(models.Model):
newsletter = models.BooleanField()
class Meta:
abstract = True
contribute_to_model(MyUser, User)
I already use this to patch the email field in the User model or make
group names not unique for instance.
The only issue is that the contributed models need to be registered as
early as possible. Currently I import them in my urls.py, but we can
imagine adding hooks for such things that need to be done at startup
time (app-refactor? :) or use your AUTH_PROFILES setting for this (not
enthusiastic about this one).
I am fully aware that this can be abused a lot. However this makes a
couple of things simpler:
* No need to proxy fields on the User model, it stays a normal model
with no special treatment
* Conflicts are simply resolved: if two models contribute the same
field, the last one registered wins
* No need for a special-cased form for editing profile-related fields,
a simple ModelForm with includes = ['fields', 'to', 'include'] works.
This is the technique I will use anyway if your proposal is
implemented, and I don't see anything that would prevent this from
working with the new auth so I'm mainly posting this because I haven't
seen this approach in the different proposals for the auth refactor.
-Bruno
Jacob--
You received this message because you are subscribed to the Google Groups "Django developers" group.
Since I weighed in with a +1 on the linked-profiles approach, I should
say that I also find this proposal pretty compelling, and would be happy
to see us go either way. After reflecting on it a bit I think on balance
I prefer this proposal, for the following reasons:
1. Requires zero migration from people with existing projects who are
happy with the existing contrib.auth.User model. I think this is a big
plus: all the other proposals require every single installed Django
codebase to perform a migration.
2. Introduces fewer new-and-different one-off concepts into Django (the
data__ ORM special case, the automatic select_related special case, the
automatic collection of profile fields into user.data...). This also
translates into significantly less implementation work and less new
code, which is another big plus - we want something that'll actually get
done and not introduce a bunch of new code we need to maintain.
By the way, I took the liberty of removing from the wiki page the
references to models/settings circular dependencies, because AFAIK the
statements made about it on the wiki page were simply incorrect.
Importing settings does _not_ immediately loop through INSTALLED_APPS
and load every models file (that only happens if you run a management
command that performs model validation, and even then it happens only
after settings are fully loaded). And "from django.db import models"
itself imports settings, so if there were such a circular dependency
problem, every models.py in existence would already be suffering from
it. I frequently refer to settings in models.py and it does not cause a
problem. If anyone can provide sample code demonstrating that this is
actually a problem, feel free to correct me!
Carl
I just now got around to reading Jacob's solution and Alex's solution.
Thanks to everybody for the thoughts and impassioned debate so far.
Here's my take on it.
First, some background: I haven't used the built-in User module in
several years. I always write my own User model from scratch -- it's
so nice and clean. Want a twitter_username field? Just add it. No need
to add a convoluted foreign key or (oh god) one-to-one relationship to
some other table.
To me, this is the Right Way to do things. The framework should bend
to my needs, I shouldn't bend to the framework's needs.
Also, profile modules need to die. They needed to die circa 2006.
So, with that in mind, I've got to say I prefer Alex's solution. I
really think the right way to do it is:
1. Let you create your own User model, with whichever fields you want.
2. Provide a way to tell Django which model you're using for that.
3. In your own code, just deal with that model like you deal with any
other one. No need to jump through hoops.
4. Third-party models should be changed to use something like "user =
UserField()", which would automatically create a foreign key to the
registered User model. If you change your registered User model after
you've created those third-party tables, you're in for trouble. Don't
do that.
5. Django provides some generic APIs for getting at the registered
user. Example: a middleware that sets request.user based on the
current session.
6. Given that some third-party apps will likely want to get access to
common attributes of a User -- notably, email address -- there could
be some sort of standard interface that User models need to adhere to
(duck typing). So, a custom User model would say "for this User model,
the email address is stored in the database field called 'email'" --
or "this User model doesn't have email addresses."
I chatted about this with Jacob on IRC, and we reached consensus on
this approach. I'd like to get moving on this and would be happy to
take it on myself, starting next week.
Adrian
To unsubscribe from this group, send email to mailto:django-developers%2Bunsu...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.
You would add whatever authorization fields you need to your single user
model. If you add new kinds of authorization that require new fields on
the user model, you'd do a schema migration (just like with any other
modification to any other model).
A third-party app that wants to provide, say, Facebook integration,
could either do its own model with a one-to-one to user (nothing is
going to suddenly prevent that approach, it just won't have any extra
sugar around it), or could provide an abstract base class that your user
model can inherit from that includes the needed fields, or could just
document "to use this app, your user model must have these fields: ..."
and let you do it yourself.
Carl
L
4. Third-party models should be changed to use something like "user =
UserField()", which would automatically create a foreign key to the
registered User model. If you change your registered User model after
you've created those third-party tables, you're in for trouble. Don't
do that.
5. Django provides some generic APIs for getting at the registered
user. Example: a middleware that sets request.user based on the
current session.
Those comments were my doing. I swear that at some point in Django's past, importing settings in models was a source of problems. However, the fact that django.db.models clearly imports settings indicates that regardless of whether this problem existed in the past, it certainly isn't the case any more.
Yours,
Russ Magee %-)
Extending on this -- User model requirements should be encoded as part of an integration test suite.
As an example of best practice, django.contrib.admin should implement a UserPropertiesTest that checks that the current USER_MODEL has an email field, and a get_permissions method, and so on. That way, if you swap in a user model that doesn't have the properties that the admin requires, it will get flagged as a issue during testing.
This should, of course, be backed up with a clear documentation of exactly what type of User-duck Django's admin requires.
Yours,
Russ Magee %-)
> On Tue, Apr 3, 2012 at 9:28 AM, Alex Ogier <alex....@gmail.com> wrote:
>> I have written up a little bit about the alternate proposal that I made a
>> while ago, Solution 2a
>> from https://code.djangoproject.com/wiki/ContribAuthImprovements
>
> ...
> 4. Third-party models should be changed to use something like "user =
> UserField()", which would automatically create a foreign key to the
> registered User model. If you change your registered User model after
> you've created those third-party tables, you're in for trouble. Don't
> do that.
>
My only concern about this approach is making a special case of swappable Users. There's at least one other example of a swappable model in Django's core -- the Comments model -- and I have no doubt that we could find other examples with a quick survey.
If we're going down the path of swappable models, I'd rather set up the infrastructure to solve the *general* problem of swappable models, rather than just swappable *user* models specifically.
If this required a massive increase in the effort required, I can see how practicality would determine that we just solve the immediate problem. However, in this case, it's really just a matter of avoiding User-specific naming on 4 features:
a) Specifying the model that can be swapped.
This is just the name of the setting. USER_MODEL is fine by itself, and has obvious analogs with other models. However, an alternate way of spelling the same thing would be to have a single setting for all swappable models:
SWAPPABLE_MODELS = {
'user': 'myauth.SuperDuperUser',
'comment': 'comments.Comment',
}
in which you can define any extensible model, and provide a convenient key (e.g., 'user') to identify the value for that model.
b) Preventing the "default" model from being added to the app cache, or synchronized to the database
contrib.auth is going to need ship with a User model, but we really don't want an auth_user table to be created, or get_model(auth,'User') to resolve, if the default User isn't being used. Same goes for any other swappable model.
Rather than make a special case of User inside syncdb, or nesting model definitions in if blocks, lets add a "swappable" attribute to Meta. If swappable is defined, syncdb checks the contents of SWAPPABLE_MODELS to see if this model has been substituted; if it has, then the table isn't created, and the model isn't added to the app cache. The value of pluggable can match the key in SWAPPABLE_MODELS (so auth.User would define swappable='user', following the previous example)
This can also act as a safety mechanism; if a developer has an app that contains a ForeignKey(User), and the User model has been swapped out, this can now raise a validation warning (notifying the developer that the User model could potentially be swapped out) or error (in the case where the model *has* been swapped out).
c) Providing a way to specify foreign keys to that model
Rather than introduce a User-specific UserField(), introduce a generic LazyForeignKey('user') - both of which are effectively just ForeignKey(settings.XXXX) anyway.
d) Provide a way to discover the current user model
Rather than have auth.get_user_model(), leverage the existing app cache. We already have get_model(); it wouldn't be too hard to add a get_swappable_model('user').
> 6. Given that some third-party apps will likely want to get access to
> common attributes of a User -- notably, email address -- there could
> be some sort of standard interface that User models need to adhere to
> (duck typing). So, a custom User model would say "for this User model,
> the email address is stored in the database field called 'email'" --
> or "this User model doesn't have email addresses."
>
As I've noted elsewhere, this can be both a documentation issue, and backed up by an integration test. As a longer term goal, if someone ever takes the bait and does the Validation refactor for the GSoC (hint hint), it could also be extracted as a validation condition for an app.
Yours,
Russ Magee %-)
Right now, we're trying to solve the swappable model *for User*, which is a bigger problem because it's not confined to a single app; it's defined in auth, but auth functions as a nexus for lots of other things.
Regards,
Luke
> I'm not so sure that it's necessary or even desirable to solve the "general" problem of swappable models. If anyone can swap any model by changing a setting, that sounds like a recipe for confusion to me.
Sure, but that's not what I've proposed. A model would only be swappable if the original app developer declared that model as swappable. An end user wouldn't be able to arbitrarily decide that they wanted to replace a model in an app developed by someone else.
And sure, any feature we add could ultimately end up being used (and overused) in bad ways. However, that's true of any language or library feature. Classes, metaclasses, decorators, or any other Python language feature can be both used and abused, as can Django features like ModelForms or the internals of the Meta class.
My point is that there is nothing about this problem that is unique to User. Django's own codebase contains another example of exactly the same pattern -- Comments. Therefore, we shouldn't pretend that the solution is User specific. At some point, we have to just provide enough documentation and guidance to shepherd people away from bad architectural decisions, and trust that the userbase will take that advice.
Yours,
Russ Magee %-)
My point is that there is nothing about this problem that is unique to User. Django's own codebase contains another example of exactly the same pattern -- Comments.
Totally agree with Jacob here, plus Tai's comment that "There is such
a thing as too generic." We've made the mistake of making things too
generic in the past, and it's kind of infuriating in retrospect, both
philosophically and in terms of code maintenance/understanding.
(django/utils/tree.py, anyone??)
I think our policy should be: make the simplest thing that can
possibly work for a narrowly-tailored use case, then make things more
generic *slowly* if there's a demand. No need to be an Architecture
Astronaut.
Adrian
Adrian
Here's the source of that term:
http://www.joelonsoftware.com/articles/fog0000000018.html
http://www.codinghorror.com/blog/2004/12/it-came-from-planet-architecture.html
Adrian
> On Wednesday, April 4, 2012 at 9:44 AM, Russell Keith-Magee wrote:
>> My point is that there is nothing about this problem that is unique to User. Django's own codebase contains another example of exactly the same pattern -- Comments.
> As the original author and designer of that pattern, I should probably point out that I now think it's a mistake. Have you actually tried using it? It doesn't really work very well. Every time I've introduced any sort of "swappable model" mechanism I've come to regret it.
>
> I'm -1 on the idea of generalized "swappable model" mechanism. I can stomach it for User because in this context it's not any worse than the alternatives, but as a generalized mechanism it makes me really, really unhappy. Decoupling is a laudable goal, but providing a mechanism to reach in and effect code not under your control isn't good design. We use derisive terms like "monkeypatching" for a reason.
Agreed that monkeypatching is bad. However, I think that's the wrong analogy in this case; I think "interface" is a closer match.
An interface is essentially just a way of saying "I need to operate on an object with these properties, but I'm going to let the end user define the specific object instance that provides those properties". As a language, Python generally doesn't need interfaces because of duck typing. However, ForeignKey is a "strongly typed" database relationship, so you can't duck type it -- the original app developer needs to be able to define it as something that the end developer might want to change.
> I'm sure there are good reasons for wanting swappable models. Russ, I know you're smarter than me,
Don't put too much weight in that argument. I have plenty of braindead ideas. The PhD just means I'm persistent :-)
> so the fact that you want LazyForeignKey so much probably indicates that you've got some really solid use cases in mind. But really this is a hard veto from me; I just can't be convinced that this sort of mechanism is anything but bad news.
To tell the truth, I haven't used the comments app extensively, so I can't really comment on that example specifically. I also don't have a specific case in mind where I want to use this feature. However, if you think of the problem being solved here as interfaces, it isn't hard to think of other possible applications.
More broadly, my reaction comes from the the fact that I *have* been bitten -- many times -- by claims that "this is a special case". Special cases almost never are, and the counterexample usually shows up a week after you're irretrievably committed to a "specialized" solution.
> However, I don't see why we should actively prevent this sort of thing being done externally, so if there's anything in Django that's precluding the creation of a LazyForeignKey as an external add-on let's consider that limitation a bug and get it fixed.
Sure -- I can live with that. There's really only two places where I see this being an issue in practice:
1) Introducing UserField(). I'd be against introducing UserField() as a special case of ForeignKey(). Even though it's more typing, ForeignKey(settings.USER_MODEL) offends me less. This doesn't preclude other developers writing their own ForeignKey shortcuts; I just think it sets a bad example.
2) The synchronization/app cache problem. In order to do this properly, we need to prevent the auth_user table from being created, and auth.User being added to the app cache. If we're going to address this by adding hooks into the model startup process, I'd like to see them as general hooks, rather than special cases for auth.User -- even if they're undocumented hooks.
Of course, the other option is just an if statement in the models.py file:
if settings.USER_MODEL == 'auth.User':
class User(models.Model):
username = ...
which is a pattern that other uses could adopt.
Yours,
Russ Magee %-)
Certainly agreed that astronauting is a bad thing.
However, I would like to draw attention to one particular benefit of the generic solution (other than being generic):
Once we make User swappable, every app with a model that has a ForeignKey to User will need to be updated. This can be done slowly; existing projects that use auth.User will continue to work. However there won't be any real alert to the fact that the app requires updating until you try to swap out User and things start to break. This breakage will be somewhat unpredictable -- you'll just be observing side effect errors as a result of a non-existent (or empty) auth_user table.
Under the approach I described, User will be marked (in the Meta object) as swappable, and ForeignKey(User) will be a hard link to a swapapble model, which is something we can catch as a validation warning, providing a cue to developers that there are apps in their project that may need to be updated. And if there is a ForeignKey(User) and settings.USER_MODEL *isn't* User, then we can raise an validation error, because we know that this app won't work.
Even if we don't implement a fully generic solution, I think this property of the generic approach is worth preserving.
Yours,
Russ Magee %-)
It seems that swappable models are nothing but a different way of doing what
I already am doing for when I am extending the flat pages; except that it
ads a nice centralized SWAPPABLE_MODELS setting.
Furthermore if I do make a swappable custom user model the correct
implementation of 'standard' User methods depends on me; sure I could extend
a the base User model and inherit these methods but then
what did I gained by having this swappable model concept?
The more I think about it the more it makes sense to me to have a base User
model just a stub with a user Identifier and password field. Sure one could
argue for less ore more fields, but I think the idea
is to pick something that would work in 95% situations and yet be flexible
enough to be extended as you wish. Need to extend to add your own
authorization you create a profile with a FK key to the base model and
a new auth backend.
Perhaps the reason the current contib.auth is still not overhauled is
because it does work for a large number of situation and extending it is
relatively easy. Keep the solution simple - I think we are overthinking it.
-----Original Message-----
From: Russell Keith-Magee
Sent: Wednesday, April 04, 2012 10:44 AM
To: django-d...@googlegroups.com
Subject: Re: auth.user refactor: the profile aproach
Yours,
Russ Magee %-)
--
iPhoneから送信
On 2012/04/04, at 5:34, Adrian Holovaty <adr...@holovaty.com> wrote:
> First, some background: I haven't used the built-in User module in
> several years. I always write my own User model from scratch -- it's
> so nice and clean. Want a twitter_username field? Just add it. No need
> to add a convoluted foreign key or (oh god) one-to-one relationship to
> some other table.
>
> To me, this is the Right Way to do things. The framework should bend
> to my needs, I shouldn't bend to the framework's needs.
>
> Also, profile modules need to die. They needed to die circa 2006.
Yes, Yes, Yes. I'm really glad someone besides me disliked user profiles and favored just creating your own user model. I was feeling lonely.
Just like Adrian, me and everyone at my company have used our own user models for years. It always felt like the simplest and most straight-forward approach. It also has the be benefit that users can use south or anything they want. For migrating and managing user data. Big big +1.
> So, with that in mind, I've got to say I prefer Alex's solution. I
> really think the right way to do it is:
>
> 1. Let you create your own User model, with whichever fields you want.
>
> 2. Provide a way to tell Django which model you're using for that.
>
> 3. In your own code, just deal with that model like you deal with any
> other one. No need to jump through hoops.
>
> 4. Third-party models should be changed to use something like "user =
> UserField()", which would automatically create a foreign key to the
> registered User model. If you change your registered User model after
> you've created those third-party tables, you're in for trouble. Don't
> do that.
>
> 5. Django provides some generic APIs for getting at the registered
> user. Example: a middleware that sets request.user based on the
> current session.
I wanted to point out that Adrien's plan is pretty close to newauth. Though I didn't go so far as to provide a UserField, I did have a way for third party apps to get a handle of the User model via a get_user_model() function. The UserField would just glue something like that to a ForeignKey.
> 6. Given that some third-party apps will likely want to get access to
> common attributes of a User -- notably, email address -- there could
> be some sort of standard interface that User models need to adhere to
> (duck typing). So, a custom User model would say "for this User model,
> the email address is stored in the database field called 'email'" --
> or "this User model doesn't have email addresses.
I think people get too hung up on providing fields do third party apps when you could provide a minimal set of methods which subclasses could override. There isn't really any reason i can think of that third party apps need to access the fields directly.
Though if you really hav to deal with fields, I prefer a simple convention for common fields; for example, 'email' for the email field. That way you can do a simple hasattr() to look if the model has a particular field. I realize convention is hard to document though.
I'm curious though how the admin fits into your ideas. If you wanted to use the admin, would you have to use a User model that has and or supports all the cruft on the current user model? e.g. username, password, email, permissions etc.
All in all I'm excited about where this is going and that you're taking the lead on this. Can't thank you enough.
Yes, you'd need to tell the admin how your User model interacted with
it -- how it authenticates, how permissions work, etc.
Adrian
--
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.
iPhoneから送信
On 2012/04/06, at 0:29, "Daniel Sokolowski" <daniel.s...@klinsight.com> wrote:
> The more I think about it the more it makes sense to me to have a base User model just a stub with a user Identifier and password field. Sure one could argue for less ore more fields, but I think the idea
> is to pick something that would work in 95% situations and yet be flexible enough to be extended as you wish. Need to extend to add your own authorization you create a profile with a FK key to the base model and
> a new auth backend.
The good part about swappable user models is that you don't need to necessarily fix the model's DB fields in advance. Your identifier and password's length and other properties can be user defined and can be reflected in the DB.
Django can also leave migration of user models an data up to the developer so they an use south or whatever to manage the user model since they "own" it. Django Devs wouldn't necessarily need to support a DB table that can essentially never change as is the case currently.
Fixing that stuff ahead of time and just making a FK means the user model itself is fixed. I don't want to be able to just add fields. I want to be able to change the primary key to be a uuid, or a email, or use the default auto incrementing integer. I want to be able to use an existing model or DB table and, with some work, plug it into Django auth.
Now if I'm customizing the user model itself anyway, why not just tack on whatever other fields I want? I don't need a FK since those fields are on the user model and I can create however many one to one or one to many relationships for "profiles" or user data as makes sense for my project. That may be a lot or it may be zero.
(now whether that is realistic given the needs of the admin is a different story)
> Perhaps the reason the current contib.auth is still not overhauled is because it does work for a large number of situation and extending it is relatively easy. Keep the solution simple - I think we are overthinking it.
Sure. I'm not completely discontent continuing to use my own library and simply shun anything that uses auth (besides the admin maybe), but I think Django would be better off with a better auth module.
> The good part about swappable user models is that you don't need to necessarily fix the model's DB fields in advance. Your identifier and password's length and other properties can be user defined and can be reflected in the DB.
>
> Django can also leave migration of user models an data up to the developer so they an use south or whatever to manage the user model since they "own" it. Django Devs wouldn't necessarily need to support a DB table that can essentially never change as is the case currently.
>
> Fixing that stuff ahead of time and just making a FK means the user model itself is fixed. I don't want to be able to just add fields. I want to be able to change the primary key to be a uuid, or a email, or use the default auto incrementing integer. I want to be able to use an existing model or DB table and, with some work, plug it into Django auth.
>
> Now if I'm customizing the user model itself anyway, why not just tack on whatever other fields I want? I don't need a FK since those fields are on the user model and I can create however many one to one or one to many relationships for "profiles" or user data as makes sense for my project. That may be a lot or it may be zero.
>
> (now whether that is realistic given the needs of the admin is a different story)
But I still don't see how a swapped in `User` model which *has* to behave in a specified way so that it can work with the Django admin and any other pluggable apps that might have special requirements, is any better than simply allowing the admin and other pluggable apps to have their profile and authentication needs self-contained?
If Django's `User` model was just a stub (without even username and password fields), and Django shipped with an abstract `BaseAuth` model with a `username` field that was email compliant and a `password` field, and corresponding `BaseAuthForm` and `BaseAuthBackend`, then user's can still create their own `User` model with literally *whatever* fields they want in it, they can use the standard auth fields, form and backend provided by Django, or roll their own.
Instead of creating a custom `User` model that quacks like an admin duck, and quacks like every pluggable app that is installed as well, all they need to do is create/update an an `AdminUser` whenever their custom `User` is saved.
This is explicit, the admin and other pluggable apps know where to access information that they need (from their own models), and the developer has control over how the data is kept in sync across the pluggable apps used in the project, at the project level.
Cheers.
Tai.
I haven't been following this thread nearly closely enough. But ISTM that any abstraction that doesn't let the admin work with any User (assuming it supplies the right interface) isn't very useful, and rather misses the point.
It's a good thing that I didn't document that as a "universal concern" on the wiki right from the start ...
https://code.djangoproject.com/wiki/ContribAuthImprovements#TheUserContract
Oh wait...
:-)
Russ %-)
For the sake of avoiding duplication, which could be managed with signals and the save() method of a project level profile, you potentially overload fields that are not analogous across pluggable apps by sharing a single namespace. E.g. is_active for the admin may not mean is_active for app2 or app3.
Jacob, by having to define a minimum set of fields that users must implement in their swappable User model to support contrib apps like the admin, don't we end up exactly where we are now? Isn't this exactly what we have already?
The only difference I see then is that the interface would be defined in docs instead of a model and re-implemented by developers for every project, and pluggable apps will often require a schema migration on the swapped-in project level User model when adding a pluggable app to an established project.
In my ideal scenario, User would be a glue model with just a PK, and maybe some convenience methods. AdminProfile would not have username or password fields, but would have is_active, is_superuser, and maybe optionally a name, etc.
Developers would need to create at least one model in their project, which would be a subclass of BaseAuthModel in most cases, which stores authentication credentials.
They would also need to create an auth backend, which would be a subclass of BaseAuthBackend in most cases.
Pluggable apps could also define auth models and backends if they require specific auth to function (e.g. an app that adds twitter integration.)
Then people could login to the admin and any other pluggable apps using whatever credentials and authentication system they like (username/email and password, twitter, Facebook, openid, etc.) Developers wouldn't need to implement a minimal set of fields or do a database schema migration to support or install any pluggable apps.
If app1 or app2 require access to an email address (for example), their profiles should have a required email field. It should be up to the project developer to make sure that an email address is set when creating an app1 or app2 profile for a User, and synchronizing them between app1 and app2 (if appropriate).
I think the data duplication issue is much easier for project developers to manage explicitly without resorting to magic and assumptions than sharing or combining namespaces for profile data, doing database scheme migrations, and duck typing a single model for use with multiple pluggable apps.
Cheers.
Tai.
--
You received this message because you are subscribed to the Google Groups "Django developers" group.
To view this discussion on the web visit https://groups.google.com/d/msg/django-developers/-/p4jhylEp3x8J.
I think this proposal will make more sense if people stop thinking "If someone wants to use contrib.auth, then why do we need another crufty interface to swap out auth.User?" Instead think of someone who wants to use contrib.admin but not be stuck with contrib.auth.
The point of this proposal isn't to make contrib.auth larger and better, it's to make it unnecessary. A lot of people find contrib.auth's models unsatisfactory. Adrian Holovaty stated that he hasn't used auth.User for several years. When you have a complex site with multiple authentication methods and requirements that don't fit django's idea of a user, it stops being worth it to bend yourself to django's will. The problem is that contrib.auth and contrib.admin are currently intimately linked. This proposal's purpose is to give an official way to break these two apart.
I don't know of a single framework out there besides Django that ships with a fixed model for its users. The reason is that authentication and identity are radically different for every site so it's tremendously important to support whatever people decide to do, and not force decisions on them.
So, stop thinking just in terms of contrib.auth.models.User. If you're already using that with a profile and it's all working fine, then this change isn't for you. This is for everyone who just wishes auth.User would go away without totally borking admin.
Respectfully,
Alex Ogier
I don't know of a single framework out there besides Django that ships with a fixed model for its users.
To unsubscribe from this group, send email to mailto:django-developers%2Bunsu...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.
--
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.
--
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 mailto:django-developers%2Bunsu...@googlegroups.com.
How is the final approach chosen ?
I chatted about this with Jacob on IRC, and we reached consensus on
this approach. I'd like to get moving on this and would be happy to
take it on myself, starting next week.
Hi Alex
Is https://gist.github.com/2289395 the complete proposal for what is
to be implemented? It seems more of a point by point rebuttal of
another proposal.
Is the approved solution to have mixins which contribute to a user
class? Are pluggable apps expected to provide mixins that contribute
to the user model?
Does this proposal fix the current issues with the user model in new projects?
My biggest concerns with this approach:
1) Monolithic user tables.
Adding apps that want their own user storage with this system requires
new columns in your user model. This is not the best approach. Foreign
keys to separate user data tables per app is much more appropriate.
Monolithic tables kill performance. As an example, a C++ ORM I have
used had this approach, and it was common to come across a user table
with 100+ columns, including some massive fields (unbounded text
fields, blobs). On most page requests, only a few columns were looked
at, but every page paid the cost of retrieving massive user objects.
The most common complaint against profiles is that they are 'slow' as
you have to join to many tables, or issue multiple queries. Queries
against monolithic tables are much slower than a few queries on much
smaller tables.
2) Constant flux on my user model as a site develops
Adding new apps which require user storage would require schema
change. If you have lots of users, this is a real pain. When adding an
app profile, all that is required is a new table to be created, which
would not lock a critical table like 'user' for a long period.
I've no objection to allowing project managers more control over the
user model, but I don't think we should encourage the majority of
pluggable apps to pollute the user model - in fact, probably only apps
dealing with AAA.
Eg, a photo gallery app may want to store the preferred thumbnail size
and whether to open images in a new window. These do not belong on the
user model, but on a photo gallery app profile. Most users may not
have preferences, and for those that do, it is only relevant to access
that info on a photo gallery page.
A twitter auth app may want to store an oauth token. This should
belong on the user model, as it is used for AAA, and may be accessed
on any request.
Cheers
Tom
Thanks for raising those issues. I would just like to add that I hope to see fields currently in `User` that are required by the admin (is_staff, etc.), moved to an admin profile model, and not simply made available through mixins that are still required by every `User` model that gets swapped in.
Even if we technically allow the `User` model to be swapped in, and therefore allow new fields to be added to it, I think that this would set a dangerous example and precedent for authors of other pluggable apps.
The admin is arguably *the* premiere example of a "pluggable" app, held up as a reference on how it should be done. I think it's important that we clearly define when it is appropriate for a pluggable app to require schema changes to a project's `User` model, and that should only be in rare and specific circumstances.
Generally, fields should only be added to the `User` model by a project author (not a pluggable app author), because pluggable app authors won't know the details of the environment (other pluggable apps and project) they will be installed into.
I also hope to see a more fleshed out proposal from Adrian, before an actual implementation is delivered, hopefully containing answers to some of the questions raised here.
Cheers.
Tai.
Hi,
I'm not getting why you *have* to add fields to the User model to store data pertaining to the user. There is nothing in the proposal for pluggable user models that says you can never have a seperate model with a foreign key to the user model. It just means that you can define your user model the way you want it to be.
Why can't third party apps have a model with a foreign key to the user table with the pluggable models approach? I imagine you are right that every app and it's brother adding fields to the user model is not realistic but I don't think that anyone has proposed that. Certainly not me. The thing I want to be able to is define user models suitable for my project. Third party apps adding their own fields wasn't proposed by anyone AFAIK, nor was specifically requiring that you add them yourself. Some might require that your user has something like an 'email' field because that would be a common field across apps but app specific data can easily go on a seperate model included with the app that simply has a FK to user. You can then only fetch that data on requests that need it.
I'm sorry but doing a JOIN every request is a BAD idea. You will run into problems there quickly and have no way out of it besides ditching auth completely (and thus all the thirdparty apps you use that depend on it). Assuming the user table and profile tables are small is awfully short sighted.
Ian
That is perfectly fine. The problem comes when there is a simple
system to add fields to the user model, people will use it to add
fields to the user model in their pluggable apps, for 'simplicity' and
'ease of use'.
> Why can't third party apps have a model with a foreign key to the user table
> with the pluggable models approach? I imagine you are right that every app
> and it's brother adding fields to the user model is not realistic but I
> don't think that anyone has proposed that. Certainly not me.
The proposed solution as decided by BDFL diktat is 2a from [1]. I quote:
Split off as much as possible of auth.User into orthogonal mixins that
can be reused.
Modify auth.User to inherit these mixins. Care must be taken to ensure
that the database expression of the new User model is identical to the
old User model, to ensure backwards compatibility.
Unrelated and third-party apps can indicate that they depend on
various orthogonal mixins. For example, contrib.admin can specify that
it works with auth.User out of the box, and with any model
implementing PermissionsMixin if you supply your own login forms.
At the moment, you cannot change the user model, so we do not have
issues relating to third party apps changing the user model. With the
proposed solution, you would be able to change the user model, so we
may have issues.
It's also enlightening to read the code from Alex's Django branch,
which is an initial implementation of option 2a.
> The thing I
> want to be able to is define user models suitable for my project. Third
> party apps adding their own fields wasn't proposed by anyone AFAIK, nor was
> specifically requiring that you add them yourself. Some might require that
> your user has something like an 'email' field because that would be a common
> field across apps but app specific data can easily go on a seperate model
> included with the app that simply has a FK to user. You can then only fetch
> that data on requests that need it.
>
> I'm sorry but doing a JOIN every request is a BAD idea. You will run into
> problems there quickly and have no way out of it besides ditching auth
> completely (and thus all the thirdparty apps you use that depend on it).
I completely disagree, but I'm not here to try and convince people how
to design their databases. A JOIN every request will not end the
world. Besides, it is far more likely to be a separate query than a
JOIN, and would only happen on views that required that data.
More to the point, what basis are you making this claim on? People
love to pipe up "JOINs are slow and evil", but have you actually
analysed the cost compared to monolithic tables?
> Assuming the user table and profile tables are small is awfully short
> sighted.
To be fair, I was slightly ambiguous with my use of the word 'small'. I said:
>> Queries against monolithic tables are much slower than a few queries on much
>> smaller tables.
Here 'small' means fewer columns, not less tuples.
However, assuming tables will be small is precisely what you have just
done - "we must not have JOINs, they are evil, but it doesn't matter
because the user table will only have the columns I desire". I agree
that it is a short sighted position, if you do not prevent the table
becoming monolithic ;)
Cheers
Tom
[1] https://code.djangoproject.com/wiki/ContribAuthImprovements
Hi Tom,
The best rounded description with pros and cons is Solution 2a on https://code.djangoproject.com/wiki/ContribAuthImprovements
You are correct that I am primarily thinking of pluggable authentication when I think of this new user model. The reason is that there is nothing stopping you from continuing to place app data outside the user model as has been standard for a while now. For example, there is nothing stopping you from using the following pattern in you app's view:
if request.user.is_authenticated():
try:
prefs = GalleryPref.objects.get(user=request.user)
except GalleryPref.DoesNotExist:
prefs = None
That is, unless you have a reason that your particular data should be eagerly loaded on every request there is no reason to require it on the user. In fact app developers are incentivized to keep their data separate in order to remain compatible with the default user.
The solution isn't perfect, it does in fact provide some barriers to this pattern. The Gallery app must explicitly choose to foreign key to settings.USER_MODEL, and once they do *changing* which model the setting points to requires a migration of your table. These are both real issues, but I don't think that user model bloat will be because there is a straightforward way to work around it if it does prove to be an issue for any particular project.
The only thing this proposal kills is magic proxying back from user attributes. If you really wanted to, you could roll your own proxy attributes to app fields, after all you control the entire user class.
Best,
Alex Ogier
Tom,
I proposed mixins to solve the specific problem: there is an app that needs a specific contract from a model it wants to authenticate or otherwise interact with, how can we make it easy for developers to implement that contract?
Most apps don't actually need that much though. There are a bunch of standard ways to relate to a model that don't invasively change it. They are all still available, and in fact preferred because no matter how easy it is to use a mixin, doing nothing is even easier.
Best,
Alex Ogier
On Tue, Apr 10, 2012 at 3:13 PM, Ian Lewis <ianm...@gmail.com> wrote:That is perfectly fine. The problem comes when there is a simple
> Hi,
>
> I'm not getting why you *have* to add fields to the User model to store data
> pertaining to the user. There is nothing in the proposal for pluggable user
> models that says you can never have a seperate model with a foreign key to
> the user model. It just means that you can define your user model the way
> you want it to be.
system to add fields to the user model, people will use it to add
fields to the user model in their pluggable apps, for 'simplicity' and
'ease of use'.
The proposed solution as decided by BDFL diktat is 2a from [1]. I quote:
> Why can't third party apps have a model with a foreign key to the user table
> with the pluggable models approach? I imagine you are right that every app
> and it's brother adding fields to the user model is not realistic but I
> don't think that anyone has proposed that. Certainly not me.
Split off as much as possible of auth.User into orthogonal mixins that
can be reused.
Modify auth.User to inherit these mixins. Care must be taken to ensure
that the database expression of the new User model is identical to the
old User model, to ensure backwards compatibility.
Unrelated and third-party apps can indicate that they depend on
various orthogonal mixins. For example, contrib.admin can specify that
it works with auth.User out of the box, and with any model
implementing PermissionsMixin if you supply your own login forms.
At the moment, you cannot change the user model, so we do not have
issues relating to third party apps changing the user model. With the
proposed solution, you would be able to change the user model, so we
may have issues.
It's also enlightening to read the code from Alex's Django branch,
which is an initial implementation of option 2a.
> The thing II completely disagree, but I'm not here to try and convince people how
> want to be able to is define user models suitable for my project. Third
> party apps adding their own fields wasn't proposed by anyone AFAIK, nor was
> specifically requiring that you add them yourself. Some might require that
> your user has something like an 'email' field because that would be a common
> field across apps but app specific data can easily go on a seperate model
> included with the app that simply has a FK to user. You can then only fetch
> that data on requests that need it.
>
> I'm sorry but doing a JOIN every request is a BAD idea. You will run into
> problems there quickly and have no way out of it besides ditching auth
> completely (and thus all the thirdparty apps you use that depend on it).
to design their databases. A JOIN every request will not end the
world. Besides, it is far more likely to be a separate query than a
JOIN, and would only happen on views that required that data.
More to the point, what basis are you making this claim on? People
love to pipe up "JOINs are slow and evil", but have you actually
analysed the cost compared to monolithic tables?
> Assuming the user table and profile tables are small is awfully shortTo be fair, I was slightly ambiguous with my use of the word 'small'. I said:
> sighted.
>> Queries against monolithic tables are much slower than a few queries on much
>> smaller tables.
Here 'small' means fewer columns, not less tuples.
However, assuming tables will be small is precisely what you have just
done - "we must not have JOINs, they are evil, but it doesn't matter
because the user table will only have the columns I desire". I agree
that it is a short sighted position, if you do not prevent the table
becoming monolithic ;)
Tai,
I think you are overestimating the importance of a "pluggable" user model. If 100 apps all try to add fields to the User model then of course bloat and performance issues and field name conflicts will be a problem. But I don't think that will happen. There are very good reasons for an app *not* to plug in: it's more work for everyone who uses your app and it means the app is incompatible with Django's default user. I trust app developers to recognize both of those facts.
This is orthogonal to the notion of swappable users. Django's default doesn't satisfy many projects' needs and we want to give them a way to implement their own user on a project-wide basis. Such users are "pluggable" merely because they are raw python, and raw python supports multiple inheritance and extensive monkey-patching. Setting a precedent here is fine IMO, and doesn't signal that every app should store all data related to the user on the user model.
Best,
Alex
Hi Alex, thanks for that. I think that a lot of this information
should end up in the revised docs, showing patterns on how to
(correctly) use the new features, when to add fields to user and when
not to, etc. and we should be fine.
I wasn't that interested in the magic proxying. Eventually, all magic
dies and has to be removed, so it is better to just be explicit about
what is happening.
Cheers
Tom
What if the User owns more than one Twitter handle? I use six
different email-addresses regularly and several openids. The auth
backends I write use Foreign Key and not OneToOneKey back to User for
a reason.
> The reason being that the latter is *so much
> more flexible*. You can simulate the first with the second, but not vice
> versa. Twitter-auth might not need its own table (in fact, it shouldn't need
> its own table). If you really wanted to, you could make one, and foreign-key
> *from* the user model which gives you everything the first solution has,
> with no need to created magical .prof1, .prof2 proxy attributes. You could
> even let users sign in with multiple handles with a many-to-many. Heck,
> maybe your blog posts have their own twitter credentials, I don't know.
This would *only* be flexible with a many-to-many. Then you wouldn't
have to ALTER TABLE to add an auth-backend.
HM
Hi folks --I've written up a proposal for how *I* would like to address refactoring auth.user: https://gist.github.com/2245327.In essence, this does two things:* Vastly "prunes" the required fields on auth.user. The only things left are an "identifier" (which could be username, email, url, uuid, whatever), and a password.* Introduces a new "profile" system that provides a way to contribute extra related fields. Multiple profiles are supported, along with some syntactic sugar for dealing with multiple profiles in a reasonably reusable way.And that's about it. I'm deliberately trying to find a middle ground between "do the minimum to allow people to move on" and "throw out and rewrite django.contrib.auth entirely". I'm not expecting everyone to be thrilled by this idea, but I'm hoping that this is "Good Enough" for almost everyone.For more please see the document. Please do try to read the whole thing: I've had a few rounds of feedback incorporated already, and there's even an FAQ at the end.I'm not using BDFL fiat here, at least not yet. This is a proposal, and I very much want to hear feedback, objections, and alternatives. I'm particularly interested in hearing from people who've got complicated auth needs and think this absolutely won't work for them.I *have* reviewed all the other proposals and I'm between -0 and -1 on all of them. This means that if you don't like my proposal, you'll probably have to come up with a complete *new* idea to have any chance of getting my vote.Thanks!Jacob