Permalink
Browse files

major multi-profiles cleanup; this branch should now be transparently…

… usable either with multi or single profiles
  • Loading branch information...
1 parent eab7f83 commit 0ffd2dd78683254dc97450a5517602ea04efcc3e @carljm carljm committed Aug 30, 2010
Showing with 160 additions and 58 deletions.
  1. +9 −0 idios/base_urls.py
  2. +20 −6 idios/models.py
  3. +36 −0 idios/settings.py
  4. +4 −4 idios/urls.py
  5. +58 −24 idios/utils.py
  6. +33 −24 idios/views.py
View
9 idios/base_urls.py
@@ -0,0 +1,9 @@
+from django.conf.urls.defaults import *
+
+
+urlpatterns = patterns("idios.views",
+ url(r"^$", "profiles", name="profile_list"),
+ url(r"^profile/(?P<username>[\w\._-]+)/$", "profile", name="profile_detail"),
+ url(r"^edit/$", "profile_edit", name="profile_edit"),
+ url(r"^create/$", "profile_create", name="profile_create"),
+)
View
26 idios/models.py
@@ -1,4 +1,3 @@
-from django.conf import settings
from django.core.urlresolvers import reverse
from django.db import models
from django.db.models.signals import post_save
@@ -7,31 +6,46 @@
from django.contrib.auth.models import User
from idios.utils import get_profile_model
+from idios.settings import MULTIPLE_PROFILES
try:
from pinax.apps.account.signals import user_logged_in
except ImportError:
user_logged_in = None
+class ClassProperty(property):
+ def __get__(self, cls, owner):
+ return self.fget.__get__(None, owner)()
+
+
class ProfileBase(models.Model):
# @@@ could be unique=True if subclasses don't inherit a concrete base class
# @@@ need to look at this more
user = models.ForeignKey(User, verbose_name=_("user"))
-
+
class Meta:
verbose_name = _("profile")
verbose_name_plural = _("profiles")
abstract = True
-
+
def __unicode__(self):
return self.user.username
def get_absolute_url(self, group=None):
- # @@@ make group-aware / # @@@ hard coded nasty on the profile_slug, refactor immediately
- return reverse("profile_detail", kwargs={"profile_slug": "default", "username": self.user.username})
+ # @@@ make group-aware
+ kwargs = {"username": self.user.username}
+ if MULTIPLE_PROFILES:
+ kwargs["profile_slug"] = self.profile_slug
+ return reverse("profile_detail", kwargs=kwargs)
+
+ @classmethod
+ def _default_profile_slug(cls):
+ return cls._meta.module_name
+ profile_slug = ClassProperty(_default_profile_slug)
+
def create_profile(sender, instance=None, **kwargs):
if instance is None:
@@ -44,4 +58,4 @@ def additional_info_kickstart(sender, **kwargs):
request = kwargs.get("request")
request.session["idios_additional_info_kickstart"] = True
if user_logged_in: # protect against Pinax not being available
- user_logged_in.connect(additional_info_kickstart)
+ user_logged_in.connect(additional_info_kickstart)
View
36 idios/settings.py
@@ -0,0 +1,36 @@
+"""
+Combine the settings ``AUTH_PROFILE_MODULE`` and
+``IDIOS_PROFILE_MODULES`` into a single ``PROFILE_MODULES`` list.
+
+``MULTIPLE_PROFILES`` is True if there is more than one profile model
+defined, False otherwise.
+
+``DEFAULT_PROFILE_MODULE`` is the profile model referenced by
+``AUTH_PROFILE_MODULE``, or the first one listed in
+``IDIOS_PROFILE_MODULES``.
+
+This module also sets a default value of "idios.ProfileBase" for the
+``IDIOS_PROFILE_BASE`` setting.
+
+"""
+
+from django.conf import settings
+
+
+PROFILE_MODULES= []
+
+modules = []
+mod = getattr(settings, 'AUTH_PROFILE_MODULE', None)
+if mod:
+ modules.append(mod)
+
+DEFAULT_PROFILE_MODULE = None
+
+for module in modules + getattr(settings, 'IDIOS_PROFILE_MODULES', []):
+ if DEFAULT_PROFILE_MODULE is None:
+ DEFAULT_PROFILE_MODULE = module
+ PROFILE_MODULES.append(module)
+
+MULTIPLE_PROFILES = len(PROFILE_MODULES) > 1
+
+PROFILE_BASE = getattr(settings, 'IDIOS_PROFILE_BASE', 'idios.ProfileBase')
View
8 idios/urls.py
@@ -1,9 +1,9 @@
from django.conf.urls.defaults import *
+from idios.views import profiles, ALL_PROFILES
urlpatterns = patterns("",
- url(r"^(?P<profile_slug>[\w\._-]+)/$", "idios.views.profiles", name="profile_list"),
- url(r"^(?P<profile_slug>[\w\._-]+)/profile/(?P<username>[\w\._-]+)/$", "idios.views.profile", name="profile_detail"),
- url(r"^(?P<profile_slug>[\w\._-]+)/edit/$", "idios.views.profile_edit", name="profile_edit"),
- url(r"^(?P<profile_slug>[\w\._-]+)/create/$", "idios.views.profile_create", name="profile_create"),
+ url(r"^all/$", profiles, {"profile_slug": ALL_PROFILES}, name="profile_list_all"),
+ url(r"", include("idios.base_urls")),
+ url(r"^(?P<profile_slug>[\w\._-]+)/", include("idios.base_urls")),
)
View
82 idios/utils.py
@@ -1,56 +1,90 @@
"""
Utility functions for retrieving and generating forms for the
site-specific user profile model specified in the
-``AUTH_PROFILE_MODULE`` setting.
+``AUTH_PROFILE_MODULE`` or ``IDIOS_PROFILE_MODULES`` settings.
This file was pulled from django-profiles as it made the most sense. Slightly
modified for Eldarion standards.
"""
from django import forms
-from django.conf import settings
from django.db.models import get_model
from django.contrib.auth.models import SiteProfileNotAvailable
+from idios import settings
+
+def get_profile_base():
+ """
+ Return the profile model class which is the base class for all
+ profile models (used for querying on all profiles).
+
+ If multiple-profiles are not in use, this will be the single
+ profile model class itself: there is no reason to query on an
+ ancestor model in this case.
+
+ If multiple-profiles are in use, this will be the model class
+ referenced by the ``IDIOS_PROFILE_BASE`` setting. Normally this
+ will be idios' own ``ProfileBase`` model, but some projects may
+ have another model class inheriting from ProfileBase and defining
+ some additional fields, which all their profile models then
+ inherit from in turn.
+
+ If the appropriate setting does not resolve to an actual model,
+ raise ``django.contrib.auth.models.SiteProfileNotAvailable``.
+
+ """
+ if settings.MULTIPLE_PROFILES:
+ module = settings.PROFILE_BASE
+ else:
+ module = settings.DEFAULT_PROFILE_MODULE
+ model = get_model(*module.split('.'))
+ if model is None:
+ raise SiteProfileNotAvailable
+ return model
+
def get_profile_model(profile_slug=None):
"""
- 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
+ Return the model class for the profile module identified by the
+ given ``profile_slug``, as defined in the ``AUTH_PROFILE_MODULE``
+ or ``IDIOS_PROFILE_MODULES`` settings.
+
+ If ``profile_slug`` is not provided, return the default profile
+ model.
+
+ If no matching profile model is found, return None.
+
+ If no default profile model is found, raise
``django.contrib.auth.models.SiteProfileNotAvailable``.
"""
if profile_slug is None:
- if (not hasattr(settings, "AUTH_PROFILE_MODULE")) or \
- (not settings.AUTH_PROFILE_MODULE):
+ module = settings.DEFAULT_PROFILE_MODULE
+ model = get_model(*module.split('.'))
+ if model is None:
raise SiteProfileNotAvailable
- module = settings.AUTH_PROFILE_MODULE
else:
- if (not hasattr(settings, "IDIOS_PROFILE_MODULES")) or \
- (not settings.IDIOS_PROFILE_MODULES) or \
- (not settings.IDIOS_PROFILE_MODULES.get(profile_slug)):
- raise SiteProfileNotAvailable
- module = settings.IDIOS_PROFILE_MODULES.get(profile_slug).get("model")
- profile_mod = get_model(*module.split("."))
- if profile_mod is None:
- raise SiteProfileNotAvailable
- return profile_mod
+ for module in settings.PROFILE_MODULES:
+ model = get_model(*module.split('.'))
+ if model and profile_slug == model.profile_slug:
+ break
+ else:
+ model = None
+ return model
-def get_profile_form(profile_slug):
+def get_profile_form(profile_model=None):
"""
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``.
+ suitable for creating/editing instances of the given user profile
+ model.
"""
- profile_mod = get_profile_model(profile_slug)
+ if profile_model is None:
+ profile_model = get_profile_model()
class _ProfileForm(forms.ModelForm):
class Meta:
- model = profile_mod
+ model = profile_model
exclude = ("user",) # user will be filled in by the view.
return _ProfileForm
View
57 idios/views.py
@@ -10,7 +10,7 @@
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
-from idios.utils import get_profile_form, get_profile_model
+from idios.utils import get_profile_form, get_profile_model, get_profile_base
if "notification" in settings.INSTALLED_APPS:
@@ -44,17 +44,28 @@ def group_context(group, bridge):
"group": group,
}
+ALL_PROFILES = object()
-def profiles(request, profile_slug, **kwargs):
+def profiles(request, profile_slug=None, **kwargs):
"""
- profiles
+ List all profiles of a given type (or the default type, if
+ profile_slug is not given.)
+
+ If profile_slug is the ``ALL_PROFILES`` marker object, all
+ profiles are listed.
+
"""
template_name = kwargs.pop("template_name", "idios/profiles.html")
group, bridge = group_and_bridge(kwargs)
# @@@ not group-aware (need to look at moving to profile model)
- profile_class = get_profile_model(profile_slug)
+ if profile_slug is ALL_PROFILES:
+ profile_class = get_profile_base()
+ else:
+ profile_class = get_profile_model(profile_slug)
+ if profile_class is None:
+ raise Http404
profiles = profile_class.objects.select_related().order_by("-date_joined")
search_terms = request.GET.get("search", "")
@@ -74,13 +85,12 @@ def profiles(request, profile_slug, **kwargs):
"profiles": profiles,
"order": order,
"search_terms": search_terms,
- "current_profile_slug": profile_slug
})
return render_to_response(template_name, RequestContext(request, ctx))
-def profile(request, profile_slug, username, **kwargs):
+def profile(request, username, profile_slug=None, **kwargs):
"""
profile
"""
@@ -91,6 +101,8 @@ def profile(request, profile_slug, username, **kwargs):
# @@@ not group-aware (need to look at moving to profile model)
other_user = get_object_or_404(User, username=username)
profile_class = get_profile_model(profile_slug)
+ if profile_class is None:
+ raise Http404
profile = profile_class.objects.get(user=other_user)
if request.user.is_authenticated():
@@ -100,37 +112,29 @@ def profile(request, profile_slug, username, **kwargs):
is_me = False
else:
is_me = False
-
- profiles = []
- for k in settings.IDIOS_PROFILE_MODULES.keys():
- p = None
- for p in get_profile_model(k).objects.filter(user=other_user):
- break
- profiles.append({"profile_slug": k, "profile": p})
+
+ base_profile_class = get_profile_base()
+ profiles = base_profile_class.objects.filter(user=other_user)
ctx = group_context(group, bridge)
ctx.update({
"is_me": is_me,
"other_user": other_user,
"profile": profile,
"profiles": profiles,
- "current_profile_slug": profile_slug
})
return render_to_response(template_name, RequestContext(request, ctx))
@login_required
-def profile_create(request, profile_slug, **kwargs):
+def profile_create(request, profile_slug=None, **kwargs):
"""
profile_create
"""
template_name = kwargs.pop("template_name", "idios/profile_create.html")
form_class = kwargs.pop("form_class", None)
- if form_class is None:
- form_class = get_profile_form(profile_slug) # @@@ is this the same for edit/create
-
if request.is_ajax():
template_name = kwargs.get(
"template_name_facebox",
@@ -139,8 +143,13 @@ def profile_create(request, profile_slug, **kwargs):
group, bridge = group_and_bridge(kwargs)
profile_class = get_profile_model(profile_slug)
+ if profile_class is None:
+ raise Http404
profile = profile_class.objects.get(user=request.user)
+ if form_class is None:
+ form_class = get_profile_form(profile_class) # @@@ is this the same for edit/create
+
if request.method == "POST":
profile_form = form_class(request.POST, instance=profile)
if profile_form.is_valid():
@@ -155,23 +164,19 @@ def profile_create(request, profile_slug, **kwargs):
ctx.update({
"profile": profile,
"profile_form": profile_form,
- "current_profile_slug": profile_slug
})
return render_to_response(template_name, RequestContext(request, ctx))
@login_required
-def profile_edit(request, profile_slug, **kwargs):
+def profile_edit(request, profile_slug=None, **kwargs):
"""
profile_edit
"""
template_name = kwargs.pop("template_name", "idios/profile_edit.html")
form_class = kwargs.pop("form_class", None)
- if form_class is None:
- form_class = get_profile_form(profile_slug)
-
if request.is_ajax():
template_name = kwargs.get(
"template_name_facebox",
@@ -182,8 +187,13 @@ def profile_edit(request, profile_slug, **kwargs):
# @@@ not group-aware (need to look at moving to profile model)
profile_class = get_profile_model(profile_slug)
+ if profile_class is None:
+ raise Http404
profile = profile_class.objects.get(user=request.user)
+ if form_class is None:
+ form_class = get_profile_form(profile_class)
+
if request.method == "POST":
profile_form = form_class(request.POST, instance=profile)
if profile_form.is_valid():
@@ -198,7 +208,6 @@ def profile_edit(request, profile_slug, **kwargs):
ctx.update({
"profile": profile,
"profile_form": profile_form,
- "current_profile_slug": profile_slug
})
return render_to_response(template_name, RequestContext(request, ctx))

0 comments on commit 0ffd2dd

Please sign in to comment.