Reputation: 304
In my Django app, I have a user profile page displaying the user profile image apart from the other information.
Every time I load this page, a duplicate copy of image is created with an additional 'key' and is saved in my media folder. I'm facing difficulty in resolving this
This is what my user model looks like:
class CustomUser(AbstractUser):
email =models.EmailField(unique =True)
state = models.CharField(max_length =100)
city = models.CharField(max_length=100)
is_active =models.BooleanField(default=False)
about_me =models.TextField(max_length=255,default =None,blank=True,null =True)
user_image =models.ImageField(upload_to="images",default =None,null =True,blank=True)
def save(self,*args,**kwargs):
try:
# opening the uploaded image
im =Image.open(self.user_image)
output =BytesIO()
# resize image
im =im.resize((130,100))
# after modification, save to ouput
im.save(output,format ='JPEG',quality =100)
output.seek(0)
self.user_image =InMemoryUploadedFile(output,'ImageField',"%s.jpg" % self.user_image.name.split('.')[0],'image/jpeg',
sys.getsizeof(output),None )
except: pass
super(CustomUser,self).save()
def get_absolute_url(self):
return reverse('view_profile',args =[(self.pk)])
Let me know if you need anything else
This is the functions that renders My Profile page
@login_required
def my_profile(request):
user =request.user
template ='my_profile_up.html'
return render(request,template,{'profile':user})
urls.py:
...
urlpatterns=[
path('signup/',views.SignUp.as_view(),name ='signup'),
path('myprofile/',views.my_profile,name ='my_profile'),
path('profile_edit/',views.my_profile_edit,name='profile_edit'),
path('confirm-email/<str:user_id>/<str:token>/',views.ConfirmRegistrationView.as_view(),name='confirm_email'),
path('signup_confirm/',views.signup_confirm,name='signup_confirm'),
path('signup_confirm/complete/',views.signup_complete,name ='signup_complete'),
path('profile/<int:user_id>/',views.view_profile,name='view_profile'),
]
Adding a snip of my media folder to show how it keeps on creating duplicates if it helps:
Template rendering my profile:
{% extends 'base.html' %}
{% block title %}My Profile | ReadingRoots{% endblock %}
{% block content %}
<div class="container base-container">
<div class="emp-profile shadow">
<div class="row">
<div class="col-md-4 col-3">
<div class="profile-img">
{% if profile.user_image %}
<img src ="{{profile.user_image.url}}" class="img-responsive image-circle" />
{% else %}
<img src="/media/images/reader.png" class="img-responsive image-circle bg-white">
{% endif %}
</div>
</div>
<div class="col-md-8 col-9">
<div class="profile-head">
<div class="row">
<h4 class="col-md-9 col-6">
{{ profile.username }}
</h4>
<div class="col-md-3 col-6 mt-1">
<a class="profile-edit-btn" href="{% url 'profile_edit' %}">Edit Profile</a>
</div>
</div>
{% if profile.about_me %}
<h6>{{profile.about_me}}</h6>
{% endif %}
</div>
</div>
<!-- <div class="col-md-2">
</div> -->
</div>
<div class="row">
<div class="col-md-4 text-center">
<div class="col-md-8">
<div class="profile-head">
<ul class="nav nav-tabs" id="myTab" role="tablist">
<li class="nav-item">
<a class="nav-link active" id="home-tab" data-toggle="tab" href="#home" role="tab" aria-controls="home" aria-selected="true">About</a>
</li>
</ul>
</div>
<div class="tab-content profile-tab" id="myTabContent">
<div class="tab-pane fade show active" id="home" role="tabpanel" aria-labelledby="home-tab">
<div class="row">
<div class="col-md-5 col-5">
<i class="fa fa-user fa-lg mr-1"></i>
<label>Username</label>
</div>
<div class="col-md-7 col-7">
<p>{{profile.username}}</p>
</div>
</div>
<div class="row">
<div class="col-md-5 col-5">
<i class="fa fa-envelope fa-lg mr-1"></i>
<label>Email</label>
</div>
<div class="col-md-7 col-7" style="overflow-wrap: break-word;">
<p>{{profile.email}}</p>
</div>
</div>
<div class="row">
<div class="col-md-5 col-5">
<i class="fa fa-map-marker fa-lg mr-1"></i>
<label>City</label>
</div>
<div class="col-md-7 col-7">
<p>{{profile.city}}</p>
</div>
</div>
<div class="row">
<div class="col-md-5 col-5">
<i class="fa fa-globe fa-lg mr-1"></i>
<label>State</label>
</div>
<div class="col-md-7 col-7">
<p>{{profile.state}}</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
I'm not sure if the issue is with the my_profile
function, it's not like it always creates a duplicate when I open this page, though somehow it keeps on adding images. I've not exactly identified the pattern yet..
Upvotes: 0
Views: 138
Reputation:
Your core problem is that you've made image resizing a side effect and are now wondering why it happens when you don't ask for it. You should be resizing the image, when a new profile image is uploaded - instead, you resize when your custom user is saved.
Secondly - this is a common pattern. There's lots of sites that resize images to fit their layout and chances are, somebody made a package that you can readily use. And that is also the case here, for example django-imagekit.
In your case, your custom user would look like this:
from django.db import models
from imagekit.models import ProcessedImageField
from imagekit.processors import ResizeToFill
class CustomUser(AbstractUser):
email = models.EmailField(unique =True)
state = models.CharField(max_length =100)
city = models.CharField(max_length=100)
is_active = models.BooleanField(default=False)
about_me = models.TextField(max_length=255,default =None,blank=True,null =True)
user_image = ProcessedImageField(
upload_to="images", processors=[ResizeToFill(130, 100)],
format='JPEG', options={'quality': 100}
)
def get_absolute_url(self):
return reverse('view_profile',args =[(self.pk)])
That's it. No custom rolled save method to worry about and no side effects. When a new image is uploaded, it will be resized again, but if nothing is uploaded, nothing will happen.
Upvotes: 1
Reputation: 181
Since it is a model that extends from the base User model, you need to take into account that that model has a full logic behind the curtain, and for example the last_login
field is updated when a user connects, so that would trigger your overriden save()
method and duplicate the image.
To avoid this, I would try to separate the logic that creates the image from the save()
method and do it in the form processing instead.
Upvotes: 0