Use django-imagekit to allow uploading avatar images. Fixes #41
This commit is contained in:
parent
ef77c8faed
commit
353286e1d6
10 changed files with 27 additions and 9 deletions
|
@ -2,6 +2,10 @@ from django.db import models
|
||||||
from django.contrib.sites.models import Site
|
from django.contrib.sites.models import Site
|
||||||
from django.contrib.auth.models import User, Group, AnonymousUser
|
from django.contrib.auth.models import User, Group, AnonymousUser
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
from imagekit.models import ProcessedImageField
|
||||||
|
from imagekit.processors import ResizeToFill
|
||||||
|
|
||||||
from .locale import *
|
from .locale import *
|
||||||
|
|
||||||
|
@ -15,7 +19,10 @@ class UserProfile(models.Model):
|
||||||
user = models.OneToOneField(User, on_delete=models.CASCADE)
|
user = models.OneToOneField(User, on_delete=models.CASCADE)
|
||||||
realname = models.CharField(verbose_name=_("Real Name"), max_length=150, blank=True)
|
realname = models.CharField(verbose_name=_("Real Name"), max_length=150, blank=True)
|
||||||
tz = models.CharField(max_length=32, verbose_name=_('Timezone'), default='UTC', choices=[(tz, tz) for tz in pytz.all_timezones], blank=False, null=False)
|
tz = models.CharField(max_length=32, verbose_name=_('Timezone'), default='UTC', choices=[(tz, tz) for tz in pytz.all_timezones], blank=False, null=False)
|
||||||
avatar = models.URLField(verbose_name=_("Photo Image"), max_length=150, blank=True, null=True)
|
avatar = ProcessedImageField(verbose_name=_("Photo Image"),
|
||||||
|
upload_to='avatars',
|
||||||
|
processors=[ResizeToFill(128, 128)],
|
||||||
|
format='PNG')
|
||||||
|
|
||||||
web_url = models.URLField(verbose_name=_('Website URL'), blank=True, null=True)
|
web_url = models.URLField(verbose_name=_('Website URL'), blank=True, null=True)
|
||||||
twitter = models.CharField(verbose_name=_('Twitter Name'), max_length=32, blank=True, null=True)
|
twitter = models.CharField(verbose_name=_('Twitter Name'), max_length=32, blank=True, null=True)
|
||||||
|
@ -37,6 +44,12 @@ class UserProfile(models.Model):
|
||||||
except:
|
except:
|
||||||
return "Unknown Profile"
|
return "Unknown Profile"
|
||||||
|
|
||||||
|
def avatar_url(self):
|
||||||
|
if self.avatar.url.startswith('http'):
|
||||||
|
return self.avatar.url
|
||||||
|
else:
|
||||||
|
return settings.MEDIA_URL + '/' + self.avatar.url
|
||||||
|
|
||||||
def get_timezone(self):
|
def get_timezone(self):
|
||||||
try:
|
try:
|
||||||
return pytz.timezone(self.tz)
|
return pytz.timezone(self.tz)
|
||||||
|
|
|
@ -43,6 +43,8 @@ INSTALLED_APPS = [
|
||||||
'django.contrib.sites',
|
'django.contrib.sites',
|
||||||
'rest_framework',
|
'rest_framework',
|
||||||
'social_django',
|
'social_django',
|
||||||
|
'imagekit',
|
||||||
|
'imagekit_cropper',
|
||||||
|
|
||||||
'get_together',
|
'get_together',
|
||||||
'events',
|
'events',
|
||||||
|
@ -180,3 +182,5 @@ try:
|
||||||
except:
|
except:
|
||||||
print("WARNING: You should create a local_settings.py to store local and secret data.")
|
print("WARNING: You should create a local_settings.py to store local and secret data.")
|
||||||
|
|
||||||
|
MEDIA_ROOT = './media/'
|
||||||
|
MEDIA_URL = '/media/'
|
||||||
|
|
|
@ -72,7 +72,7 @@ form {
|
||||||
{% if request.user.is_authenticated %}
|
{% if request.user.is_authenticated %}
|
||||||
<li class="nav-item dropdown">
|
<li class="nav-item dropdown">
|
||||||
<a class="nav-link dropdown-toggle" href="#" id="navbarUserMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
<a class="nav-link dropdown-toggle" href="#" id="navbarUserMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
<img class="rounded-circle mr-1" src="{{request.user.profile.avatar}}" height="24px"/>{% if request.user.profile.realname %}{{ request.user.profile.realname }}{% else %}{{ request.user.username }}{% endif %}
|
<img class="rounded-circle mr-1" src="{{request.user.profile.avatar.url}}" height="24px"/>{% if request.user.profile.realname %}{{ request.user.profile.realname }}{% else %}{{ request.user.username }}{% endif %}
|
||||||
</a>
|
</a>
|
||||||
<div class="dropdown-menu" aria-labelledby="navbarUserMenuLink">
|
<div class="dropdown-menu" aria-labelledby="navbarUserMenuLink">
|
||||||
<a class="dropdown-item" href="{% url 'show-profile' request.user.profile.id %}">Profile</a>
|
<a class="dropdown-item" href="{% url 'show-profile' request.user.profile.id %}">Profile</a>
|
||||||
|
|
|
@ -72,7 +72,7 @@
|
||||||
{% for attendee in attendee_list %}
|
{% for attendee in attendee_list %}
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<div class="col media gt-profile">
|
<div class="col media gt-profile">
|
||||||
<img class="mr-1 gt-profile-avatar" src="{{attendee.user.avatar}}" width="32px" height="32px">
|
<img class="mr-1 gt-profile-avatar" src="{{attendee.user.avatar.url}}" width="32px" height="32px">
|
||||||
<span class="gt-profile-badges">{% for badge in attendee.user.user.account.badges.all %}<img class="mr-0 gt-profile-badge" src="{{badge.img_url}}" title="{{badge.name}}" width="16px" height="16px">{% endfor %}</span>
|
<span class="gt-profile-badges">{% for badge in attendee.user.user.account.badges.all %}<img class="mr-0 gt-profile-badge" src="{{badge.img_url}}" title="{{badge.name}}" width="16px" height="16px">{% endfor %}</span>
|
||||||
<div class="media-body">
|
<div class="media-body">
|
||||||
<h6 class="mt-2 mb-0">
|
<h6 class="mt-2 mb-0">
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<center>
|
<center>
|
||||||
<p><img class="align-bottom" border="1" src="{{profile.avatar}}" height="64px"/></p>
|
<p><img class="align-bottom" border="1" src="{{profile.avatar.url}}" height="64px"/></p>
|
||||||
<h3>Please confirm your profile information</h3>
|
<h3>Please confirm your profile information</h3>
|
||||||
|
|
||||||
<form action="{% url 'setup-1-confirm-profile' %}" method="POST" class="form">
|
<form action="{% url 'setup-1-confirm-profile' %}" method="POST" class="form">
|
||||||
|
|
|
@ -58,7 +58,7 @@
|
||||||
{% for member in member_list %}
|
{% for member in member_list %}
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<div class="col media gt-profile">
|
<div class="col media gt-profile">
|
||||||
<img class="mr-1 gt-profile-avatar" src="{{member.user.avatar}}" width="32px" height="32px">
|
<img class="mr-1 gt-profile-avatar" src="{{member.user.avatar.url}}" width="32px" height="32px">
|
||||||
<span class="gt-profile-badges">{% for badge in member.user.user.account.badges.all %}<img class="mr-0 gt-profile-badge" src="{{badge.img_url}}" title="{{badge.name}}" width="16px" height="16px">{% endfor %}</span>
|
<span class="gt-profile-badges">{% for badge in member.user.user.account.badges.all %}<img class="mr-0 gt-profile-badge" src="{{badge.img_url}}" title="{{badge.name}}" width="16px" height="16px">{% endfor %}</span>
|
||||||
<div class="media-body">
|
<div class="media-body">
|
||||||
<h6 class="mt-0 mb-0"><a href="{% url 'show-profile' member.user.id %}" title="{{member.user}}'s profile">{{member.user}}</a></h6>
|
<h6 class="mt-0 mb-0"><a href="{% url 'show-profile' member.user.id %}" title="{{member.user}}'s profile">{{member.user}}</a></h6>
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<img class="align-bottom" border="1" src="{{profile.avatar}}" height="64px"/>
|
<img class="align-bottom" border="1" src="{{profile.avatar.url}}" height="128px"/>
|
||||||
<h2>Profile: {{user}}</h2>
|
<h2>Profile: {{user}}</h2>
|
||||||
<form action="{% url "edit-profile" %}" method="post">
|
<form enctype="multipart/form-data" action="{% url "edit-profile" %}" method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{% include "events/profile_form.html" %}
|
{% include "events/profile_form.html" %}
|
||||||
<br />
|
<br />
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
<div class="col-md-2"></div>
|
<div class="col-md-2"></div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<div class="h2">
|
<div class="h2">
|
||||||
<img class="align-bottom" border="1" src="{{user.avatar}}" height="64px"/> {{user.user}}
|
<img class="align-bottom" border="1" src="{{user.avatar.url}}" height="128px"/> {{user.user}}
|
||||||
{% if user.user.id == request.user.id %}
|
{% if user.user.id == request.user.id %}
|
||||||
<a href="{% url 'edit-profile' %}" class="btn btn-secondary btn-sm">Edit Profile</a>
|
<a href="{% url 'edit-profile' %}" class="btn btn-secondary btn-sm">Edit Profile</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -72,3 +72,4 @@ urlpatterns = [
|
||||||
]
|
]
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
urlpatterns = urlpatterns + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
urlpatterns = urlpatterns + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
||||||
|
urlpatterns = urlpatterns + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||||
|
|
|
@ -71,7 +71,7 @@ def edit_profile(request):
|
||||||
elif request.method == 'POST':
|
elif request.method == 'POST':
|
||||||
old_email = request.user.email
|
old_email = request.user.email
|
||||||
user_form = UserForm(request.POST, instance=user)
|
user_form = UserForm(request.POST, instance=user)
|
||||||
profile_form = UserProfileForm(request.POST, instance=profile)
|
profile_form = UserProfileForm(request.POST, request.FILES, instance=profile)
|
||||||
if user_form.is_valid() and profile_form.is_valid():
|
if user_form.is_valid() and profile_form.is_valid():
|
||||||
user = user_form.save()
|
user = user_form.save()
|
||||||
profile = profile_form.save()
|
profile = profile_form.save()
|
||||||
|
|
Loading…
Reference in a new issue