I have this view with two forms.
def anunciocreateview(request):
anuncio_form = AnuncioForm(request.POST or None)
producto_form = ProductoForm(request.POST or None)
if request.method == "POST":
if all([anuncio_form.is_valid(), producto_form.is_valid(), imagen_form.is_valid()]):
anuncio = anuncio_form.save(commit=False)
anuncio.anunciante = request.user
anuncio.save()
producto = producto_form.save(commit=False)
producto.anuncio = anuncio
producto.save()
return HttpResponse(status=204, headers={'HX-Trigger' : 'eventsListChanged'})
else:
anuncio_form = AnuncioForm()
producto_form = ProductoForm()
context = {
'anuncio_form' : anuncio_form,
'producto_form' : producto_form,
}
return render(request, 'buyandsell/formulario.html', context)
This view works OKAY; it allows the user to create instances of both models with the correct relation. I'm trying to add another form for the image of the product. I tried adding this:
def anunciocreateview(request):
anuncio_form = AnuncioForm(request.POST or None)
producto_form = ProductoForm(request.POST or None)
imagen_form = ImagenForm(request.POST, request.FILES)
if request.method == "POST":
if all([anuncio_form.is_valid(), producto_form.is_valid(), imagen_form.is_valid()]):
anuncio = anuncio_form.save(commit=False)
anuncio.anunciante = request.user
anuncio.save()
producto = producto_form.save(commit=False)
producto.anuncio = anuncio
producto.save()
imagen = imagen_form.request.FILES.get('imagen')
if imagen:
Imagen.objects.create(producto=producto, imagen=imagen)
return HttpResponse(status=204, headers={'HX-Trigger' : 'eventsListChanged'})
else:
print(request.FILES)
else:
anuncio_form = AnuncioForm()
producto_form = ProductoForm()
imagen_form = ImagenForm()
context = {
'anuncio_form' : anuncio_form,
'producto_form' : producto_form,
'imagen_form' : imagen_form
}
return render(request, 'buyandsell/formulario.html', context)
But this happens:
1- The 'Image upload' form field shows error 'This field is required' at the moment of rendering the form.
2- If uploading an image and clicking submit, the redirect doesn't happen as the imagen_form
is not marked as valid. No error pops in the console whatsoever (I'm handling requests with HTMX).
If I omit the 'request.FILES'
when instantiating the form, the error when the form renders disappear, but it anyway doesn't upload the image nor the form.
What am I missing?
For reference, here is the HTML file:
<form class="row g-3" method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Create new listing</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="mb-3">
<label for="{{ anuncio_form.titulo.auto_id }}">{{ anuncio_form.titulo.label }}</label>
{% render_field anuncio_form.titulo|add_error_class:"is-invalid" class="form-control" %}
</div>
<div class="mb-3">
<label for="{{ anuncio_form.envio.auto_id }}">{{ anuncio_form.envio.label }}</label>
{% translate "Select available delivery options" as input_place_holder %}
{% render_field anuncio_form.envio|add_error_class:"is-invalid" class="form-control" placeholder=input_place_holder %}
</div>
<h5>Product:</h5>
<div class="mb-3">
<label for="{{ producto_form.nombre.auto_id }}">{{ producto_form.nombre.label }}</label>
{% translate "Name of your product" as input_place_holder %}
{% render_field producto_form.nombre|add_error_class:"is-invalid" class=" form-control" placeholder=input_place_holder %}
</div>
<div class="mb-3">
<label for="{{ producto_form.descripcion.auto_id }}">{{ producto_form.descripcion.label }}</label>
{% translate "Give a detailed description of your product" as input_place_holder %}
{% render_field producto_form.descripcion|add_error_class:"is-invalid" class=" form-control" placeholder=input_place_holder %}
</div>
<div class="row g-3">
<div class="col-md-6">
<div class="mb-3">
<label for="{{ producto_form.estado.auto_id }}">{{ producto_form.estado.label }}</label>
{% render_field producto_form.estado|add_error_class:"is-invalid" class=" form-control" %}
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label for="{{ producto_form.cantidad.auto_id }}">{{ producto_form.cantidad.label }}</label>
{% render_field producto_form.cantidad|add_error_class:"is-invalid" class=" form-control" %}
</div>
</div>
</div>
<div class="row g-3">
<div class="col-md-6">
<div class="mb-3">
<label for="{{ producto_form.precio_unitario.auto_id }}">{{ producto_form.precio_unitario.label }}</label>
{% render_field producto_form.precio_unitario|add_error_class:"is-invalid" class=" form-control" %}
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label for="{{ producto_form.disponibilidad.auto_id }}">{{ producto_form.disponibilidad.label }}</label>
{% render_field producto_form.disponibilidad|add_error_class:"is-invalid" class=" form-control" %}
</div>
</div>
</div>
<h5>Images:</h5>
<div class="mb-3">
<label for="{{ imagen_form.imagen.auto_id }}">{{ imagen_form.imagen.label }}</label>
{% render_field imagen_form.imagen|add_error_class:"is-invalid" class=" form-control" %}
</div>
<div id="productforms"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-tertiary" hx-get="{% url 'buyandsell:create-product' %}" hx-target="#productforms" hx-swap="beforeend">Add new product</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-primary" hx-post="{% url 'buyandsell:createview' %}">Submit</button>
</div>
</div>
</form>
Edit:
forms.py for ImagenForm:
class ImagenForm(ModelForm):
class Meta:
model = Imagen
fields = ['imagen']
models.py for the Imagen model:
class Imagen(models.Model):
producto = models.ForeignKey(Producto, on_delete=models.CASCADE, related_name='imagen', blank=True, null=True)
imagen = models.ImageField(upload_to='marketplace/')
def __str__(self):
return f"Imagen de {self.producto}"
def save(self, *args, **kwargs):
self.image = resize_image(self.image, size=(350, 350))
super().save(*args, **kwargs)