How to Update ImageField in Django?

Viewed 8432

i am new in Django. i am having issue in updating ImageField.i have following code

in models.py

 class ImageModel(models.Model):
      image_name = models.CharField(max_length=50)
      image_color = models.CharField(max_length=50)
      image_document = models.ImageField(upload_to='product/')

-This is My forms.py

 class ImageForm(forms.ModelForm):
    class Meta:
        model = ImageModel
        fields = ['image_name', 'image_color' , 'image_document']

in Html file (editproduct.html)

<form method="POST" action="/myapp/updateimage/{{ singleimagedata.id }}">
       {% csrf_token %}
        <input class="form-control" type="text" name="image_name" value="{{ singleimagedata.image_name}}">
        <input class="form-control" type="file" name="image_document">
        <button type="submit" class="btn btn-primary">UPDATE PRODUCT</button>
</form>

-myapp is my application name. {{singleimagedata}} is a Variable Containing all fetched Data

-urls.py

urlpatterns = [
    path('productlist', views.productlist, name='productlist'),
    path('addproduct', views.addproduct, name='addproduct'),
    path('editimage/<int:id>', views.editimage, name='editimage'),
    path('updateimage/<int:id>', views.updateimage, name='updateimage'),
]

and Here is My views.py

def productlist(request):
    if request.method == 'GET':
        imagedata = ImageModel.objects.all()
        return render(request,"product/productlist.html",{'imagedata':imagedata})

def addproduct(request):
    if request.method == 'POST':
        form = ImageForm(request.POST, request.FILES)
        if form.is_valid():
            form.save()
            messages.add_message(request, messages.SUCCESS, 'Image Uploaded')
            return redirect('/myapp/productlist')
    else:
        imageform = ImageForm()
        return render(request, "product/addproduct.html", {'imageform': imageform})

def editimage(request, id):
    singleimagedata = ImageModel.objects.get(id=id)
    return render(request, 'product/editproduct.html', {'singleimagedata': singleimagedata})

def updateimage(request, id):  #this function is called when update data
    data = ImageModel.objects.get(id=id)
    form = ImageForm(request.POST,request.FILES,instance = data)
    if form.is_valid():
        form.save()
        return redirect("/myapp/productlist")
    else:
        return render(request, 'demo/editproduct.html', {'singleimagedata': data})
  • My image Upload is working fine.i can not Update image while updating data.rest of the data are updated.i don't know how to update image and how to remove old image and put new image into directory.
4 Answers

I think you missed the enctype="multipart/form-data", try to change:

<form method="POST" action="/myapp/updateimage/{{ singleimagedata.id }}">

into;

<form method="POST" enctype="multipart/form-data" action="{% url 'updateimage' id=singleimagedata.id %}">

Don't miss also to add the image_color field to your html input.
Because, in your case the image_color field model is designed as required field.

To remove & update the old image file from directory;

import os
from django.conf import settings

# your imported module...


def updateimage(request, id):  #this function is called when update data
    old_image = ImageModel.objects.get(id=id)
    form = ImageForm(request.POST, request.FILES, instance=old_image)

    if form.is_valid():

        # deleting old uploaded image.
        image_path = old_image.image_document.path
        if os.path.exists(image_path):
            os.remove(image_path)

        # the `form.save` will also update your newest image & path.
        form.save()
        return redirect("/myapp/productlist")
    else:
        context = {'singleimagedata': old_image, 'form': form}
        return render(request, 'demo/editproduct.html', context)

I had a similar issue while updating the profile_pic of user. I solved this with the following code I think this might help:

Models.py

class Profile(models.Model):
    # setting o2o field of user with User model
    user_name = models.OneToOneField(User, on_delete=models.CASCADE, blank=True, null=True)
    first_name = models.CharField(max_length=70, null=True, blank=True)
    last_name = models.CharField(max_length=70, null=True, blank=True)    
    profile_pic = models.ImageField(upload_to="images", blank=True, null=True,)


    def __str__(self):
        return str(self.user_name)

forms.py

class ProfileEditForm(ModelForm):
    class Meta:
        model = Profile
        fields = '__all__'
        # excluding user_name as it is a one_to_one relationship with User model
        exclude = ['user_name']

views.py

@login_required(login_url='login')
def edit_profile(request, id):
    username = get_object_or_404(Profile, id=id)
    extended_pro_edit_form = ProfileEditForm(instance=username)
    if request.method == "POST":
        extended_pro_edit_form = ProfileEditForm(request.POST, request.FILES, instance=username)
        if extended_pro_edit_form.is_valid():
            extended_pro_edit_form.save()
            next_ = request.POST.get('next', '/')
            return HttpResponseRedirect(next_)

    context = {'extended_pro_edit_form': extended_pro_edit_form}
    return render(request, 'edit_profile.html', context)

edit-profile.html

<form action="" method="post"
              enctype="multipart/form-data">
            {% csrf_token %}
            {{ extended_pro_edit_form.as_p }}
            {{ extended_pro_edit_form.errors }}
            <!--To redirect user to prvious page after post req-->
            <input type="hidden" name="next" value="{{ request.GET.next }}">

            <button type="submit">UPDATE</button>

        </form>

Answer from @binpy should solve your problem. In addition to your second answer, you could do:

def updateimage(request, id):  #this function is called when update data
    data = ImageModel.objects.get(id=id)
    form = ImageForm(request.POST,request.FILES,instance = data)
    if form.is_valid():
        data.image_document.delete()  # This will delete your old image
        form.save()
        return redirect("/myapp/productlist")
    else:
        return render(request, 'demo/editproduct.html', {'singleimagedata': data})

Check delete() method on django docs.

some times something like cached old image is not replaced in the front-end so you might just need to forces refresh by pressing CTRL + F5 or clear your browsing history.

the answer given by @binpy is a needed update so that the files are passed to the back-end.

Related