jitesh2796
jitesh2796

Reputation: 304

django creating dupliucate images as and when the profile page is loaded

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: enter image description here

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

Answers (2)

user1600649
user1600649

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

Joseba S.
Joseba S.

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

Related Questions