I have the same conundrum as presented in this question, but applied to Django's auth.User.
I have this proxy model:
class OrderedUser(User):
def __unicode__(self):
return self.get_full_name()
class Meta:
proxy=True
ordering=["first_name", "last_name"]
And some of my other models use an OrderedUser
instead of a django.contrib.auth.models.User
as field types.
In my views I then use the request.user
to populate a field and - as expected - get an error:
'Cannot assign "<User...>": <field> must be a "OrderedUser" instance'
I could just do OrderedUser.objects.get(request.user.id)
, but that is an extra hit to the database.
So, how to convert a base model class into its proxied class?
return wrapped class SimpleLazyObject(LazyObject): """ A lazy object initialized from any function. Designed for compound objects of unknown type. For builtins or objects of known type, use django.utils.functional.lazy. """ def __init__(self, func): """ Pass in a callable that returns the object to be wrapped.
AUTH_USER_MODEL is the recommended approach when referring to a user model in a models.py file. For this you need to create custom User Model by either subclassing AbstractUser or AbstractBaseUser.
get_user_model () Instead of referring to User directly, you should reference the user model using django.contrib.auth.get_user_model() . This method will return the currently active user model – the custom user model if one is specified, or User otherwise.
user is User model object. You cannot access request object in template if you do not pass request explicitly. If you want access user object from template, you should pass it to template or use RequestContext. It depends upon what you set .
It's another database hit, but this will work:
OrderedUser.objects.get(pk=request.user.pk)
Edit You could try:
o = OrderedUser()
o.__dict__ = request.user.__dict__
I couldn't get the copy dict method to work on Python 2.7.4 and Django 1.6. I didn't trace it all the way down, but I think it had something to do with it being a lazy object.
What worked for me:
request.user.__class__ = OrderedUser
It avoids the database call and gives access to the base auth stuff and all my extended behaviors.
To make the request.user act like the proxy class always, I put the assignment in middleware after the authentication middleware and before any of my apps could reference it. Since the middleware is called on every request, make sure the user is authenticated before setting the class. Using your example, here is how the middleware code might look:
from yourapp.models import OrderedUser
class OrderedUserMiddleware():
def process_request(self, request):
if hasattr(request, 'user') and request.user.is_authenticated():
request.user.__class__ = OrderedUser
And remember to register the middleware after the authentication:
MIDDLEWARE_CLASSES = [
# ...middleware from the guts of Django, none of your middle wares yet...
'django.contrib.auth.middleware.AuthenticationMiddleware',
# ...more middleware from the guts of Django, none of your middlewares yet...
'yourapp.middleware.OrderedUserMiddleware',
# ...more middleware from you other middlewares...
]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With