Search code examples
djangodjango-formsdjango-viewsimagefield

Django ImageField won't upload in function based view, but it does in the admin


I've been trying to add some user uploaded profile picture to my website. It works fine when I do it from the admin, the image is showed and all the engines seems to be working fine (image going to the correct upload location and so on). The problem is when I try to do the same thing from my view.

I noticed that the print("upload_location") only appears when I do it from the admin. The weird thing is that all the other fields in my Profile model are working fine (like name "foo" is updated to "foobar") and not only in the admin, but in the view as well. The issue is only with the ImageField.

I believe it could have something to do with the way I'm handling the form.is_valid(), but I've been playing around with that and nothing changed (I know it is working to some extend, since HttpResponseRedirect is working.

Any ideas?

views.py

...

@login_required
def profile_update(request, username=None):
    obj = get_object_or_404(User, username=username)
    user = obj.profile
    form = ProfileForm(request.POST or None, instance = user)
    context = {
        "form": form
    }
    if form.is_valid():
        form.save()
        return HttpResponseRedirect('/profiles/{username}'.format(username=user.user))
    template = 'profile_update.html'
    return render(request, template, context)

forms.py

from django import forms
from .models import Profile

class ProfileForm(forms.ModelForm):
    class Meta:
        model = Profile
        fields = [
            "profilePic",
            "nome",
             ...
        ]

    def profile(self, request, user):
        print('printing forms')
        user.uf = self.cleaned_data['uf']
        user.cidade = self.cleaned_data['cidade']
        user.telefone = self.cleaned_data['telefone']
        user.save()

models.py

...

User = settings.AUTH_USER_MODEL # 'auth.User'

def upload_location(instance, filename):
    print("upload_location")
    return "%s/%s" %(instance.user, filename)

class Profile(models.Model):
    user = models.OneToOneField(User)
    id = models.AutoField(primary_key=True)
    width = models.IntegerField(default=0, null=True, blank=True,)
    height = models.IntegerField(default=0, null=True, blank=True,)
    profilePic = models.ImageField(
                upload_to = upload_location,
                blank=True, null=True,
                verbose_name = 'Foto de Perfil',
                width_field="width",
                height_field="height",
                )
    ...

template.html

...

<form action="" method="POST" enctype="multipart/form-data">{% csrf_token %}
                {{ form|crispy }}
                <input type="submit" value="Enviar" class="btn btn-primary"/>
            </form>
...

Solution

  • You need to add FILES into the form.

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

    Docs: https://docs.djangoproject.com/en/1.10/topics/http/file-uploads/