djangodjango-modelsdjango-viewsdjango-formsdjango-file-upload

Image not getting uploaded in Django


I tried to save a record using two different methods but both are not working.

  1. Django Form
  2. Models (create method)

1 I have created a ModelForm


class ProductForm(ModelForm):
    class Meta:
        model= ProductDetails
        fields= ("name","category","subcategory","price","mrp","product_details","main_img","img1","img2","img3")

        labels={
            "name":"Product Name",
            "product_details":"Description",
            "category":"Category",
            "subcategory":"Sub-Category",
            "price":"Price",
            "mrp":"MRP",
            "main_img":"Main Image",
            "img1":"Image 1",
            "img2":"Image 2",
            "img3":"Image 3",
        }

        widgets = {
            'name':forms.TextInput(attrs={'class':'form-control validate',}),
            'product_details':forms.TextInput(attrs={'class':'form-control validate',}),

            'category':forms.TextInput(attrs={'class':'custom-select tm-select-accounts',}),
            'subcategory':forms.TextInput(attrs={'class':'custom-select tm-select-accounts',}),

            'price':forms.TextInput(attrs={'class':'form-control validate',}),
            'mrp':forms.TextInput(attrs={'class':'form-control validate',}),

            'main_img':forms.FileInput(attrs={'class':'btn btn-primary btn-block mx-auto',}),
            'img1':forms.FileInput(attrs={'class':'btn btn-primary btn-block mx-auto',}),
            'img2':forms.FileInput(attrs={'class':'btn btn-primary btn-block mx-auto',}),
            'img3':forms.FileInput(attrs={'class':'btn btn-primary btn-block mx-auto',}),
            
        }

Models File


# For Product details
class ProductDetails(models.Model):
    name= models.CharField(max_length=100)
    price= models.FloatField()
    mrp= models.FloatField()
    main_img = models.ImageField(upload_to='product_img')
    img1 = models.ImageField(upload_to='product_img')
    img2 = models.ImageField(upload_to='product_img')
    img3 = models.ImageField(upload_to='product_img')
    category = models.ForeignKey(Category, related_name='produits', on_delete=models.CASCADE)
    subcategory = models.ForeignKey(SubCategory, related_name='produits', on_delete=models.CASCADE)
    product_details = RichTextField(blank=True, null=True)
    trending = models.BooleanField(default=False)
    
    def __str__(self):
        return self.name

Method 1

Save record using form.save() getting Form validation error I have tried by removing main_img,img1,img2,img3 from all place (Forms.py, template, views,py). Then there is not validation error and record is getting saved successfully.

The validation error is just because of some issue with the image uploading

print(form.errors)= <ul class="errorlist"><li>main_img<ul class="errorlist"><li>This field is required.</li></ul></li><li>img1<ul class="errorlist"><li>This field is required.</li></ul></li><li>img2<ul class="errorlist"><li>This field is required.</li></ul></li><li>img3<ul class="errorlist"><li>This field is required.</li></ul></li></ul>


def add_product(request):
    if request.method == "POST":
        form = ProductForm(request.POST or None, request.FILES or None)
        print(form.errors )
        if form.is_valid():
            category_id = request.POST.get('category')
            subcategory_id = request.POST.get('subcategory')
            category= Category.objects.get(id=int(category_id))
            subcategory= SubCategory.objects.get(id=int(subcategory_id))
            form.category = category
            form.subcategory = subcategory
            form.save()
            return redirect("/dashboard/products")
    form = ProductForm()
    categories=Category.objects.all()
    subcategories=SubCategory.objects.all()
    return render(request, "01-add-product.html", "form":form,"categories":categories,"subcategories":subcategories})

Method 2

Tried Saving records using models.save() The record is getting saved but image is not getting uploaded to the media folder On saving record from Django-admin the image is getting uploaded to proper place i.e. /media.product_img/... But From this outside HTML its showing the file name in Django-admin but the file is not available in media folder

I already added urlpattern + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) in my project/urls.py. Also tried adding the same in urls.py of this app

Note = I have mentioned upload_to=product_img in my model (this may be important to know)

def add_product(request):
    if request.method == "POST":        
        name = request.POST['name']
        product_details = request.POST['product_details']
        category_id = request.POST.get('category')
        subcategory_id = request.POST.get('subcategory')
        category= Category.objects.get(id=int(category_id))
        subcategory= SubCategory.objects.get(id=int(subcategory_id))
        price = request.POST['price']
        mrp = request.POST['mrp']
        main_img = request.POST['main_img']
        img1 = request.POST['img1']
        img2 = request.POST['img2']
        img3 = request.POST['img3']
        product = ProductDetails.objects.create(name=name,product_details=product_details,category=category,subcategory=subcategory,price=price,mrp=mrp,main_img=main_img,img1=img1,img2=img2,img3=img3)
        product.save()

Here is my template

{% extends '01-admin-base.html' %}
{% load static %}
{% block content %}

    <div class="container tm-mt-big tm-mb-big">
      <div class="row">
        <div class="col-xl-9 col-lg-10 col-md-12 col-sm-12 mx-auto">
          <div class="tm-bg-primary-dark tm-block tm-block-h-auto">
            <div class="row">
              <div class="col-12">
                <h2 class="tm-block-title d-inline-block">Add Product</h2>
              </div>
            </div>
            <div class="row tm-edit-product-row">
              <div class="col-xl-6 col-lg-6 col-md-12">
                <form action="" method="post" class="tm-edit-product-form">
                  {% csrf_token %}
                  {{form.media}}
                  <div class="form-group mb-3">
                    <label
                      for="name"
                      >Product Name
                    </label>
                    {{form.name}}
                    
                  </div>
                  
                  <div class="form-group mb-3">
                    <label
                      for="category"
                      >Category</label
                    >
                    <select
                      class="custom-select tm-select-accounts"
                      id="category" name="category"
                    >
                      <option selected>Select category</option>
                      {% for category in categories %}
                      <option value="{{category.id}}">{{category.name}}</option>
                      {% endfor %}
                    </select>
                  </div>
                  <div class="form-group mb-3">
                    <label
                      for="subcategory"
                      >Sub Category</label
                    >
                    <select
                      class="custom-select tm-select-accounts"
                      id="subcategory" name="subcategory"
                    >
                      <option selected>Select sub-category</option>
                      {% for subcategory in subcategories %}
                      <option value="{{subcategory.id}}">{{subcategory.name}}</option>
                      {% endfor %}
                    </select>
                  </div>
                  <div class="row">
                      <div class="form-group mb-3 col-xs-12 col-sm-6">
                          <label
                            for="price"
                            >Price
                          </label>
                          {{form.price}}
                        </div>
                        <div class="form-group mb-3 col-xs-12 col-sm-6">
                          <label
                            for="mrp"
                            >MRP
                          </label>
                          {{form.mrp}}
                        </div>
                  </div>
                  <div class="form-group mb-3">
                    <label
                      for="description"
                      >Description</label
                    >
                    {{form.product_details}}
                  </div>
                  
              </div>
              
              <div class="col-xl-6 col-lg-6 col-md-12 mx-auto mb-4">
                <div class="custom-file mt-3 mb-3">
                  <label>Main Image</label>
                  {{form.main_img}}
                </div>
                <br><br>
                <label>Images</label>
                <div class="custom-file mt-3 mb-3">
                  {{form.img1}}                  
                </div>
                <div class="custom-file mt-3 mb-3">
                  {{form.img2}}                  
                </div>
                <div class="custom-file mt-3 mb-3">
                  {{form.img3}}                  
                </div>
              </div>

              <div class="col-12">
                <button type="submit" class="btn btn-primary btn-block text-uppercase">Add Product Now</button>
              </div>
            </form>
            </div>
          </div>
        </div>
      </div>
    </div>

{% endblock content %}

Please help me to get solution for this.


Solution

  • You need to add enctype="multipart/form-data"> in Html form so:

    <form action="/" method="POST" enctype="multipart/form-data">
        {% csrf_token %}
          <label for="fname">First name:</label>
          <input type="text" id="fname" name="fname"><br><br>
          <label for="lname">Last name:</label>
          <input type="text" id="lname" name="lname"><br><br>
          <input type="submit" value="Submit">
     </form>