Hi, I’ve been facing a problem with rendering user-uploaded images in my project (in development). I have a form in a template for creating an object for a Model that has an ImageField attribute. However, it does not seem to follow the upload_to argument. I would appreciate any info on how to fix this.
models.py:
class Product(models.Model):
name = models.CharField(max_length=50)
model = models.CharField(max_length=50)
version = models.CharField(max_length=20)
image = models.ImageField(default='products/default.jpeg', upload_to='products/', blank=False, null=False)
def __str__(self):
return self.name
views.py:
def add_product(request):
if request.method == "POST":
name = request.POST["product_name"]
version = request.POST["product_version"]
model = request.POST["product_model"]
image = request.FILES.get("product_image", None)
product = Product(
name = name,
model = model,
version = version,
image = image if image else 'products/default.jpeg'
)
product.save()
return HttpResponseRedirect(reverse('products'))
else:
if request.user.is_authenticated:
products = Product.objects.all()
return render(request, 'add_product.html',{
"products" : products
})
else:
return render(request, "login.html", {
"message": "Login to add products"
})
The form in my template:
<form class="row gy-2 gx-3 align-items-center" action="{% url 'add_product' %}" method="post">
{% csrf_token %}
<div class="col-auto">
<label for="autoSizingInput">Product Name</label>
<input type="text" class="form-control" id="autoSizingInput" placeholder="Product name" name="product_name" required>
</div>
<div class="col-auto">
<label for="autoSizingInputGroup">Version</label>
<div class="input-group">
<div class="input-group-text"><em>v</em></div>
<input type="text" class="form-control" id="autoSizingInputGroup" placeholder="Product version" name="product_version" required>
</div>
</div>
<div class="col-auto">
<label for="autoSizingInput">Model number</label>
<input type="text" class="form-control" id="autoSizingInput" placeholder="Model number" name="product_model" required>
</div>
<div class="col-auto">
<label for="inputGroupFile02">Product image (optional)</label>
<div class="input-group">
<!--<div class="input-group-text">Upload</div>-->
<input type="file" class="form-control" id="inputGroupFile02" name="product_image">
</div>
</div>
<div class="col-auto">
<button type="submit" class="btn btn-success">Save</button>
</div>
</form>
root urls.py:
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
path('', include("RMA_app.urls"))
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
app urls.py:
from django.urls import path
from . import views
urlpatterns = [
path('', views.home, name="home"),
path('login', views.signin, name="login"),
path('logout', views.signout, name="logout"),
path('register', views.signup, name="register"),
path('products', views.products, name="products"),
path('products/add', views.add_product, name="add_product"),
path('devices', views.devices, name="device"),
path('devices/add', views.add_device, name="add_device"),
path('complaints', views.complaint, name="complaint"),
path('complaints/add', views.add_complaint, name="add_complaint"),
path('complaints/<int:complaint_id>', views.view_complaint, name="view_complaint")
]
settings.py:
STATIC_URL = 'static/'
STATICFILES_DIRS = [
BASE_DIR / 'RMA_app/static',
]
MEDIA_ROOT = BASE_DIR / 'media'
MEDIA_URL = '/media/'
When the user creates a Product object by uploading an image, it is saved with the default image with this URL: http://localhost:8000/media/products/default.jpeg . No image is uploaded to the MEDIA_ROOT directory. However, when I create a Product object from the admin page, it works as expected by uploading the image to MEDIA_ROOT and the URL of the image being localhost:8000/media/products/filename.jpeg
I did try changing my view to:
def add_product(request):
if request.method == "POST":
name = request.POST["product_name"]
version = request.POST["product_version"]
model = request.POST["product_model"]
image_response = request.POST["product_image"]
if image_response:
image = image_response
else:
image = None
product = Product(
name = name,
model = model,
version = version,
image = image if image else 'products/default.jpeg'
)
product.save()
return HttpResponseRedirect(reverse('products'))
but in this case, the images aren’t uploaded to MEDIA_ROOT. The URL for the images ended up being http://localhost:8000/media/filename.jpeg and not media/products/filename.jpeg
Any input would be appreciated. Thank you.