Alternative to User.get_profile()

Rather than having you call User.get_profile directly, this retrieves the profile instance for a User and attaches the fields from the profile to the User object when instantiated. The special methods for DateField, FileField, ImageField and fields with choices are also created.

Since the profile object still has to be retrieved from the database before its fields can be added to the User, the costs for using this might outweigh the rewards unless you are heavily using profiles.

To install, place it in a module on your PYTHONPATH and add it to INSTALLED_APPS.

fromdjango.confimportsettingsfromdjango.contrib.auth.modelsimportUserfromdjango.core.exceptionsimportImproperlyConfigured,ObjectDoesNotExistfromdjango.dbimportmodelsfromdjango.db.models.signalsimportpost_initfromdjango.dispatchimportdispatcherfromdjango.utils.functionalimportcurrytry:getattr(settings,'AUTH_PROFILE_MODULE')exceptAttributeError:raiseImproperlyConfigured("The 'AUTH_PROFILE_MODULE' setting isn't defined.")def_get_next_or_previous_by_profile_FIELD(self,field,is_next):profile=self.get_profile()next_or_previous=profile._get_next_or_previous_by_FIELD(field,is_next)returnnext_or_previous.userdefinject_profile(sender,instance):"""Attach fields from a ``Profile`` to a ``User`` instance. Provide an alternative to ``User.get_profile`` by automatically attaching the profile's fields to the ``User`` when it is instantiated. The special methods for ``DateField``, ``FileField``, ``ImageField`` and fields with choices are also created. ``_get_next_or_previous_by_profile_FIELD`` is used instead of ``Model._get_next_or_previous_by_FIELD`` when currying the ``get_next_by_FIELD`` and ``get_previous_by_FIELD`` methods. If the profile doesn't exist -- ``AUTH_PROFILE_MODULE`` isn't set or a profile instance hasn't been created for the ``User`` -- nothing happens. """try:profile=instance.get_profile()exceptObjectDoesNotExist:returnNone# Don't overwrite existing fields on User model.blacklist=[f.nameforfininstance._meta.fields]+['id','user']forfieldin[fforfinprofile._meta.fieldsiff.namenotinblacklist]:value=getattr(profile,field.name)setattr(instance,field.name,value)iffield.choices:setattr(sender,'get_%s_display'%field.name,curry(sender._get_FIELD_display,field=field))ifisinstance(field,models.DateField)andnotfield.null:setattr(sender,'get_next_by_%s'%field.name,curry(_get_next_or_previous_by_profile_FIELD,field=field,is_next=True))setattr(sender,'get_previous_by_%s'%field.name,curry(_get_next_or_previous_by_profile_FIELD,field=field,is_next=False))ifisinstance(field,models.FileField):setattr(sender,'get_%s_filename'%field.name,curry(sender._get_FIELD_filename,field=field))setattr(sender,'get_%s_url'%field.name,curry(sender._get_FIELD_url,field=field))setattr(sender,'get_%s_size'%field.name,curry(sender._get_FIELD_size,field=field))ifisinstance(field,models.ImageField):setattr(sender,'get_%s_height'%field.name,curry(sender._get_FIELD_height,field=field))setattr(sender,'get_%s_width'%field.name,curry(sender._get_FIELD_width,field=field))dispatcher.connect(inject_profile,sender=User,signal=post_init)

The better way is to pass profile instance explicitly into context. Profile may have proxy properties to underlying user attributes: username,email,first_name,second_name. And there is no need in any magic. It is my opinion.