From 93fb42fd833ef9bc4399cb42f751727b6a9285b7 Mon Sep 17 00:00:00 2001 From: Simon Meers Date: Fri, 15 Mar 2013 21:29:07 +1100 Subject: [PATCH 1/5] Commence experimental support for custom User models. --- avatar/models.py | 7 ++++++- avatar/templatetags/avatar_tags.py | 7 ++++++- avatar/tests.py | 7 ++++++- avatar/util.py | 7 ++++++- avatar/views.py | 8 +++++++- setup.py | 8 ++++---- 6 files changed, 35 insertions(+), 9 deletions(-) diff --git a/avatar/models.py b/avatar/models.py index a956b96..86f2a4f 100644 --- a/avatar/models.py +++ b/avatar/models.py @@ -9,7 +9,12 @@ from django.utils.hashcompat import md5_constructor from django.utils.encoding import smart_str from django.db.models import signals -from django.contrib.auth.models import User +try: + from django.contrib.auth import get_user_model +except ImportError: + from django.contrib.auth.models import User +else: + User = get_user_model() try: from cStringIO import StringIO diff --git a/avatar/templatetags/avatar_tags.py b/avatar/templatetags/avatar_tags.py index 39b4317..31eb589 100644 --- a/avatar/templatetags/avatar_tags.py +++ b/avatar/templatetags/avatar_tags.py @@ -7,7 +7,12 @@ from django.utils.translation import ugettext as _ from django.utils.hashcompat import md5_constructor from django.core.urlresolvers import reverse -from django.contrib.auth.models import User +try: + from django.contrib.auth import get_user_model +except ImportError: + from django.contrib.auth.models import User +else: + User = get_user_model() from avatar.settings import (AVATAR_GRAVATAR_BACKUP, AVATAR_GRAVATAR_DEFAULT, AVATAR_DEFAULT_SIZE, AVATAR_GRAVATAR_BASE_URL) diff --git a/avatar/tests.py b/avatar/tests.py index 74938ab..8f3b381 100644 --- a/avatar/tests.py +++ b/avatar/tests.py @@ -4,7 +4,12 @@ from django.test import TestCase from django.core.urlresolvers import reverse from django.conf import settings -from django.contrib.auth.models import User +try: + from django.contrib.auth import get_user_model +except ImportError: + from django.contrib.auth.models import User +else: + User = get_user_model() from avatar.settings import AVATAR_DEFAULT_URL, AVATAR_MAX_AVATARS_PER_USER from avatar.util import get_primary_avatar diff --git a/avatar/util.py b/avatar/util.py index d181085..ccb17be 100644 --- a/avatar/util.py +++ b/avatar/util.py @@ -4,7 +4,12 @@ from django.utils.hashcompat import md5_constructor from django.utils.encoding import smart_str from django.template.defaultfilters import slugify -from django.contrib.auth.models import User +try: + from django.contrib.auth import get_user_model +except ImportError: + from django.contrib.auth.models import User +else: + User = get_user_model() from avatar.settings import (AVATAR_DEFAULT_URL, AVATAR_CACHE_TIMEOUT, AUTO_GENERATE_AVATAR_SIZES, AVATAR_DEFAULT_SIZE) diff --git a/avatar/views.py b/avatar/views.py index 658bcc2..f90621d 100644 --- a/avatar/views.py +++ b/avatar/views.py @@ -7,7 +7,13 @@ from django.views.decorators.csrf import csrf_exempt from django.contrib import messages from django.contrib.auth.decorators import login_required -from django.contrib.auth.models import User + +try: + from django.contrib.auth import get_user_model +except ImportError: + from django.contrib.auth.models import User +else: + User = get_user_model() from avatar.forms import PrimaryAvatarForm, DeleteAvatarForm, UploadAvatarForm from avatar.models import Avatar diff --git a/setup.py b/setup.py index df35977..7dc32ca 100644 --- a/setup.py +++ b/setup.py @@ -92,12 +92,12 @@ template rendering system: ``{% avatar_url user [size in pixels] %}`` Renders the URL of the avatar for the given user. User can be either a - ``django.contrib.auth.models.User`` object instance or a username. + ``django.contrib.auth.get_user_model()`` object instance or a username. ``{% avatar user [size in pixels] %}`` - Renders an HTML ``img`` tag for the given user for the specified size. User - can be either a ``django.contrib.auth.models.User`` object instance or a - username. + Renders an HTML ``img`` tag for the given user for the specified size. User + can be either a ``django.contrib.auth.get_user_model()`` object instance + or a username. ``{% render_avatar avatar [size in pixels] %}`` Given an actual ``avatar.models.Avatar`` object instance, renders an HTML From 7ee83431b33225de4d1c621e0f334ad2e1eb1754 Mon Sep 17 00:00:00 2001 From: Simon Meers Date: Fri, 15 Mar 2013 21:45:24 +1100 Subject: [PATCH 2/5] More quickly scrawled / untested custom user model support changes --- avatar/admin.py | 4 ++-- avatar/models.py | 13 ++++-------- .../avatar_friend_updated/notice.html | 4 ++-- avatar/templatetags/avatar_tags.py | 12 +++-------- avatar/tests.py | 9 +-------- avatar/urls.py | 4 ++-- avatar/util.py | 20 +++++++++++++++++-- avatar/views.py | 20 +++++++++---------- 8 files changed, 42 insertions(+), 44 deletions(-) diff --git a/avatar/admin.py b/avatar/admin.py index fafcf0e..a6486ce 100644 --- a/avatar/admin.py +++ b/avatar/admin.py @@ -3,12 +3,12 @@ from django.utils.translation import ugettext_lazy as _ from avatar.models import Avatar from avatar.templatetags.avatar_tags import avatar - +from avatar.util import User class AvatarAdmin(admin.ModelAdmin): list_display = ('get_avatar', 'user', 'primary', "date_uploaded") list_filter = ('primary',) - search_fields = ('user__username',) + search_fields = ('user__%s' % getattr(User, 'USERNAME_FIELD', 'username'),) list_per_page = 50 def get_avatar(self, avatar_in): diff --git a/avatar/models.py b/avatar/models.py index 86f2a4f..2b00dc6 100644 --- a/avatar/models.py +++ b/avatar/models.py @@ -9,12 +9,7 @@ from django.utils.hashcompat import md5_constructor from django.utils.encoding import smart_str from django.db.models import signals -try: - from django.contrib.auth import get_user_model -except ImportError: - from django.contrib.auth.models import User -else: - User = get_user_model() +from avatar.util import User, get_username try: from cStringIO import StringIO @@ -45,10 +40,10 @@ avatar_storage = get_storage_class(AVATAR_STORAGE)() def avatar_file_path(instance=None, filename=None, size=None, ext=None): tmppath = [AVATAR_STORAGE_DIR] if AVATAR_HASH_USERDIRNAMES: - tmp = md5_constructor(instance.user.username).hexdigest() - tmppath.extend([tmp[0], tmp[1], instance.user.username]) + tmp = md5_constructor(get_username(instance.user)).hexdigest() + tmppath.extend([tmp[0], tmp[1], get_username(instance.user)]) else: - tmppath.append(instance.user.username) + tmppath.append(get_username(instance.user)) if not filename: # Filename already stored in database filename = instance.avatar.name diff --git a/avatar/templates/notification/avatar_friend_updated/notice.html b/avatar/templates/notification/avatar_friend_updated/notice.html index 093c2c1..6d9b8c0 100644 --- a/avatar/templates/notification/avatar_friend_updated/notice.html +++ b/avatar/templates/notification/avatar_friend_updated/notice.html @@ -1,2 +1,2 @@ -{% load i18n %}{% url profile_detail username=user.username as user_url %} -{% blocktrans with user as avatar_creator and avatar.get_absolute_url as avatar_url %}{{ avatar_creator }} has updated their avatar {{ avatar }}.{% endblocktrans %} \ No newline at end of file +{% load i18n %}{% url profile_detail username=user.username as user_url %}{# TODO: support custom user models via get_username #} +{% blocktrans with user as avatar_creator and avatar.get_absolute_url as avatar_url %}{{ avatar_creator }} has updated their avatar {{ avatar }}.{% endblocktrans %} diff --git a/avatar/templatetags/avatar_tags.py b/avatar/templatetags/avatar_tags.py index 31eb589..f55a7e0 100644 --- a/avatar/templatetags/avatar_tags.py +++ b/avatar/templatetags/avatar_tags.py @@ -7,16 +7,10 @@ from django.utils.translation import ugettext as _ from django.utils.hashcompat import md5_constructor from django.core.urlresolvers import reverse -try: - from django.contrib.auth import get_user_model -except ImportError: - from django.contrib.auth.models import User -else: - User = get_user_model() - from avatar.settings import (AVATAR_GRAVATAR_BACKUP, AVATAR_GRAVATAR_DEFAULT, AVATAR_DEFAULT_SIZE, AVATAR_GRAVATAR_BASE_URL) -from avatar.util import get_primary_avatar, get_default_avatar_url, cache_result +from avatar.util import ( + get_primary_avatar, get_default_avatar_url, cache_result, User, get_user) from avatar.models import Avatar register = template.Library() @@ -45,7 +39,7 @@ def avatar_url(user, size=AVATAR_DEFAULT_SIZE): def avatar(user, size=AVATAR_DEFAULT_SIZE, **kwargs): if not isinstance(user, User): try: - user = User.objects.get(username=user) + user = get_user(user) alt = unicode(user) url = avatar_url(user, size) except User.DoesNotExist: diff --git a/avatar/tests.py b/avatar/tests.py index 8f3b381..6d233d8 100644 --- a/avatar/tests.py +++ b/avatar/tests.py @@ -4,15 +4,8 @@ from django.test import TestCase from django.core.urlresolvers import reverse from django.conf import settings -try: - from django.contrib.auth import get_user_model -except ImportError: - from django.contrib.auth.models import User -else: - User = get_user_model() - from avatar.settings import AVATAR_DEFAULT_URL, AVATAR_MAX_AVATARS_PER_USER -from avatar.util import get_primary_avatar +from avatar.util import get_primary_avatar, User from avatar.models import Avatar try: diff --git a/avatar/urls.py b/avatar/urls.py index 1fbe017..3635341 100644 --- a/avatar/urls.py +++ b/avatar/urls.py @@ -7,6 +7,6 @@ urlpatterns = patterns( url(r'^change/$', 'change', name='avatar_change'), url(r'^delete/$', 'delete', name='avatar_delete'), url(r'^render_primary/(?P[\w\d\.\-_]{3,30})/(?P[\d]+)/$', 'render_primary', name='avatar_render_primary'), - url(r'^list/(?P[\+\w]+)/$', 'avatar_gallery', name='avatar_gallery'), - url(r'^list/(?P[\+\w]+)/(?P[\d]+)/$', 'avatar', name='avatar'), + url(r'^list/(?P[\+\w\@\.]+)/$', 'avatar_gallery', name='avatar_gallery'), + url(r'^list/(?P[\+\w\@\.]+)/(?P[\d]+)/$', 'avatar', name='avatar'), ) diff --git a/avatar/util.py b/avatar/util.py index ccb17be..5336a4d 100644 --- a/avatar/util.py +++ b/avatar/util.py @@ -8,21 +8,37 @@ try: from django.contrib.auth import get_user_model except ImportError: from django.contrib.auth.models import User + custom_user_model = False else: User = get_user_model() + custom_user_model = True from avatar.settings import (AVATAR_DEFAULT_URL, AVATAR_CACHE_TIMEOUT, AUTO_GENERATE_AVATAR_SIZES, AVATAR_DEFAULT_SIZE) cached_funcs = set() +def get_username(user): + """ Return username of a User instance """ + if hasattr(user, 'get_username'): + return user.get_username() + else: + return user.username + +def get_user(username): + """ Return user from a username/ish identifier """ + if custom_user_model: + return User.objects.get_by_natural_key(username) + else: + return User.objects.get(username=username) + def get_cache_key(user_or_username, size, prefix): """ Returns a cache key consisten of a username and image size. """ if isinstance(user_or_username, User): - user_or_username = user_or_username.username + user_or_username = get_username(user_or_username) key = u'%s_%s_%s' % (prefix, user_or_username, size) return u'%s_%s' % (slugify(key)[:100], md5_constructor(smart_str(key)).hexdigest()) @@ -74,7 +90,7 @@ def get_default_avatar_url(): def get_primary_avatar(user, size=AVATAR_DEFAULT_SIZE): if not isinstance(user, User): try: - user = User.objects.get(username=user) + user = get_user(user) except User.DoesNotExist: return None try: diff --git a/avatar/views.py b/avatar/views.py index f90621d..5910681 100644 --- a/avatar/views.py +++ b/avatar/views.py @@ -8,18 +8,12 @@ from django.views.decorators.csrf import csrf_exempt from django.contrib import messages from django.contrib.auth.decorators import login_required -try: - from django.contrib.auth import get_user_model -except ImportError: - from django.contrib.auth.models import User -else: - User = get_user_model() - from avatar.forms import PrimaryAvatarForm, DeleteAvatarForm, UploadAvatarForm from avatar.models import Avatar from avatar.settings import AVATAR_MAX_AVATARS_PER_USER, AVATAR_DEFAULT_SIZE from avatar.signals import avatar_updated -from avatar.util import get_primary_avatar, get_default_avatar_url +from avatar.util import ( + get_primary_avatar, get_default_avatar_url, User, get_user) def _get_next(request): @@ -179,7 +173,10 @@ def delete(request, extra_context=None, next_override=None, *args, **kwargs): def avatar_gallery(request, username, template_name="avatar/gallery.html"): - user = get_object_or_404(User, username=username) + try: + user = get_user(username) + except User.DoesNotExist: + raise Http404 return render_to_response(template_name, { "other_user": user, "avatars": user.avatar_set.all(), @@ -187,7 +184,10 @@ def avatar_gallery(request, username, template_name="avatar/gallery.html"): def avatar(request, username, id, template_name="avatar/avatar.html"): - user = get_object_or_404(User, username=username) + try: + user = get_user(username) + except User.DoesNotExist: + raise Http404 avatars = user.avatar_set.order_by("-date_uploaded") index = None avatar = None From 23ff54e356f29dbd0d55882ab17491c5776bf1b6 Mon Sep 17 00:00:00 2001 From: Simon Meers Date: Fri, 15 Mar 2013 21:49:04 +1100 Subject: [PATCH 3/5] Update usage {% url %} syntax --- docs/usage.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/usage.txt b/docs/usage.txt index 73785c6..327e8ba 100644 --- a/docs/usage.txt +++ b/docs/usage.txt @@ -28,7 +28,7 @@ that are required. A minimal integration can work like this: 3. Somewhere in your template navigation scheme, link to the change avatar page:: - Change your avatar + Change your avatar 4. Wherever you want to display an avatar for a user, first load the avatar template tags:: @@ -135,4 +135,4 @@ Management Commands This application does include one management command: ``rebuild_avatars``. It takes no arguments and, when run, re-renders all of the thumbnails for all of the avatars for the pixel sizes specified in the ``AUTO_GENERATE_AVATAR_SIZES`` -setting. \ No newline at end of file +setting. From fff8a4e1d221eb3bea4de6200959865de20296a7 Mon Sep 17 00:00:00 2001 From: Simon Meers Date: Fri, 15 Mar 2013 21:52:45 +1100 Subject: [PATCH 4/5] Update {% url %} syntax. Not bothering with loading from future for now. --- avatar/templates/avatar/add.html | 2 +- avatar/templates/avatar/change.html | 4 ++-- avatar/templates/avatar/confirm_delete.html | 4 ++-- .../templates/notification/avatar_friend_updated/notice.html | 2 +- setup.py | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/avatar/templates/avatar/add.html b/avatar/templates/avatar/add.html index a62df6c..9b4fed6 100644 --- a/avatar/templates/avatar/add.html +++ b/avatar/templates/avatar/add.html @@ -7,7 +7,7 @@ {% if not avatars %}

{% trans "You haven't uploaded an avatar yet. Please upload one now." %}

{% endif %} -
+ {{ upload_avatar_form.as_p }}

{% csrf_token %}

diff --git a/avatar/templates/avatar/change.html b/avatar/templates/avatar/change.html index 321da0d..8d27359 100644 --- a/avatar/templates/avatar/change.html +++ b/avatar/templates/avatar/change.html @@ -7,14 +7,14 @@ {% if not avatars %}

{% trans "You haven't uploaded an avatar yet. Please upload one now." %}

{% else %} -
+
    {{ primary_avatar_form.as_ul }}

{% csrf_token %}

{% endif %} -
+ {{ upload_avatar_form.as_p }}

{% csrf_token %}

diff --git a/avatar/templates/avatar/confirm_delete.html b/avatar/templates/avatar/confirm_delete.html index 5c54a7d..f81c815 100644 --- a/avatar/templates/avatar/confirm_delete.html +++ b/avatar/templates/avatar/confirm_delete.html @@ -4,10 +4,10 @@ {% block content %}

{% trans "Please select the avatars that you would like to delete." %}

{% if not avatars %} - {% url avatar_change as avatar_change_url %} + {% url 'avatar_change' as avatar_change_url %}

{% blocktrans %}You have no avatars to delete. Please upload one now.{% endblocktrans %}

{% else %} -
+
    {{ delete_avatar_form.as_ul }}
diff --git a/avatar/templates/notification/avatar_friend_updated/notice.html b/avatar/templates/notification/avatar_friend_updated/notice.html index 6d9b8c0..79c5d54 100644 --- a/avatar/templates/notification/avatar_friend_updated/notice.html +++ b/avatar/templates/notification/avatar_friend_updated/notice.html @@ -1,2 +1,2 @@ -{% load i18n %}{% url profile_detail username=user.username as user_url %}{# TODO: support custom user models via get_username #} +{% load i18n %}{% url 'profile_detail' username=user.username as user_url %}{# TODO: support custom user models via get_username; actually, is this template even used anymore? #} {% blocktrans with user as avatar_creator and avatar.get_absolute_url as avatar_url %}{{ avatar_creator }} has updated their avatar {{ avatar }}.{% endblocktrans %} diff --git a/setup.py b/setup.py index 7dc32ca..2df6037 100644 --- a/setup.py +++ b/setup.py @@ -33,7 +33,7 @@ that are required. A minimal integration can work like this: 3. Somewhere in your template navigation scheme, link to the change avatar page:: - Change your avatar + Change your avatar 4. Wherever you want to display an avatar for a user, first load the avatar template tags:: From 1685dbc76d8a89ea3c4a86116588d71f0b9c91da Mon Sep 17 00:00:00 2001 From: Simon Meers Date: Mon, 27 May 2013 08:59:44 +1000 Subject: [PATCH 5/5] {% load url from future %}. See fff8a4e1 :) --- avatar/templates/avatar/add.html | 1 + avatar/templates/avatar/change.html | 1 + avatar/templates/avatar/confirm_delete.html | 1 + avatar/templates/notification/avatar_friend_updated/notice.html | 2 +- 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/avatar/templates/avatar/add.html b/avatar/templates/avatar/add.html index 9b4fed6..7a04b34 100644 --- a/avatar/templates/avatar/add.html +++ b/avatar/templates/avatar/add.html @@ -1,5 +1,6 @@ {% extends "avatar/base.html" %} {% load i18n avatar_tags %} +{% load url from future %} {% block content %}

{% trans "Your current avatar: " %}

diff --git a/avatar/templates/avatar/change.html b/avatar/templates/avatar/change.html index 8d27359..7e7b3d2 100644 --- a/avatar/templates/avatar/change.html +++ b/avatar/templates/avatar/change.html @@ -1,5 +1,6 @@ {% extends "avatar/base.html" %} {% load i18n avatar_tags %} +{% load url from future %} {% block content %}

{% trans "Your current avatar: " %}

diff --git a/avatar/templates/avatar/confirm_delete.html b/avatar/templates/avatar/confirm_delete.html index f81c815..373131d 100644 --- a/avatar/templates/avatar/confirm_delete.html +++ b/avatar/templates/avatar/confirm_delete.html @@ -1,5 +1,6 @@ {% extends "avatar/base.html" %} {% load i18n %} +{% load url from future %} {% block content %}

{% trans "Please select the avatars that you would like to delete." %}

diff --git a/avatar/templates/notification/avatar_friend_updated/notice.html b/avatar/templates/notification/avatar_friend_updated/notice.html index 79c5d54..c2ba8bc 100644 --- a/avatar/templates/notification/avatar_friend_updated/notice.html +++ b/avatar/templates/notification/avatar_friend_updated/notice.html @@ -1,2 +1,2 @@ -{% load i18n %}{% url 'profile_detail' username=user.username as user_url %}{# TODO: support custom user models via get_username; actually, is this template even used anymore? #} +{% load i18n %}{% load url from future %}{% url 'profile_detail' username=user.username as user_url %}{# TODO: support custom user models via get_username; actually, is this template even used anymore? #} {% blocktrans with user as avatar_creator and avatar.get_absolute_url as avatar_url %}{{ avatar_creator }} has updated their avatar {{ avatar }}.{% endblocktrans %}