I have a Django model with multiple ImageFields.
On the ModelAdmin class I've set save_as = True
, which means The admin page has a "Save as new" button, which allows for duplicating an existing item and saving it as new.
However when this button is used, the ImageFields are not duplicated and are left blank on the new item.
Looking at the POST request, I see that these fields are blank in the post data.
I've thought about overriding the Model class' save method, and copying the images from the old object by myself. But as far as I could figure out, I have no way to tell that the object is saved "as new". I also don't seem to have the ID of the old Item so I cannot get the old Images from it.
Is there a way to get these image fields to be duplicated as well?
Edit: Added Example code by request.
Created a minimalistic app with only one model. Verified problem still occurs.
Sample models.py:
from django.db import models
class Person(models.Model):
face_image = models.ImageField(upload_to='images',
null=False,
blank=True)
Sample admin.py:
from django.contrib import admin
from testapp.models import Person
class PersonAdmin(admin.ModelAdmin):
save_as = True
admin.site.register(Person, PersonAdmin)
Building up on this response, here's a more generic way of achieving the same result:
from django.core.urlresolvers import resolve
from django.db.models.fields.files import FieldFile
class PersonAdmin(admin.ModelAdmin):
save_as = True
def save_model(self, request, obj, form, change):
# Django always sends this when "Save as new is clicked"
if '_saveasnew' in request.POST:
# Get the ID from the admin URL
original_pk = resolve(request.path).args[0]
# Get the original object
original_obj = obj._meta.concrete_model.objects.get(id=original_pk)
# Iterate through all it's properties
for prop, value in vars(original_obj).iteritems():
# if the property is an Image (don't forget to import ImageFieldFile!)
if isinstance(getattr(original_obj, prop), FieldFile):
setattr(obj,prop,getattr(original_obj, prop)) # Copy it!
obj.save()
This should work with any model and any file type. It also doesn't require editing the form or the template. This is a workaround that should not be needed once the pull request gets merged: https://github.com/django/django/pull/2246.
I've managed to find some workaround:
I've overridden the original admin form (see here) to get it also include the old Model's ID in "save as new" POST request. I've did it by creating a special admin for of that model, and adding inside it a hidden input:
<input type="hidden" name="my_objectid" value="{{ object_id }}">
afterwards I've made the ModelAdmin class load that specific html. Then I overriden the AdminModel class' save_model method so it would copy the images as well.
So the new admin.py should look like this:
from django.contrib import admin
from testapp.models import Person
from django.db.models.fields.files import ImageFieldFile #added to be used later
class PersonAdmin(admin.ModelAdmin):
save_as=True
change_form_template = 'admin/person_change_form.html';
def save_model(self, request, obj, form, change):
if '_saveasnew' in request.POST: #Django always sends this when "Save as new is clicked"
origObjId = request.POST['my_objectid']; #Get the ID that is new posted after overriding the form.
originalPerson = Person.objects.get(id=origObjId); #Use the Id to get the old object
for prop, value in vars(originalPerson).iteritems(): #iterate through all it's properties
if isinstance(getattr(originalPerson,prop), ImageFieldFile): #if the property is an Image (don't forget to import ImageFieldFile!)
setattr(obj,prop,getattr(originalPerson,prop)) #Copy it!
obj.save()
admin.site.register(Person, PersonAdmin)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With