Using Django I'm creating a thumbnail of an image uploaded using a standard ImageField, adding the path to a table in a separate field 'thumbnail' alongside the usual imagefile field. I'm trying to work out how to access the thumbnail path where rendering the imagefield objects in a custom template using a formset so that I can display it.
I guess I need to add a 'form=CarImageForm' to inlineformset_factory and then modify my forms.py but I'm having trouble working out how to do it or even whether this approach is the right one. For clarity I have not included my attempts to do so in the code samples below.
My end goal is to return the thumbnail image which links to the original image - already displayed via the Imagefile field.
Thanks in advance!
template is:
<form method="post" action="" enctype="multipart/form-data">
{% csrf_token %}
{{ formset.management_form }}
{% for form in formset.forms %}
{% for field in form %}
{{ field.label }}: {{ field }}<br>
{% endfor %}
{% endfor %}
<p><input type="submit" value="Enter"/></p>
forms.py:
class CarForm(ModelForm):
class Meta:
model = Car
exclude = ['owner', 'uploaded']
views.py:
# Edit an existing record
@login_required
def edit_existing(request, object_id=False):
try:
car = Car.objects.get(pk=object_id)
except Car.DoesNotExist:
raise Http404
ImageFormSet = inlineformset_factory(Car, CarImage, extra=1, max_num=1)
if request.method == 'POST':
form = forms.CarForm(request.POST, instance=car)
formset = ImageFormSet(request.POST, request.FILES, instance=car)
if formset.is_valid() and form.is_valid():
# Handle form.save() to include user id
new_car = form.save(commit=False)
new_car.owner = request.user
new_car.save()
# Formset - contains the attached images
formset.save()
return HttpResponseRedirect(new_car.get_absolute_url())
else:
form = forms.CarForm(instance=car)
formset = ImageFormSet(instance=car)
return render_to_response('edit_existing.html',
{'form': form, 'formset': formset},
context_instance=RequestContext(request))
models.py:
class Car(models.Model):
make = models.CharField(max_length=64)
model = models.CharField(max_length=64)
owner = models.ForeignKey(User,editable=False)
uploaded = models.DateField(default=datetime.date.today,editable=False)
def get_absolute_url(self):
return reverse('vehicle_admin.views.car_detail', args=[str(self.id)])
def orig_car_id_folder(instance, filename):
return 'uploads/images/orig/{0}/{1}'.format(instance.car_id, filename)
def thumb_car_id_folder(instance, filename):
return 'uploads/images/thumb/{0}/{1}'.format(instance.car_id, filename)
class CarImage(models.Model):
car = models.ForeignKey(Car)
imagefile = models.ImageField(upload_to=orig_car_id_folder)
thumbnail = models.ImageField(upload_to=thumb_car_id_folder, editable=False)
# PIL tips from
# https://snipt.net/danfreak/generate-thumbnails-in-django-with-pil/
# http://www.mechanicalgirl.com/post/image-resizing-file-uploads-doing-it-easy-way/
def save(self):
import os
from PIL import Image
from cStringIO import StringIO
from django.core.files.uploadedfile import SimpleUploadedFile
THUMBNAIL_SIZE = (75, 75)
super(CarImage, self).save() # Use the commit=False param here?
image = Image.open(self.imagefile.path)
if image.mode not in ('L', 'RGB'):
image = image.convert('RGB')
image.thumbnail(THUMBNAIL_SIZE, Image.ANTIALIAS)
temp_handle = StringIO()
image.save(temp_handle, 'png')
temp_handle.seek(0)
name_ext = os.path.splitext(os.path.split(self.imagefile.name)[-1])
suf = SimpleUploadedFile(name_ext[0],
temp_handle.read(), content_type='image/png')
self.thumbnail.save(suf.name+'.png', suf, save=False)
super(CarImage, self).save()
I think this is a basic oversight on my part.
My problem was setting editable=False in my CarImage model for the 'thumbnail' field. This is fine for the initial data submission but causes problems where editing the entry as that field is automatically excluded in the form. (See my code snippets above for more info.)
My next step would be to set up a custom Form for my add_new view (I did not initially include this view but it is what I was using to enable the initial upload of data) like this:
class InitialCarImageForm(ModelForm):
class Meta:
model = CarImage
exclude = ['thumbnail']
I guess that the right approach is to use editable=False but unless I'm committing a grave mistake taking this approach it will probably work for me.
I'm new to the site so please let me know if answering my question in this way is the correct way to close it.