Code

Opened 3 years ago

Closed 3 years ago

#15097 closed (worksforme)

User.has_profile() for use in templates when not every user can be expected to have a profile.

Reported by: tkolar Owned by: nobody
Component: contrib.auth Version: master
Severity: Keywords: get_profile templates user auth
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: UI/UX:

Description

Problem

This ticket is a proposal aimed at fixing a problem I'm having using User.get_profile from a template. I googled for an elegant solution, but couldn't find one, and nobody on #django was able to think of one either.

When setting a profile model with AUTH_PROFILE_MODULE, it is still possible that a given user has no profile yet. When using django-registration and django-profiles, this is actually the default workflow (create a user, and then log in and create a profile).
In view code, this is not a problem: user.get_profile() will either return the users profile or raise an exception that can be caught. In templates, however, the exception would cause the rendering of the entire template to fail, so this is not an option. By extension, there is no way for a template to find out whether a given user has a profile or not. It is therefore impossible for a template to access a user profile given the user, unless it relies on the existence of a profile.
Given that profiles are a close extension of the user model, and that it is easily possible for a user not to have a profile, I guess I can safely say that that is a Bad Thing.

I have looked at tickets #9788, #7592, #7585 and #11879, and feel the need to clarify that I do NOT want to offer another way to dynamically create default profiles, change get_profile itself, or provide a near-identical and redundant alternative.

Proposal

My proposal is a method has_profile for the User model that returns True if a profile for that user exists, and False otherwise. I have attached a version of models.py that implements this.

Use cases

My personal use case

Yes, it may seem egocentric, but I am posting this here because I think that it provides a good example for a situation where the problem does not have a simple workaround.
For my web app, I decided to implement a template "suggestions.html" that displays things like "Register to do stuff on the site", or (and that is what I am having a problem with at the moment), "Hey, you don't have a profile yet, why don't you create one here?". This template is included in my base template as a default filler for an area that could also display suggestions/notices that are view-specific ("You are looking at a list of foos you have added a bar to, you can find the complete list of foos here.").

Things like that are the reason that templates get a variable for the current user in their context for every request. It is very limiting that that is not the case for profiles.

Using generic views

When using generic views, it is quite common not to write any view code that does not count as glue, often just mapping a url to a generic view and passing it arguments is sufficient. If the template needs any profile for any reason, the view code has to be changed.

This article was written by {{ user.username }}, who joined <a href="{% url index_page %}">example.org</a> on {{ user.oh_crap_I_need_the_profile }}

When the people writing the code are not the people writing the templates

Because in that case, the template designers shall need to complain to the developers that they can't access user profiles, and the developers shall need to implement get_profile_or_none in every second view they write, and they shall get fed up with doing that and monkey patch django.contrib.auth.models.User, and there won't be any cake left.

Yeah, I realize that this got rather long, but I felt that I needed to explain why what I am proposing does not violate the rule that "There should be one-- and preferably only one --obvious way to do it." - for templates, at the moment, there isn't. While it might make more sense to make get_profile more template-friendly, this isn't possible due to compatibility reasons. I also thought of a get_profile_or_none method, but that seems more redundant (maybe the profile is not interesting itself and we are only interested in whether it exists or not, which might leave room for optimizations, I am not familiar enough with django to be able to do more than guess at that though).

Attachments (1)

models.py (19.0 KB) - added by tkolar 3 years ago.
Version of models.py that implements User.has_profile

Download all attachments as: .zip

Change History (2)

Changed 3 years ago by tkolar

Version of models.py that implements User.has_profile

comment:1 Changed 3 years ago by tkolar

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Resolution set to worksforme
  • Status changed from new to closed

...

Having been mislead by an answer to http://stackoverflow.com/questions/422140/how-to-access-the-user-profile-in-a-django-template and having ignored that the paragraph above http://docs.djangoproject.com/en/dev/ref/templates/api/#how-invalid-variables-are-handled only applies to the dev version, I checked whether SiteProfileNotAvailable was a subclass of django.core.exceptions.ObjectDoesNotExist or had silent_variable_failure=True for some other reason. I then assumed that that was the way it would work, didn't try it out, and instead went and posted this ticket. Well, turns out that there is nothing to fix here.

I am so sorry for the hassle.

On the other hand, SiteProfileNotAvailable should probably have silent_variable_failure=True, which it doesn't in SVN. I'll post a ticket for that in a moment.

And sorry again.

Add Comment

Modify Ticket

Change Properties
<Author field>
Action
as closed
as The resolution will be set. Next status will be 'closed'
The resolution will be deleted. Next status will be 'new'
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.