I'm using django non-rel for appengine (djangoappengine) and have an app where the user selects an image and I have to return a crop from the selected image.
The images in my app are uploaded to the Blobstore following the django-filetransfers instructions. I've managed to upload (and even download) files just fine.
The problem I have is that I don't know how to display an image in template once it's been cropped.
The (simplified) code of my view is as follows:
def canvas_size(request):
if request.method == 'POST':
#some code here
else:
#At this point the user has selected an image, and I store its pk in session
img_file = ImageModel.objects.get(pk=request.session[SESSION_KEY]['image_pk'])
img = images.Image(blob_key=str(img_file.file.file.blobstore_info.key()))
img.resize(height=300)
img.crop(left_x=0.0, top_y=0.0, right_x=0.5, bottom_y=1.0)
crop_img = img.execute_transforms(output_encoding=images.JPEG)
#I know that the image is being cropped because if I do
#print crop_img
#I get to see the image in browser
response_dict = {
'crop_img' : crop_img,
}
template_name = 'canvas/step7.html'
response = render_to_response(template_name, response_dict, context_instance=RequestContext(request))
return response
In canvas/step7.html I've tried the following:
<img src="{{ crop_img.url }}" />
<img src="{{ crop_img.file.url }}" />
But of course that does not work.
Based on the Google AppEngine Image documentation, I know that the execute_transforms() function returns the image's encoded representation as a string. So I suppose I'm missing a step where I transform the string to a file... maybe?
Could someone point me in the right direction in order to display a crop in template using django?
Thanks for your help!
I finally managed to solve my problem. I followed voscausa's advice, but I'm posting a solution adapted to Django.
Background: I couldn't use get_serving_url since I'll need to crop specific coordinates. The method execute_transforms returns a string. Crops are better served from the blobstore
Solution
from djangotoolbox.fields import BlobField
class ImageModel(models.Model):
file = models.FileField(upload_to="images")
class MiniCanvas(models.Model):
crop = BlobField()
from my_app.models import ImageModel, MiniCanvas
from google.appengine.api import images
def view_that_crops(request):
if request.method == 'POST':
#Do stuff here
else:
#The pk of the selected image is stored in session
img_file = ImageModel.objects.get(pk=request.session[SESSION_KEY]['image_pk'])
img = images.Image(blob_key=str(img_file.file.file.blobstore_info.key()))
img.resize(height=300)
img.crop(left_x=0.0, top_y=0.0, right_x=0.5, bottom_y=1.0)
#This method returns the image's encoded representation as a string
crop_img = img.execute_transforms(output_encoding=images.JPEG)
#I can save the string as a BlobField in my model
mini_canvas = MiniCanvas.objects.create(crop=crop_img)
response_dict = {
'mini_canvas_pk' : mini_canvas.pk,
}
template_name = 'canvas/step7.html'
response = render_to_response(template_name, response_dict, context_instance=RequestContext(request))
return response
#This function will be called in template
def show_crop(request, crop_pk):
try:
crop = MiniCanvas.objects.get(pk=crop_pk)
except MiniCanvas.DoesNotExist:
crop = None
if not crop:
#TODO: return a default image maybe?
return HttpResponse()
#Don't forget content_type
return HttpResponse(crop.crop, content_type="image/jpeg")
from my_app.views import show_crop, view_that_crops
urlpatterns = patterns('',
url(r'^cropper/(?P<crop_pk>\d+)/$', show_crop, name='show_crop'),
)
<img src="{% url show_crop mini_canvas_pk %}" alt="The crop you were looking for" />
And this is it. What I didn't understand was how to call the handler suggested by voscausa in template. (I'm new at this :( )
This is a full example on how to crop an image and display it in template. However, I believe that some improvements can (and should) be made. Such as: cropping as a background task to avoid performance issues; or using memecache...
I hope this helps someone else!
EDIT I should probably add that the BlobField in models.py is not evident at first. I found about it thanks to the discussion in this google group.