Django admin lets you edit related model objects “inline”. For example when editing a
Recipe you can add/eding a group of
Core fields for edit_inline
The related model being edited inline must specify one or more “core” fields using
core=True. If the core fields are filled in, the related model is added. If the core fields are empty, the related model is removed.
This works great for normal objects with
CharFields, etc, but not so well if you want to have images or files uploaded using inline editing. If the only core field is a
ImageField, you’ll get strange behaviour like the file/image being removed when you edit an existing model in the admin.
Using inline editing with ImageField or FileField
In a recent project I wanted to have an item with title and description and zero or more photos. The
Photo model just has an
ImageField. To make it easy to edit, I wanted the photos set to
Here’s my first attempt:
class Item(models.Model): title = models.CharField(max_length=100) description = models.TextField() class Admin: pass class Photo(models.Model): item = models.ForeignKey(Item, related_name='photos', edit_inline=models.STACKED) image = models.ImageField(blank=False, upload_to='items', core=True)
Notice that the
core=True to make it a core field.
This worked ok in the Django admin interface for adding a
Photo to a new
Item, but if I edited that
Photo would be deleted.
This is a known issue (see Ticket #2534), but it’s marked as “pending design decision” and may be ignored for now since the Django admin is being rewritten to use
In the meantime I needed a workaround.
Workaround using a different core field
Instead of having the
ImageField as a core field, we need something else. If you’ve got some other natural data, such as a caption, that would work fine.
In my case, I didn’t want to add any other fields to the interface, so I went with a
BooleanField that is not editable.
Here’s the revised
class Photo(models.Model): item = models.ForeignKey(Item, related_name='photos', edit_inline=models.STACKED) image = models.ImageField(blank=False, upload_to='items') keep = models.BooleanField(default=True, editable=False, core=True) def save(self): # Don't save if there is no image (since core field is always set). if not self.id and not self.image: return super(Photo, self).save()
The keep field has been added and set to be core instead of the image field. Since there is a core field and it’s not empty, the main
Item model can be edited without the
Photo models being deleted.
Don’t save the empties
The core field always has a value which means the
Photo model is told to save even when its
ImageField is empty. To prevent creating these empty objects, the
Photo model overrides
save() and checks if an image was uploaded to the
ImageField. If not, it returns without saving.
The remaining issue is that you can’t delete a
Photo using the Django admin interface. You can replace the image, but will need some other method for deleting. For me this isn’t a big problem, so the workaround solved the problem for now.
Note that this is just a workaround to the problem which hopefully will be fixed in Django at some point in the future. Ideally, the admin interface would properly handle having an
FileField as the only core field of the related model and optionally put a “remove” checkbox in the UI to allow removing the image/file.