Imagefield layout not working + missing name when there are multiple image inline formsets
See original GitHub issue- Package version: 1.11.2
- Django version: 3.2
- Python version: 3.9
- Template pack: Bootstrap4
Description:
I noticed that:
- When there is multiple image inline formsets, the filenames do not appear after upload, but the files there because it will appear in database table once the form is submitted
- ImageField’s
ClearableFileInput
do not follow the layout defined
If there is only single image inline formset, filename appear just fine.
In this image, you see 2 image upload, both with ---
, but I have already uploaded 2 images, thus problem 1.
If you refer to below forms.py
, you see that I have defined the layout, is_primary
field should be before image
field, but that is not the html generated, thus problem 2.
# forms.py
class PersonImageForm(forms.ModelForm):
class Meta:
model = PersonImage
fields = "__all__"
widgets = {
"image": forms.ClearableFileInput(
attrs={"multiple": False},
),
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.disable_csrf = True
self.helper.layout = Layout(
Row(
Column(
"is_primary", css_class="form-group col-md-2 mb-0",
),
Column(
"image", css_class="form-group col-md-10 mb-0",
),
),
)
PersonImageFormSet = forms.models.inlineformset_factory(
Person, PersonImage, form=PersonImageForm, can_delete=False, extra=0, min_num=1, validate_min=True,
)
template
{% extends "base.html" %}
{% load static %}
{% load crispy_forms_tags %}
{% block content %}
<div class="container-fluid">
<h1>Create Person</h1>
<form enctype="multipart/form-data" method="post">
{% csrf_token %}
{% crispy form %}
{% if images %}
<h3>Create Image(s)</h3>
{{ images.management_form|crispy }}
<div id="person_image_formset">
{% for form in images.forms %}
<table class="no_error">
{% crispy form %}
</table>
{% endfor %}
</div>
<input class="btn btn-outline-secondary" id="person_image_add_more" type="button" value="Add more image">
<div id="person_image_empty_form" style="display:none">
<table class="no_error">
{% crispy images.empty_form %}
</table>
</div>
{% endif %}
</form>
</div>
{% endblock %}
{% block scriptblock %}
{{ block.super }}
document.querySelector("#person_image_add_more").addEventListener("click", function() {
var form_idx = document.querySelector("#id_person_image-TOTAL_FORMS").value
document.querySelector("#person_image_formset").innerHTML += document.querySelector("#person_image_empty_form").innerHTML.replace(/__prefix__/g, form_idx)
document.querySelector("#id_person_image-TOTAL_FORMS").value = parseInt(form_idx) + 1
});
{% endblock %}
html output
<div id="person_image_formset">
<div id="div_id_person_image-0-image" class="form-group">
<label for="id_person_image-0-image" class="requiredField">
Image<span class="asteriskField">*</span>
</label>
<div class="mb-2">
<div class="form-control custom-file" style="border: 0">
<input
type="file"
name="person_image-0-image"
class="custom-file-input"
accept="image/*"
id="id_person_image-0-image"
/>
<label
class="custom-file-label text-truncate"
for="id_person_image-0-image"
>---</label
>
<script type="text/javascript" id="script-id_person_image-0-image">
document
.getElementById("script-id_person_image-0-image")
.parentNode.querySelector(".custom-file-input").onchange =
function (e) {
var filenames = "";
for (let i = 0; i < e.target.files.length; i++) {
filenames += (i > 0 ? ", " : "") + e.target.files[i].name;
}
e.target.parentNode.querySelector(
".custom-file-label"
).textContent = filenames;
};
</script>
</div>
</div>
</div>
<div class="form-group">
<div
id="div_id_person_image-0-is_primary"
class="custom-control custom-checkbox"
>
<input
type="checkbox"
name="person_image-0-is_primary"
class="checkboxinput custom-control-input"
id="id_person_image-0-is_primary"
/>
<label for="id_person_image-0-is_primary" class="custom-control-label">
Is primary
</label>
<small id="hint_id_person_image-0-is_primary" class="form-text text-muted"
>Tick if this is primary image</small
>
</div>
</div>
<table class="no_error">
<input
type="hidden"
name="csrfmiddlewaretoken"
value="ofoZMUaNboqwVHl0UonJ2ihl5xSimkfSN3MrIiFaH3HDv2M7ab9TyglLZymu2b5S"
/>
<input
type="hidden"
name="person_image-0-person"
id="id_person_image-0-person"
/>
<input type="hidden" name="person_image-0-id" id="id_person_image-0-id" />
</table>
<div id="div_id_person_image-1-image" class="form-group">
<label for="id_person_image-1-image" class="requiredField">
Image<span class="asteriskField">*</span>
</label>
<div class="mb-2">
<div class="form-control custom-file" style="border: 0">
<input
type="file"
name="person_image-1-image"
class="custom-file-input"
accept="image/*"
id="id_person_image-1-image"
/>
<label
class="custom-file-label text-truncate"
for="id_person_image-1-image"
>---</label
>
<script type="text/javascript" id="script-id_person_image-1-image">
document
.getElementById("script-id_person_image-1-image")
.parentNode.querySelector(".custom-file-input").onchange =
function (e) {
var filenames = "";
for (let i = 0; i < e.target.files.length; i++) {
filenames += (i > 0 ? ", " : "") + e.target.files[i].name;
}
e.target.parentNode.querySelector(
".custom-file-label"
).textContent = filenames;
};
</script>
</div>
</div>
</div>
<div class="form-group">
<div
id="div_id_person_image-1-is_primary"
class="custom-control custom-checkbox"
>
<input
type="checkbox"
name="person_image-1-is_primary"
class="checkboxinput custom-control-input"
id="id_person_image-1-is_primary"
/>
<label for="id_person_image-1-is_primary" class="custom-control-label">
Is primary
</label>
<small id="hint_id_person_image-1-is_primary" class="form-text text-muted"
>Tick if this is primary image</small
>
</div>
</div>
<table class="no_error">
<input
type="hidden"
name="csrfmiddlewaretoken"
value="ofoZMUaNboqwVHl0UonJ2ihl5xSimkfSN3MrIiFaH3HDv2M7ab9TyglLZymu2b5S"
/>
<input
type="hidden"
name="person_image-1-person"
id="id_person_image-1-person"
/>
<input type="hidden" name="person_image-1-id" id="id_person_image-1-id" />
</table>
</div>
Help is greatly appreciated 🙏
Preferably also include:
- Example Django Crispy Forms code
- Screenshots
- Actual HTML generated
- Expected HTML
Issue Analytics
- State:
- Created 2 years ago
- Comments:6 (3 by maintainers)
Top Results From Across the Web
Imagefield layout not working + missing name when there are ...
If there is only single image inline formset, filename appear just fine. image. In this image, you see 2 image upload, both with...
Read more >Django inline-formset with an image field not updating
The issues I am having are: 1) If there is a photo attached to the listing, through the admin, the photo form does...
Read more >Django crispy form imagefield example - GitHub
Problem 1. When there is multiple image inline formsets, the filenames do not appear after upload, but the files there because it will...
Read more >Problem with ImageField and inline admin form - Google Groups
Hi. I'm stumped and can't figure out a solution for the following: With the models: class Entry(models.Model): pub_date = models.
Read more >Module and theme fields - HubSpot Developers
Add fields to modules and themes to allow content creators to control various aspects of a page within the page editor.
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
Gotcha, anyway, I tried using bootstrap 5,
CreateView / UpdateView
for image formsets are working as expected. The only thing for improvement is just to use bootstrap 5 input cssI am going to close this issue as I believe there is no point fixing outdated software.
For others’ future reference. The working code for dcf bootstrap 5 is here https://github.com/shawnngtq/django_dcf_image_example
Thanks @smithdc1
One of the aims we’ve had for a long time is to split the template packs from the core app. So yes you’ll need to install the bootstrap5 pack and update the setting as you noted.
With bootstrap 4 we had to ship some JS in the crispy-form template to get it to work. Clearly some bug in that code where formsets are in play.
For Bootstrap 5 they changed how these inputs work and so no custom JS. Therefore this may just work is you try the bootstrap5 template pack. 🤔