diff options
author | substantialnoninfringinguser <substantialnoninfringinguser@gmail.com> | 2009-05-13 05:48:10 +0100 |
---|---|---|
committer | substantialnoninfringinguser <substantialnoninfringinguser@gmail.com> | 2009-05-13 05:48:10 +0100 |
commit | ed345f25760d8927f834a69202c2b9b2cef71ee0 (patch) | |
tree | 652dba01640060cc2106af850955728828bcd8f0 /profiles | |
parent | cdd4e685ee95e44b9a599b03cf11723a4ce7b7c6 (diff) | |
download | troggle-ed345f25760d8927f834a69202c2b9b2cef71ee0.tar.gz troggle-ed345f25760d8927f834a69202c2b9b2cef71ee0.tar.bz2 troggle-ed345f25760d8927f834a69202c2b9b2cef71ee0.zip |
[svn] Add user registration and user profiles.
Used modified versions of django-registration and django-profiles , both on bitbucket.
The Person model is now set up as the profile for auth.User s.
I set up a requestcontext so that settings is automatically passed to every template, no need to repeat ourselves in views. However, this needs to be refined: I will soon change it to only pass a subset of settings. E.G. we do not need to be passing the DB login and password!
Copied from http://cucc@cucc.survex.com/svn/trunk/expoweb/troggle/, rev. 8231 by aaron @ 1/29/2009 11:02 PM
Diffstat (limited to 'profiles')
-rw-r--r-- | profiles/__init__.py | 0 | ||||
-rw-r--r-- | profiles/urls.py | 43 | ||||
-rw-r--r-- | profiles/utils.py | 45 | ||||
-rw-r--r-- | profiles/views.py | 340 |
4 files changed, 428 insertions, 0 deletions
diff --git a/profiles/__init__.py b/profiles/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/profiles/__init__.py diff --git a/profiles/urls.py b/profiles/urls.py new file mode 100644 index 0000000..05ff9e4 --- /dev/null +++ b/profiles/urls.py @@ -0,0 +1,43 @@ +""" +URLConf for Django user profile management. + +Recommended usage is to use a call to ``include()`` in your project's +root URLConf to include this URLConf for any URL beginning with +'/profiles/'. + +If the default behavior of the profile views is acceptable to you, +simply use a line like this in your root URLConf to set up the default +URLs for profiles:: + + (r'^profiles/', include('profiles.urls')), + +But if you'd like to customize the behavior (e.g., by passing extra +arguments to the various views) or split up the URLs, feel free to set +up your own URL patterns for these views instead. If you do, it's a +good idea to keep the name ``profiles_profile_detail`` for the pattern +which points to the ``profile_detail`` view, since several views use +``reverse()`` with that name to generate a default post-submission +redirect. If you don't use that name, remember to explicitly pass +``success_url`` to those views. + +""" + +from django.conf.urls.defaults import * + +from profiles import views + + +urlpatterns = patterns('', + url(r'^create/$', + views.create_profile, + name='profiles_create_profile'), + url(r'^edit/$', + views.edit_profile, + name='profiles_edit_profile'), + url(r'^(?P<username>\w+)/$', + views.profile_detail, + name='profiles_profile_detail'), + url(r'^$', + views.profile_list, + name='profiles_profile_list'), + ) diff --git a/profiles/utils.py b/profiles/utils.py new file mode 100644 index 0000000..faacfcb --- /dev/null +++ b/profiles/utils.py @@ -0,0 +1,45 @@ +""" +Utility functions for retrieving and generating forms for the +site-specific user profile model specified in the +``AUTH_PROFILE_MODULE`` setting. + +""" + +from django import forms +from django.conf import settings +from django.contrib.auth.models import SiteProfileNotAvailable +from django.db.models import get_model + + +def get_profile_model(): + """ + Return the model class for the currently-active user profile + model, as defined by the ``AUTH_PROFILE_MODULE`` setting. If that + setting is missing, raise + ``django.contrib.auth.models.SiteProfileNotAvailable``. + + """ + if (not hasattr(settings, 'AUTH_PROFILE_MODULE')) or \ + (not settings.AUTH_PROFILE_MODULE): + raise SiteProfileNotAvailable + profile_mod = get_model(*settings.AUTH_PROFILE_MODULE.split('.')) + if profile_mod is None: + raise SiteProfileNotAvailable + return profile_mod + + +def get_profile_form(): + """ + Return a form class (a subclass of the default ``ModelForm``) + suitable for creating/editing instances of the site-specific user + profile model, as defined by the ``AUTH_PROFILE_MODULE`` + setting. If that setting is missing, raise + ``django.contrib.auth.models.SiteProfileNotAvailable``. + + """ + profile_mod = get_profile_model() + class _ProfileForm(forms.ModelForm): + class Meta: + model = profile_mod + exclude = ('user',) # User will be filled in by the view. + return _ProfileForm diff --git a/profiles/views.py b/profiles/views.py new file mode 100644 index 0000000..c119165 --- /dev/null +++ b/profiles/views.py @@ -0,0 +1,340 @@ +""" +Views for creating, editing and viewing site-specific user profiles. + +""" + +from django.contrib.auth.decorators import login_required +from django.contrib.auth.models import User +from django.core.exceptions import ObjectDoesNotExist +from django.core.urlresolvers import reverse +from django.http import Http404 +from django.http import HttpResponseRedirect +from django.shortcuts import get_object_or_404 +from django.shortcuts import render_to_response +from django.template import RequestContext +from django.views.generic.list_detail import object_list + +from profiles import utils + +import troggle.settings as settings + + + +def create_profile(request, form_class=None, success_url=None, + template_name='profiles/create_profile.html', + extra_context=None): + """ + Create a profile for the current user, if one doesn't already + exist. + + If the user already has a profile, as determined by + ``request.user.get_profile()``, a redirect will be issued to the + :view:`profiles.views.edit_profile` view. If no profile model has + been specified in the ``AUTH_PROFILE_MODULE`` setting, + ``django.contrib.auth.models.SiteProfileNotAvailable`` will be + raised. + + **Optional arguments:** + + ``extra_context`` + A dictionary of variables to add to the template context. Any + callable object in this dictionary will be called to produce + the end result which appears in the context. + + ``form_class`` + The form class to use for validating and creating the user + profile. This form class must define a method named + ``save()``, implementing the same argument signature as the + ``save()`` method of a standard Django ``ModelForm`` (this + view will call ``save(commit=False)`` to obtain the profile + object, and fill in the user before the final save). If the + profile object includes many-to-many relations, the convention + established by ``ModelForm`` of using a method named + ``save_m2m()`` will be used, and so your form class should + also define this method. + + If this argument is not supplied, this view will use a + ``ModelForm`` automatically generated from the model specified + by ``AUTH_PROFILE_MODULE``. + + ``success_url`` + The URL to redirect to after successful profile creation. If + this argument is not supplied, this will default to the URL of + :view:`profiles.views.profile_detail` for the newly-created + profile object. + + ``template_name`` + The template to use when displaying the profile-creation + form. If not supplied, this will default to + :template:`profiles/create_profile.html`. + + **Context:** + + ``form`` + The profile-creation form. + + **Template:** + + ``template_name`` keyword argument, or + :template:`profiles/create_profile.html`. + + """ + try: + profile_obj = request.user.get_profile() + return HttpResponseRedirect(reverse('profiles_edit_profile')) + except ObjectDoesNotExist: + pass + + # + # We set up success_url here, rather than as the default value for + # the argument. Trying to do it as the argument's default would + # mean evaluating the call to reverse() at the time this module is + # first imported, which introduces a circular dependency: to + # perform the reverse lookup we need access to profiles/urls.py, + # but profiles/urls.py in turn imports this module. + # + + if success_url is None: + success_url = reverse('profiles_profile_detail', + kwargs={ 'username': request.user.username }) + if form_class is None: + form_class = utils.get_profile_form() + if request.method == 'POST': + form = form_class(data=request.POST, files=request.FILES) + if form.is_valid(): + profile_obj = form.save(commit=False) + profile_obj.user = request.user + profile_obj.save() + if hasattr(form, 'save_m2m'): + form.save_m2m() + return HttpResponseRedirect(success_url) + else: + form = form_class() + + if extra_context is None: + extra_context = {} + context = RequestContext(request) + for key, value in extra_context.items(): + context[key] = callable(value) and value() or value + + return render_to_response(template_name, + { 'form': form, 'settings':settings }, + context_instance=context) +create_profile = login_required(create_profile) + +def edit_profile(request, form_class=None, success_url=None, + template_name='profiles/edit_profile.html', + extra_context=None): + """ + Edit the current user's profile. + + If the user does not already have a profile (as determined by + ``User.get_profile()``), a redirect will be issued to the + :view:`profiles.views.create_profile` view; if no profile model + has been specified in the ``AUTH_PROFILE_MODULE`` setting, + ``django.contrib.auth.models.SiteProfileNotAvailable`` will be + raised. + + **Optional arguments:** + + ``extra_context`` + A dictionary of variables to add to the template context. Any + callable object in this dictionary will be called to produce + the end result which appears in the context. + + ``form_class`` + The form class to use for validating and editing the user + profile. This form class must operate similarly to a standard + Django ``ModelForm`` in that it must accept an instance of the + object to be edited as the keyword argument ``instance`` to + its constructor, and it must implement a method named + ``save()`` which will save the updates to the object. If this + argument is not specified, this view will use a ``ModelForm`` + generated from the model specified in the + ``AUTH_PROFILE_MODULE`` setting. + + ``success_url`` + The URL to redirect to following a successful edit. If not + specified, this will default to the URL of + :view:`profiles.views.profile_detail` for the profile object + being edited. + + ``template_name`` + The template to use when displaying the profile-editing + form. If not specified, this will default to + :template:`profiles/edit_profile.html`. + + **Context:** + + ``form`` + The form for editing the profile. + + ``profile`` + The user's current profile. + + **Template:** + + ``template_name`` keyword argument or + :template:`profiles/edit_profile.html`. + + """ + try: + profile_obj = request.user.get_profile() + except ObjectDoesNotExist: + return HttpResponseRedirect(reverse('profiles_create_profile')) + + # + # See the comment in create_profile() for discussion of why + # success_url is set up here, rather than as a default value for + # the argument. + # + + if success_url is None: + success_url = reverse('profiles_profile_detail', + kwargs={ 'username': request.user.username }) + if form_class is None: + form_class = utils.get_profile_form() + if request.method == 'POST': + form = form_class(data=request.POST, files=request.FILES, instance=profile_obj) + if form.is_valid(): + form.save() + return HttpResponseRedirect(success_url) + else: + form = form_class(instance=profile_obj) + + if extra_context is None: + extra_context = {} + context = RequestContext(request) + for key, value in extra_context.items(): + context[key] = callable(value) and value() or value + + return render_to_response(template_name, + { 'form': form, + 'profile': profile_obj, }, + context_instance=context) +edit_profile = login_required(edit_profile) + +def profile_detail(request, username, public_profile_field=None, + template_name='profiles/profile_detail.html', + extra_context=None): + """ + Detail view of a user's profile. + + If no profile model has been specified in the + ``AUTH_PROFILE_MODULE`` setting, + ``django.contrib.auth.models.SiteProfileNotAvailable`` will be + raised. + + If the user has not yet created a profile, ``Http404`` will be + raised. + + **Required arguments:** + + ``username`` + The username of the user whose profile is being displayed. + + **Optional arguments:** + + ``extra_context`` + A dictionary of variables to add to the template context. Any + callable object in this dictionary will be called to produce + the end result which appears in the context. + + ``public_profile_field`` + The name of a ``BooleanField`` on the profile model; if the + value of that field on the user's profile is ``False``, the + ``profile`` variable in the template will be ``None``. Use + this feature to allow users to mark their profiles as not + being publicly viewable. + + If this argument is not specified, it will be assumed that all + users' profiles are publicly viewable. + + ``template_name`` + The name of the template to use for displaying the profile. If + not specified, this will default to + :template:`profiles/profile_detail.html`. + + **Context:** + + ``profile`` + The user's profile, or ``None`` if the user's profile is not + publicly viewable (see the description of + ``public_profile_field`` above). + + **Template:** + + ``template_name`` keyword argument or + :template:`profiles/profile_detail.html`. + + """ + user = get_object_or_404(User, username=username) + try: + profile_obj = user.get_profile() + except ObjectDoesNotExist: + raise Http404 + if public_profile_field is not None and \ + not getattr(profile_obj, public_profile_field): + profile_obj = None + + if extra_context is None: + extra_context = {} + context = RequestContext(request) + for key, value in extra_context.items(): + context[key] = callable(value) and value() or value + + return render_to_response(template_name, + { 'profile': profile_obj }, + context_instance=context) + +def profile_list(request, public_profile_field=None, + template_name='profiles/profile_list.html', **kwargs): + """ + A list of user profiles. + + If no profile model has been specified in the + ``AUTH_PROFILE_MODULE`` setting, + ``django.contrib.auth.models.SiteProfileNotAvailable`` will be + raised. + + **Optional arguments:** + + ``public_profile_field`` + The name of a ``BooleanField`` on the profile model; if the + value of that field on a user's profile is ``False``, that + profile will be excluded from the list. Use this feature to + allow users to mark their profiles as not being publicly + viewable. + + If this argument is not specified, it will be assumed that all + users' profiles are publicly viewable. + + ``template_name`` + The name of the template to use for displaying the profiles. If + not specified, this will default to + :template:`profiles/profile_list.html`. + + Additionally, all arguments accepted by the + :view:`django.views.generic.list_detail.object_list` generic view + will be accepted here, and applied in the same fashion, with one + exception: ``queryset`` will always be the ``QuerySet`` of the + model specified by the ``AUTH_PROFILE_MODULE`` setting, optionally + filtered to remove non-publicly-viewable proiles. + + **Context:** + + Same as the :view:`django.views.generic.list_detail.object_list` + generic view. + + **Template:** + + ``template_name`` keyword argument or + :template:`profiles/profile_list.html`. + + """ + profile_model = utils.get_profile_model() + queryset = profile_model._default_manager.all() + if public_profile_field is not None: + queryset = queryset.filter(**{ public_profile_field: True }) + kwargs['queryset'] = queryset + return object_list(request, template_name=template_name, **kwargs) |