-1

I'm trying to upload a user photo and show it in homepage.

problem 1 : When i upload an image from admin section it gets saved in database but it doesn't show up in 'homepage.html'.

Problem 2 : When i try to upload an image using 'profile.html' template the image is not even saved in database.

I've tried several solution from stackoverflow but failed to solve my problem. My code is given below:

models.py

from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver


class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
    first_name= models.CharField(max_length=100, default='', blank=True)
    last_name = models.CharField(max_length=100, default='', blank=True)
    email = models.CharField(max_length=100, default='', blank=True)
    pro_pic = models.ImageField(upload_to='profilepic',blank=True)
    phone = models.CharField(max_length=20, blank=True, default='')
    city = models.CharField(max_length=100, default='', blank=True)
    country = models.CharField(max_length=100, default='', blank=True)
    job = models.CharField(max_length=20, blank=True, default='')
    organization = models.CharField(max_length=100, default='', blank=True)

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

    @receiver(post_save, sender=User)
    def create_user_profile(sender, instance, created, **kwargs):
        if created:
            UserProfile.objects.create(user=instance)

    @receiver(post_save, sender=User)
    def save_user_profile(sender, instance, **kwargs):
        instance.profile.save()

forms.py

from django.contrib.auth.models import User
from django import forms
from .models import UserProfile


class UserForm(forms.ModelForm):
    class Meta:
        model = UserProfile
        fields = ['first_name', 'last_name', 'email']

class ProfileForm(forms.ModelForm):
    class Meta:
        model = UserProfile
        fields = ['pro_pic','phone', 'city', 'country', 'job', 'organization']

settings.py

MEDIA_URL = '/media/'
MEDIA_ROOT=os.path.join(BASE_DIR,'obs/media')

views.py

@login_required
@transaction.atomic
def update_profile(request):
    if request.method == 'POST':
        user_form = UserForm(request.POST, instance=request.user)
        profile_form = ProfileForm(request.POST, instance=request.user.profile)
        if user_form.is_valid() and profile_form.is_valid():
            user_form.save()
            profile_form.save()
            messages.success(request,'Your profile was successfully updated!')
            return redirect('obs:homepage')
        else:
            messages.error(request, 'Please correct the error below.')
    else:
        user_form = UserForm(instance=request.user)
        profile_form = ProfileForm(instance=request.user.profile)
    return render(request, 'obs/profile.html', {
        'user_form': user_form,
        'profile_form': profile_form
    })

profile.html

{% extends 'obs/base.html' %}


{% block body %}
{% load staticfiles %}
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
    <link href='https://fonts.googleapis.com/css?family=Satisfy' rel='stylesheet' type='text/css'>
    <link rel="stylesheet" type="text/css" href="{% static 'obs/profilecss.css' %}"/>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>



<head>
    <title>Profile</title>
</head>

<div class="container">
    <div class="row">
        <div class="col-md-5 col-md-offset-3">
            <div class="panel panel-default">
                <div class="panel-heading">
                    <span class="glyzphicon glyphicon-user"></span> Update User Profile</div>

                <div class="panel-body">
                    {% if error_message %}
                        <p><strong>{{ error_message }}</strong></p>
                    {% endif %}
                 <form method="post" class="hello">
                  {% csrf_token %}

                 {% for field in user_form %}

                    <div class="form-group">
                        <label  class="col-sm-15 control-label">
                            {{ field.label_tag }}</label>
                        {{ field }}

                    </div>

                {% endfor %}

                {% for field in profile_form %}

                    <div class="form-group">
                        <label  class="col-sm-15 control-label">
                            {{ field.label_tag }}</label>
                        {{ field }}

                    </div>

                {% endfor %}
                  <center>
                  <div class="buttonHolder">
                      <button class="button tick" type="submit"></button>


                  </div>
                 </center>
                </form>
                </div>
            </div>
        </div>
    </div>
</div>

{% endblock %}

homepage.html

<div class="profile-userpic">
    <img src="{{ profile_form.pro_pic.url }}" class="img-responsive" alt="">
</div>

urls.py (project)

from django.conf.urls import include, url
from django.contrib import admin
from django.conf import settings
from django.conf.urls.static import static



urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^onlinebookshare/', include('registration.urls', namespace="accounts")),

]+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

view for homepage:

@login_required
@transaction.atomic
def update_home(request):

    user_form = UserForm(instance=request.user)
    profile_form = ProfileForm(instance=request.user.profile)
    return render(request, 'obs/homepage.html', {
        'user_form': user_form,
        'profile_form': profile_form
    })
jef
  • 23
  • 2
  • 6

2 Answers2

2

First you need to create the MEDIA_ROOT directory and upload_to directory as you specified.

MEDIA_ROOT=os.path.join(BASE_DIR,'obs/media')
pro_pic = models.ImageField(upload_to='profilepic',blank=True)

In the form tag where you upload the profile pic you need to add the following enctype='multipart/form-data' like

<form method="post" enctype="multipart/form-data" class="hello">.

In the update_profile view change the following line:

profile_form = ProfileForm(request.POST, instance=request.user.profile) 

to

profile_form = ProfileForm(request.POST, instance=request.user.profile, request.FILES or None)

Hope this will help.

akimul
  • 319
  • 1
  • 5
1

What you're doing is a bit odd. You're trying to access the already-uploaded file, whose URL is stored in a field of the model, via the form. The immediate cause of the problem is that a form field doesn't know about URLs, it just has a value. You would need to access it via the underlying form instance, which you passed in as the profile - so, {{ profile_form.instance.pro_pic.url }}.

But I can't see why you are doing this. Displaying things is not the responsibility of the form anyway. You should just use the profile directly, which is already available via the user object.

{{ user.profile.pro_pic.url }}

For the second problem, you need to pass the uploaded files to the form:

profile_form = ProfileForm(request.POST, request.FILES, instance=request.user.profile)
Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
  • thank you so much. i'm using django for the first time. sorry for my stupidity. you solved my first problem. kindly check the second one please – jef Nov 22 '17 at 18:45
  • after adding "{{ user.profile.pro_pic.url }}" i get "The 'pro_pic' attribute has no file associated with it." this error in this line in 'homepage.html' if the user doesn't have any profile pic – jef Nov 22 '17 at 19:31