jonnyd42
jonnyd42

Reputation: 500

Django Cannot Update User Profile Picture

I have created a custom UserProfile model, and want to allow the user to edit his or her profile's fields. The other fields are editable, but the ImageField is not. I am able to store an uploaded image into my target directory (media/profile_pics), but I'm not sure how to link this to the user who is currently logged in so that he or she can navigate back to the profile page and see the new picture.

The code in my views.py is pretty messy. I'm hoping someone can teach me a better way of doing it because it's hacked together with partial understanding.

models.py

#custom user profile
class UserProfile(models.Model):
    user = models.OneToOneField(User)
    description = models.CharField(max_length=200, default='')
    city = models.CharField(max_length=100, default='')

    profile_pic = models.ImageField(upload_to='profile_pics', blank=True)

    def __str__(self):
        return self.user.username

def create_profile(sender, **kwargs):
    #if user object has been created, we want to create user profile
    if kwargs['created']:
                                                    #returns the instance of our user object
        user_profile = UserProfile.objects.create(user=kwargs['instance'])
#connecting to the post_save signal. Pass in a function that should run
post_save.connect(create_profile, sender=User)

When the user navigates to the place where they can edit their profile, the view function "edit_profile" is used. Here it is in views.py:

def edit_profile(request):
    user_profile = UserProfile.objects.get(user=request.user)
    profile_form = UserProfileForm(instance=user_profile)

    if request.method == 'POST':
        update_profile_form = UserProfileForm(data=request.POST, instance=user_profile)

                                            #so we know the user object
        form = EditProfileForm(request.POST, instance=request.user)

        if form.is_valid() and update_profile_form.is_valid():
            user = form.save()
            update_profile_form.save()

            handle_uploaded_file(request, request.FILES['profile_pic'])

            #return redirect(reverse('userapp:profile'))
            args = {'profile_form': update_profile_form}

            return render(request, 'userapp/profile.html', args)

    else:
        form = EditProfileForm(instance=request.user)
        args = {'form': form, 'profile_form': profile_form}
        return render(request, 'userapp/edit_profile.html', args)

The following function is used by edit_profile to save the file into my target directory. This was taken from the Django documentation:

def handle_uploaded_file(request, f):
    with open(os.getcwd() + "/media/profile_pics/" + f.name, 'wb+') as destination:
        for chunk in f.chunks():
            destination.write(chunk)

forms.py

class UserProfileForm(forms.ModelForm):
   # profile_pic = forms.ImageField()
    class Meta:
        model = UserProfile
        fields = ('profile_pic','city', 'description',)



class EditProfileForm(UserChangeForm):
    #template_name='/something/else'

    class Meta:
        model = User
        fields = (
            'email',
            'first_name',
            'last_name',
            'password'
            #'profile_pic'
        )

I display the following HTML, "edit_profile.html" for the user to update the fields:

{% extends 'base.html' %}
{% block title %} Profile {% endblock %}


{% block body %}
    <div class="container-fluid">
        <form method="post" enctype='multipart/form-data'>
            {% csrf_token %}
            {{  form.as_p }}
            {{ profile_form.as_p }}

            <button type="submit">Submit</button>

        </form>
        <br>
    </div>

{% endblock %}

Here is the user profile HTML. After an update, when the user navigates back to the profile, their newly uploaded picture should display:

{% extends 'base.html' %}
{% block title %} Profile {% endblock %}


{% block body %}
    <div class="container-fluid">
        <h2>Profile</h2>
        <p>{{ user }}</p>
        <p>First name: {{ user.first_name }}</p>
        <p>Last name: {{ user.last_name }}</p>
        <p>Email: {{ user.email }}</p>
        <p> City: {{ profile_form.instance.city }}</p>
        <p> Description: {{ profile_form.instance.description }}</p>
        <p>
            {% if profile_form.instance.profile_pic %}
                <img src="{{ profile_form.instance.profile_pic.url}}" border-radius=10px style="width:256px;height:256px;" />
            {% endif %}
        </p>


    </div>

{% endblock %}

Upvotes: 1

Views: 2024

Answers (1)

Sandeep Balagopal
Sandeep Balagopal

Reputation: 1983

You have to pass request.FILES in form. See here https://docs.djangoproject.com/en/1.10/topics/http/file-uploads/

Upvotes: 1

Related Questions