Zagorodniy Olexiy
Zagorodniy Olexiy

Reputation: 2212

Django - modelform doesn't save image

I use Ubuntu 14.10 and apache2 web server. In my Django project i have the model with additional information about user:

class UserProfile(models.Model):
   class Meta:
      verbose_name_plural = u'User profile'

   user = models.OneToOneField(User)
   birthday = models.DateField(blank=True, null=True)
   avatar = models.ImageField(upload_to='media/profile/avatar', blank=True, null=True)
   name = models.CharField(blank=True, null=True, max_length=20)
   surname = models.CharField(blank=True, null=True, max_length=50)
   phone = models.CharField(blank=True, null=True, max_length=12)

   def __unicode__(self):
      return '%s' % self.user

Here is my form:

class ExtraProfileDataForm(ModelForm):
   name = forms.CharField(label=(u'Enter your name'))
   surname = forms.CharField(label=(u'Enter your surname'))
   phone = forms.CharField(label=(u'Enter your phone'))
   birthday = forms.DateField(label=(u'Birthday'))
   avatar = forms.ImageField(label=(u'Avatar'))

   class Meta:
      model = UserProfile
      fields = ('name', 'surname', 'phone', 'birthday', 'avatar')

   def __init__(self, *args, **kwargs):
      super(ExtraProfileDataForm, self).__init__(*args, **kwargs)
         for key in self.fields:
            self.fields[key].required = False

And this is the view:

@login_required
def UserFullDataForm(request):
   if request.method == 'POST':
      form = ExtraProfileDataForm(request.POST)
      if form.is_valid():
         profile_user = request.user
         user_profile, created = UserProfile.objects.get_or_create(user=profile_user)
         user_profile.name = form.cleaned_data['name']
         user_profile.surname = form.cleaned_data['surname']
         user_profile.phone = form.cleaned_data['phone']
         user_profile.birthday = form.cleaned_data['birthday']
         user_profile.avatar = form.cleaned_data['avatar']
         user_profile.save()
         return HttpResponseRedirect('/profile/')
      else:
         return render(request, 'profiles/extra_profile.html', {'form':form})
   else:
         form = ExtraProfileDataForm()
         context = {'form':form}
         return render (request, 'profiles/extra_profile.html', context)

When i fill the form all fields saved to the database except image field. Chown of media/profile/avatar folders is www-data and chmod is 775. Log files is empty. I have no any errors to understand why its happens. Can you help me understand why its happens or what i have to do to see the error. Thank you. PS. this how looks like media of the project in apache config:

Alias /media/ /var/www/project/media/
    <Directory /var/www/project/>
        Options Indexes MultiViews FollowSymLinks
        AllowOverride None
        Require all granted
    </Directory>

Upvotes: 1

Views: 2965

Answers (3)

Nostalg.io
Nostalg.io

Reputation: 3752

For me, the issue had nothing to do with my Python code, which correctly did not return any errors.

The issue was my <form> html did not have enctype set to support file post.

Example:

<form action="." method="post" accept-charset="utf-8" enctype="multipart/form-data">
    {{ form }}
</form>

Upvotes: 2

Muhammad Hassan
Muhammad Hassan

Reputation: 14391

You have some code which is not required. Just remove that code as form.save() will save your form. Change your view like this.

def UserFullDataForm(request):
    if request.method == 'POST':
        form = ExtraProfileDataForm(request.POST, request.FILES)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect('/profile/')
        else:
            return render(request, 'profiles/extra_profile.html', {'form':form})
    else:
        form = ExtraProfileDataForm()
        context = {'form':form}
        return render (request, 'profiles/extra_profile.html', context)

As you form is storing data in two different tables, you have to write your own save function for your form like this.

def save(self, commit=True, **kwargs):
    user = super(UserCreateForm, self).save(commit=False)
    # get or create record for UserProfile against user and save it

In your settings.py, add following

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

In your project urls.py, add following line at the end

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

You model will be changed like this

avatar = models.ImageField(upload_to='profile/avatar', blank=True, null=True)

Upvotes: 0

Kamlesh
Kamlesh

Reputation: 2056

You may need to pass request.FILES in form = ExtraProfileDataForm(request.POST, request.FILES)

def UserFullDataForm(request):
   if request.method == 'POST':
      form = ExtraProfileDataForm(data=request.POST, files=request.FILES)
      if form.is_valid():

         user_form = form.save(commit=False)

         user_form.user = request.user
         user_form.save()

         return HttpResponseRedirect('/profile/')
      else:
         return render(request, 'profiles/extra_profile.html', {'form':form})
   else:
         form = ExtraProfileDataForm()
         context = {'form':form}
         return render (request, 'profiles/extra_profile.html', context)

Upvotes: 2

Related Questions