diff --git a/avatar/models.py b/avatar/models.py index 02de5c9..2bc94ef 100644 --- a/avatar/models.py +++ b/avatar/models.py @@ -56,6 +56,25 @@ def find_extension(format): format = 'jpg' return format + +def get_primary_avatar(user, size=80): + if not isinstance(user, User): + try: + user = User.objects.get(username=user) + except User.DoesNotExist: + return AVATAR_DEFAULT_URL + avatars = user.avatar_set.order_by('-date_uploaded') + primary = avatars.filter(primary=True) + if primary.count() > 0: + avatar = primary[0] + elif avatars.count() > 0: + avatar = avatars[0] + else: + avatar = None + if avatar: + if not avatar.thumbnail_exists(size): + avatar.create_thumbnail(size) + return avatar class Avatar(models.Model): user = models.ForeignKey(User) diff --git a/avatar/templatetags/avatar_tags.py b/avatar/templatetags/avatar_tags.py index 217c6bf..b0928be 100644 --- a/avatar/templatetags/avatar_tags.py +++ b/avatar/templatetags/avatar_tags.py @@ -4,28 +4,17 @@ from django import template from django.contrib.auth.models import User from django.utils.translation import ugettext as _ from django.utils.hashcompat import md5_constructor +from django.core.urlresolvers import reverse -from avatar import AVATAR_DEFAULT_URL, AVATAR_GRAVATAR_BACKUP, AVATAR_GRAVATAR_DEFAULT +from avatar.models import get_primary_avatar +from avatar import AVATAR_DEFAULT_URL, AVATAR_GRAVATAR_BACKUP +from avatar import AVATAR_GRAVATAR_DEFAULT register = template.Library() def avatar_url(user, size=80): - if not isinstance(user, User): - try: - user = User.objects.get(username=user) - except User.DoesNotExist: - return AVATAR_DEFAULT_URL - avatars = user.avatar_set.order_by('-date_uploaded') - primary = avatars.filter(primary=True) - if primary.count() > 0: - avatar = primary[0] - elif avatars.count() > 0: - avatar = avatars[0] - else: - avatar = None - if avatar is not None: - if not avatar.thumbnail_exists(size): - avatar.create_thumbnail(size) + avatar = get_primary_avatar(user, size=size) + if avatar: return avatar.avatar_url(size) else: if AVATAR_GRAVATAR_BACKUP: @@ -55,6 +44,19 @@ def avatar(user, size=80): size, size) register.simple_tag(avatar) +def primary_avatar(user, size=80): + """ + This tag tries to get the default avatar for a user without doing any db + requests. It achieve this by linking to a special view that will do all the + work for us. If that special view is then cached by a CDN for instance, + we will avoid many db calls. + """ + alt = unicode(user) + url = reverse('avatar_render_primary', kwargs={'user' : user, 'size' : size}) + return """%s""" % (url, alt, + size, size) +register.simple_tag(primary_avatar) + def render_avatar(avatar, size=80): if not avatar.thumbnail_exists(size): avatar.create_thumbnail(size) diff --git a/avatar/urls.py b/avatar/urls.py index c3dc07b..0ddc942 100644 --- a/avatar/urls.py +++ b/avatar/urls.py @@ -4,4 +4,5 @@ urlpatterns = patterns('avatar.views', url('^add/$', 'add', name='avatar_add'), url('^change/$', 'change', name='avatar_change'), url('^delete/$', 'delete', name='avatar_delete'), + url('^render_primary/(?P[\+\w]+)/(?P[\d]+)/$', 'render_primary', name='avatar_render_primary'), ) diff --git a/avatar/views.py b/avatar/views.py index e909052..5b78e25 100644 --- a/avatar/views.py +++ b/avatar/views.py @@ -1,8 +1,8 @@ import os.path -from avatar.models import Avatar, avatar_file_path +from avatar.models import Avatar, avatar_file_path, get_primary_avatar from avatar.forms import PrimaryAvatarForm, DeleteAvatarForm, UploadAvatarForm -from django.http import HttpResponseRedirect +from django.http import HttpResponseRedirect, HttpResponse from django.shortcuts import render_to_response from django.template import RequestContext from django.contrib.auth.decorators import login_required @@ -64,7 +64,7 @@ def _get_avatars(user): else: # Slice the default set now that we used the queryset for the primary avatar avatars = avatars[:AVATAR_MAX_AVATARS_PER_USER] - return (avatar, avatars) + return (avatar, avatars) @login_required def add(request, extra_context={}, next_override=None): @@ -164,3 +164,16 @@ def delete(request, extra_context={}, next_override=None): 'next': next_override or _get_next(request), } ) ) + +def render_primary(request, user=None, size=80, extra_context={}): + avatar = get_primary_avatar(user, size=size) + if avatar: + # FIXME: later, add an option to render the resized avatar dynamically + # instead of redirecting to an already created static file. This could + # be useful in certain situations, particulary if there is a CDN and + # we want to minimize the storage usage on our static server, letting + # the CDN store those files instead + return HttpResponseRedirect(avatar.avatar_url(size)) + else: + return HttpResponseRedirect(AVATAR_DEFAULT_URL) +