1

I'm trying to upload an image. This is an avatar image for the profile of the user.

Currently, the form return no error, but I have nothing written on my database or in my folder media/avatar/.

What's wrong ?

My view :

def view_avatar(request):
    if request.method == 'POST':
        form = UploadFileForm(request.POST, request.FILES, instance=request.user.profile)
        if form.is_valid():
            form.save()            
    else:
        form = UploadFileForm(instance=request.user.profile)
    return render(request, 'avatar.html', locals())

My form :

class UploadFileForm(forms.ModelForm):
    class Meta:
        model = Profile
        fields = ('avatar',)

My model :

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    birthdate = models.DateField(null=True, blank=True)
    avatar = models.ImageField(upload_to='media/avatar/', blank=True, null=True)
6
  • Did you added form.save() after validating form in your code.? It is not in code snippest you provide. Commented Jun 29, 2017 at 9:43
  • No Ididn't in this code. But when I add it, I have an error : UploadFileForm' object has no attribute 'save'. I update my code right now. Commented Jun 29, 2017 at 9:54
  • You should either use ModelForm or write your custom save method. forms.Form do not have any save method. That is why you are getting this error. Commented Jun 29, 2017 at 10:02
  • 1
    Just as an aside (because it has tripped me up so often) make sure to include enctype="multipart/form-data" in your form if you are uploading files. Commented Jun 29, 2017 at 12:18
  • 1
    @The_Cthulhu_Kid Thank you ! Simpliest as that ! Commented Jun 29, 2017 at 20:52

4 Answers 4

1

It's because the form which you are using is inherited from forms.Form , you need to use forms.ModelForm for saving the instance directly.

Change this line,

class UploadFileForm(forms.ModelForm):
    class Meta:
        model = Profile
        fields = ('avatar', )

    def save(self, *args, **kwargs):
        profile, created = Profile.objects.get_or_create(user=self.user)
        profile.avatar = self.cleaned_data['avatar']
        profile.save()
        return profile

Also, edit in your views like this,

if form.is_valid():
    file = form.save(commit=False)
    file.user = request.user
    file.save()
Sign up to request clarification or add additional context in comments.

8 Comments

Better ! I have an error : (1048, "Column 'user_id' cannot be null")
(1062, "Duplicate entry '4' for key 'user_id'")
Does this user have already a Profile?? The error says it already has and you have defined in your model its a OneToOne Field, then you can only add one Profile for each User..
For info, this is a screenshot : img4.hostingpics.net/pics/619397Capture.png
I can write a save method so that it adds avatar to existing users, would you be interested?
|
1

For making a profile you can use signals.

This way whenever a new user been added, a profile will be generated for that user automatically

Your models.py:

from django.conf import settings
from django.db.models.signals import post_save


class Profile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL)
    birthdate = models.DateField(null=True, blank=True)
    avatar = models.ImageField(upload_to='media/avatar/%y/%m/%d', blank=True, null=True)


def post_save_profile(sender, instance, created, *args, **kwargs):
    if created:
        try:
            Profile.objects.create(user=instance)
        except:
            pass

post_save.connect(post_save_profile, sender=settings.AUTH_USER_MODEL)

and for updating the information like birthday and avatar you can use ModelForm.

forms.py:

class UploadFileForm(forms.ModelForm):
    class Meta:
        model = Profile
        fields = ('birthdate', 'avatar')

    def __init__(self, *args, **kwargs):
        super(UploadFileForm, self).__init__(*args, **kwargs)
        self.fields['avatar'].required = False

your views.py:

def view_avatar(request):
    user = request.user
    if request.method == "POST":
        form = UploadFileForm(request.POST, request.FILES, instance=user.profile)
            if form.is_valid():
                form.save()

for avatar in template you can use this:

<img src="{% if user.profile.avatar %}{{ user.profile.avatar.url }}{% else %}{% static 'no-avatar.jpg' %}{% endif %}"><i></i>

2 Comments

Thanks, no error from Django but nothing appears on the database ( and unfortunatly birthday field has been reset to NULL). Nothing on my folder media/avatar/ also.
i'm using this code on one my projects and its working. maybe you missed something? and you should set the media_root correctly so your files upload in the right folder. and if you already had user, you need to delete them all or remove you database. this code only works when you add new users and its doesn't work if you had few users before you add this code. good luck ;) @GrandGTO
0

You can write custom Save method for this like this.

View:

def view_avatar(request):
    if request.method == 'POST':
        form = UploadFileForm(request.POST, request.FILES, user=request.user)
        if form.is_valid():
            form.save()

    else:
        form = UploadFileForm()
    return render(request, 'avatar.html', locals())

Form:

class UploadFileForm(forms.Form):
    class Meta:
        model = Profile
        fields = ('avatar', )

    def __init__(self, *args, **kwargs):
        self.user = kwargs.pop('user', None)
        super(UploadFileForm, self).__init__(*args, **kwargs)
        self.fields['avatar'].required = False

    avatar = forms.FileField()


    def save(self, *args, **kwargs):
        user_profile, created = Profile.objects.get_or_create(user=self.user)
        user_profile.avatar = self.cleaned_data.get('avatar')
        user_profile.save()
        return user_profile

Comments

0

I forgot the enctype ! The solution was :

<form method="POST" action="" enctype="multipart/form-data">

1 Comment

Glad that sorted it =)