0

Im sorry but I'm really new to Django and I already tried the steps in the documentation. Unfortunately, it's not working quite as I would expect. I was hoping that after executing the steps it would save the file to my media folder. If possible I'd also like to use AJAX but I can't understand the flow.

HTML

 <form method="post" enctype="multipart/form-data">
            {% csrf_token %}
            <input type="file" name="myfile">
            <button type="submit">Upload</button>
 </form>

models.py

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    email = models.TextField(max_length=500, blank=True)
    contact_number = models.CharField(max_length=30, blank=True)
    profile_picture = models.FileField(null=True,blank=True)

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

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

forms.py

class UploadForm(forms.ModelForm):
    class Meta:
        model = Profile
        fields = ('profile_picture',)

views.py

def model_form_upload(request):
    if request.method == 'POST':
        form = UploadForm(request.POST, request.FILES)
        if form.is_valid():
            form.save()
            return redirect('/home/')

I'm trying to save a photo for a user's profile. Please help me. If there is a way to do this with AJAX, that would be helpful as well.

elena
  • 3,740
  • 5
  • 27
  • 38
Jason
  • 281
  • 8
  • 19
  • How are you debugging it? Make an else (for `form.is_valid()`), with `print(form.errors)` to check what is happening. I think the problem is the name attribute of the input type file, but let's check it. – Rafael Mar 25 '17 at 17:18
  • It doesnt show an error. It just refreshes the page but nothings going to my media folder – Jason Mar 25 '17 at 17:22
  • Ok. You said you are new on Django, right? Let's check the basic. The `print form.errors` should appear on terminal (and not at browser). When you submit your form, the other information (user, email and contact_number) appear on database? – Rafael Mar 25 '17 at 17:32
  • @Rafael I have a separate handler for my email and contact number which is working already. Thats why the only field in my UploadForm is profile_picture. I'm not sure if thats how it works though. What I want to happen is I already have a profile with contact and email, I just want to add a profile picture. When I submit a form for profile picture it just refreshes with nothing saved – Jason Mar 25 '17 at 17:34
  • Ok. But you are checking the console? Is there any error printed? And remove the redirect (just for debug. Make a render like in your GET request). Add a {{form.errors}} on HTML. It is faster to debug. – Rafael Mar 25 '17 at 17:45
  • And also, check the input generated by {{form}} and yours. Your html use `name="myfile"`, and your model use the name `profile_picture`. – Rafael Mar 25 '17 at 17:51
  • Hello, I think I did a few steps forward but when I tried to upload an image, NOT NULL constraint failed: bartr_profile.user_id. Would you happen to know why this happens? – Jason Mar 25 '17 at 17:55
  • Yes. It is a very good information. Looks like you are creating an instance, but you are updating an existent profile, right? You need to instance your profile (to be updated). A good explanation is [here](http://stackoverflow.com/questions/10205657/django-modelform-create-or-update) – Rafael Mar 25 '17 at 17:59
  • Sorry. It is duplicated of a [better one](http://stackoverflow.com/questions/4673985/how-to-update-an-object-from-edit-form-in-django) – Rafael Mar 25 '17 at 18:00
  • I think I understand it a bit. One question though what do I pass in the instance parameter? Do I pass the existing profile in my case? – Jason Mar 25 '17 at 18:04
  • Yes, you are right. An existent profile. (eg.: `profile = Profile.get(email="your@email.com"`) – Rafael Mar 25 '17 at 22:15

1 Answers1

0

heres how I solved my problem :

I used this method to extract my image from the input first

  function extractPhoto(input) {
        var files = input[0].files;
        if (!files.length) {
            alert('Unable to upload: no file selected');
            return;
        }
        return files[0]
    }

then I used jQuery's FormData and ajax to pass the extracted photo to my view

 var image = $("#image");
        $("#uploadbutton").click(function () {
            const form = new FormData();
            form.append('image', extractPhoto(image));

            generateCSRFToken();
            $.ajax({
                url: '/upload_photo/',
                data: form,
                type: "POST",
                contentType: false,
                processData: false,
                success: function (data) {
                    location.reload();
                },
                error: function (data) {

                }

            })
        });

then I handle it in my views.py

def upload_photo(request):
        if 'image' not in request.FILES:
            return HttpResponse(status=400)

        user = request.user

        user.profile.profile_picture = request.FILES.get('image')
        user.profile.save();

        return HttpResponse(status=200)
Jason
  • 281
  • 8
  • 19