[ADD] Helper for /website/image (allows to use aggressive cache)

This commit is contained in:
Fabien Meghazi 2014-09-05 18:20:55 +02:00
parent cdcd488f5a
commit bc5e6fa2cb
12 changed files with 45 additions and 51 deletions

View File

@ -8,8 +8,6 @@ import xml.etree.ElementTree as ET
import logging
import re
from sys import maxint
import werkzeug.utils
import urllib2
import werkzeug.wrappers
@ -17,7 +15,7 @@ from PIL import Image
import openerp
from openerp.addons.web import http
from openerp.http import request, Response
from openerp.http import request, STATIC_CACHE
logger = logging.getLogger(__name__)
@ -397,8 +395,8 @@ class Website(openerp.addons.web.controllers.main.Home):
@http.route([
'/website/image',
'/website/image/<model>/<id>/<field>',
'/website/image/<model>/<id>/<field>/<int:max_width>x<int:max_height>'
'/website/image/<model>-<id>-<field>',
'/website/image/<model>-<id>-<field>-<int:max_width>x<int:max_height>'
], auth="public", website=True)
def website_image(self, model, id, field, max_width=None, max_height=None):
""" Fetches the requested field and ensures it does not go above
@ -416,9 +414,12 @@ class Website(openerp.addons.web.controllers.main.Home):
all cases.
"""
try:
idsha = id.split('_')
id = idsha[0]
response = werkzeug.wrappers.Response()
return request.registry['website']._image(
request.cr, request.uid, model, id, field, response, max_width, max_height)
request.cr, request.uid, model, id, field, response, max_width, max_height,
cache=STATIC_CACHE if len(idsha) > 1 else None)
except Exception:
logger.exception("Cannot render image field %r of record %s[%s] at size(%s,%s)",
field, model, id, max_width, max_height)

View File

@ -286,21 +286,17 @@ class Image(orm.AbstractModel):
def record_to_html(self, cr, uid, field_name, record, column, options=None, context=None):
if options is None: options = {}
classes = ['img', 'img-responsive'] + options.get('class', '').split()
aclasses = ['img', 'img-responsive'] + options.get('class', '').split()
classes = ' '.join(itertools.imap(escape, aclasses))
url_frags = {
'classes': ' '.join(itertools.imap(escape, classes)),
'model': record._model._name,
'id': record.id,
'field': field_name,
'max_size': '',
}
max_size = None
max_width, max_height = options.get('max_width', 0), options.get('max_height', 0)
if max_width or max_height:
url_frags['max_size'] = '/%sx%s' % (max_width, max_height)
max_size = '%sx%s' % (max_width, max_height)
img = '<img class="%(classes)s" src="/website/image/%(model)s/%(id)s/%(field)s%(max_size)s"/>'
return ir_qweb.HTMLSafe(img % url_frags)
src = self.pool['website'].image_url(cr, uid, record, field_name, max_size)
img = '<img class="%s" src="%s"/>' % (classes, src)
return ir_qweb.HTMLSafe(img)
local_url_re = re.compile(r'^/(?P<module>[^]]+)/static/(?P<rest>.+)$')
def from_html(self, cr, uid, model, column, element, context=None):

View File

@ -4,13 +4,13 @@ import contextlib
import datetime
import hashlib
import inspect
import itertools
import logging
import math
import mimetypes
import unicodedata
import os
import re
import time
import urlparse
from PIL import Image
@ -513,7 +513,7 @@ class website(osv.osv):
response.data = f.read()
return response.make_conditional(request.httprequest)
def _image(self, cr, uid, model, id, field, response, max_width=maxint, max_height=maxint, context=None):
def _image(self, cr, uid, model, id, field, response, max_width=maxint, max_height=maxint, cache=None, context=None):
""" Fetches the requested field and ensures it does not go above
(max_width, max_height), resizing it if necessary.
@ -565,6 +565,10 @@ class website(osv.osv):
response.set_etag(hashlib.sha1(record[field]).hexdigest())
response.make_conditional(request.httprequest)
if cache:
response.cache_control.max_age = cache
response.expires = int(time.time() + cache)
# conditional request match
if response.status_code == 304:
return response
@ -593,6 +597,13 @@ class website(osv.osv):
return response
def image_url(self, cr, uid, record, field, size=None, context=None):
"""Returns a local url that points to the image field of a given browse record."""
model = record._name
id = '%s_%s' % (record.id, hashlib.sha1(record.write_date).hexdigest()[0:7])
size = '' if size is None else '-%s' % size
return '/website/image/%s-%s-%s%s' % (model, id, field, size)
class website_menu(osv.osv):
_name = "website.menu"
@ -668,11 +679,7 @@ class ir_attachment(osv.osv):
if attach.url:
result[attach.id] = attach.url
else:
result[attach.id] = urlplus('/website/image', {
'model': 'ir.attachment',
'field': 'datas',
'id': attach.id
})
result[attach.id] = self.pool['website'].image_url(cr, uid, attach, 'datas')
return result
def _datas_checksum(self, cr, uid, ids, name, arg, context=None):
return dict(

View File

@ -123,7 +123,7 @@
<div t-foreach="blog_posts" t-as="blog_post" class="mb32">
<img class="img-circle pull-right mt16"
t-attf-src="/website/image/res.partner/{{ blog_post.author_id.id }}/image_small"
t-att-src="website.image_url(blog_post.author_id, 'image_small')"
style="width: 50px;"/>
<a t-attf-href="/blog/#{ slug(blog_post.blog_id) }/post/#{ slug(blog_post) }">
@ -205,7 +205,7 @@
<h2 t-field="blog_post.subtitle"/>
<p class="post-meta text-muted text-center" name="blog_post_data"/>
<div>
<img class="img-circle" t-attf-src="/website/image/res.partner/{{ blog_post.author_id.id }}/image_small" style="width: 30px; margin-right: 10px;"/>
<img class="img-circle" t-att-src="website.image_url(blog_post.author_id, 'image_small')" style="width: 30px; margin-right: 10px;"/>
<span t-field="blog_post.author_id" style="display: inline-block;" t-field-options='{
"widget": "contact",
"fields": ["name"]
@ -224,7 +224,7 @@
<ul class="media-list" id="comments-list">
<li t-foreach="comments" t-as="message" class="media">
<span class="pull-left">
<img class="media-object img img-circle" t-attf-src="/website/image/mail.message/{{ message.id }}/author_avatar" style="width: 30px"/>
<img class="media-object img img-circle" t-att-src="website.image_url(message, 'author_avatar')" style="width: 30px"/>
</span>
<div class="media-body">
<t t-call="website.publish_short">
@ -249,7 +249,7 @@
<h1 t-field="next_post.name"/>
<h2 t-field="next_post.subtitle"/>
<div>
<img class="img-circle" t-attf-src="'/website/image/res.partner/{{ next_post.author_id.id }}/image_small" style="width: 30px; margin-right: 10px;"/>
<img class="img-circle" t-att-src="website.image_url(next_post.author_id, 'image_small')" style="width: 30px; margin-right: 10px;"/>
<span t-field="next_post.author_id" style="display: inline-block;" t-field-options='{
"widget": "contact",
"fields": ["name"]
@ -292,7 +292,7 @@
<form id="comment" t-attf-action="/blogpost/comment" method="POST">
<div class="media">
<span class="pull-left">
<img class="img img-circle media-object" t-attf-src="/website/image/res.partner/{{ user_id.partner_id.id }}/image_small" style="width: 30px"/>
<img class="img img-circle media-object" t-att-src="website.image_url(user_id.partner_id, 'image_small')" style="width: 30px"/>
</span>
<div class="media-body">
<input name="blog_post_id" t-att-value="blog_post.id" type="hidden"/>

View File

@ -404,7 +404,7 @@
<div class="country_events_list">
<div>
<t t-if="country">
<img class="img-rounded img-responsive" t-attf-src="/website/image/res.country/{{ country.id }}/image"></img>
<img class="img-rounded img-responsive" t-att-src="website.image_url(country, 'image')"></img>
<h4><b>Events: <span t-esc="country.name"></span></b></h4>
</t>
<t t-if="not country">

View File

@ -12,6 +12,3 @@ class hr(osv.osv):
_defaults = {
'website_published': False
}
def img(self, cr, uid, ids, field='image_small', context=None):
return "/website/image/%s/%s/%s" % (self._name, ids[0], field)

View File

@ -12,7 +12,7 @@
<div t-foreach="employee_ids" t-as="employee" class="col-sm-3 col-lg-2 mt16 text-center colsize">
<t t-call="website.publish_management"><t t-set="object" t-value="employee"/></t>
<div class="clearfix"/>
<img t-att-src="employee.img('image_medium')" class="img shadow img-rounded"/>
<img t-att-src="website.image_url(employee, 'image_medium')" class="img shadow img-rounded"/>
<div class="mt8">
<strong t-field="employee.name"></strong>
</div>

View File

@ -39,7 +39,7 @@
</div>
<div class="row mt8" t-foreach="groups" t-as="group">
<div class="col-md-3">
<img t-attf-src="/website/image/mail.group/{{ group['id'] }}/image_small" class="pull-left"/>
<img t-att-src="website.image_url(group, 'image_small')" class="pull-left"/>
<strong><a t-attf-href="/groups/#{ slug(group) }" t-esc="group.name"/></strong><br />
<t t-if="group.alias_id and group.alias_id.alias_name and group.alias_id.alias_domain">
<i class='fa fa-envelope-o'/>
@ -177,7 +177,7 @@
</div>
<div class="media">
<img class="img-rounded pull-left mt0 media-object o_mg_avatar"
t-attf-src="/website/image/mail.message/{{ message.id }}/author_avatar"/>
t-att-src="website.image_url(message, 'author_avatar')"/>
<div class="media-body">
<h4 class="media-heading" t-esc="message.description"/>
<small>
@ -247,7 +247,7 @@
<ul class="media-list">
<li t-foreach="messages" t-as="thread" class="media">
<img class="img-rounded pull-left mt0 media-object o_mg_avatar"
t-attf-src="/website/image/mail.message/{{ thread.id }}/author_avatar"/>
t-att-src="website.image_url(thread, 'author_avatar')"/>
<div class="media-body">
<h4 class="media-heading">
<a t-attf-href="/groups/#{slug(group)}/#{slug(thread)}?mode=#{mode}&amp;date_begin=#{date_begin}&amp;date_end=#{date_end}" t-esc="thread.description"/>

View File

@ -116,7 +116,7 @@
<t t-foreach="quotation.message_ids" t-as="message">
<li class="media" t-if="message.type &lt;&gt; 'comment' or message.subtype_id">
<div class="media-body">
<img class="media-object pull-left" t-attf-src="/website/image/res.partner/{{ message.author_id.id }}/image_small" style="width: 50px; margin-right: 10px;"/>
<img class="media-object pull-left" t-att-src="website.image_url(message.author_id, 'image_small')" style="width: 50px; margin-right: 10px;"/>
<div class="media-body">
<h5 class="media-heading">
<span t-field="message.author_id"/> <small>on <span t-field="message.date"/></small>
@ -134,7 +134,7 @@
<xpath expr="//h1" position="after">
<section class="mb32 css_editable_mode_hidden hidden-print">
<form id="comment" t-attf-action="/quote/#{quotation.id}/#{quotation.access_token}/post" method="POST">
<img class="img pull-left img-rounded" t-attf-src="/website/image/res.partner/{{ user_id.partner_id.id }}/image_small" style="width: 50px; margin-right: 10px;"/>
<img class="img pull-left img-rounded" t-att-src="website.image_url(user_id.partner_id, 'image_small')" style="width: 50px; margin-right: 10px;"/>
<div class="pull-left mb32" style="width: 75%%">
<textarea rows="4" name="comment" class="form-control" placeholder="Send us a note..."></textarea>
<button type="submit" class="btn btn-primary mt8">Send</button>

View File

@ -178,9 +178,6 @@ class product_template(osv.Model):
else:
return self.set_sequence_bottom(cr, uid, ids, context=context)
def img(self, cr, uid, ids, field='image_small', context=None):
return "/website/image/%s/%s/%s" % (self._name, ids[0], field)
class product_product(osv.Model):
_inherit = "product.product"
@ -194,10 +191,6 @@ class product_product(osv.Model):
'website_url': fields.function(_website_url, string="Website url", type="char"),
}
def img(self, cr, uid, ids, field='image_small', context=None):
temp_id = self.browse(cr, uid, ids[0], context=context).product_tmpl_id.id
return "/website/image/product.template/%s/%s" % (temp_id, field)
class product_attribute(osv.Model):
_inherit = "product.attribute"
_columns = {

View File

@ -121,7 +121,7 @@ $('.oe_website_sale').each(function () {
if (product_id) {
var $img = $(this).closest('tr.js_product, .oe_website_sale').find('span[data-oe-model^="product."][data-oe-type="image"] img');
$img.attr("src", "/website/image/product.product/" + product_id + "/image");
$img.attr("src", "/website/image/product.product-" + product_id + "-image");
$img.parent().attr('data-oe-model', 'product.product').attr('data-oe-id', product_id)
.data('oe-model', 'product.product').data('oe-id', product_id);
}

View File

@ -77,7 +77,7 @@
</div>
<div class="oe_product_image">
<a itemprop="url" t-att-href="keep('/shop/product/%s' % slug(product), page=(pager['page']['num'] if pager['page']['num']>1 else None))">
<img itemprop="image" class="img img-responsive" t-attf-src="/website/image/product.template/#{product.id}/image{{'' if product_image_big else '/300x300' }}"/>
<img itemprop="image" class="img img-responsive" t-att-src="website.image_url(product, 'image', None if product_image_big else '300x300')"/>
</a>
</div>
<section>
@ -374,7 +374,7 @@
<section t-attf-class="container oe_website_sale #{(compute_currency(product.lst_price) - product.price) &gt; 0.1 and 'discount'}" id="product_detail">
<div class="row">
<div class="col-sm-7 col-md-7 col-lg-7">
<span itemprop="image" t-field="product.image" t-field-options='{"widget": "image", "class": "product_detail_img"}'/>
<span itemprop="image" class="agr" t-field="product.image" t-field-options='{"widget": "image", "class": "product_detail_img"}'/>
</div><div class="col-sm-5 col-md-5 col-lg-4 col-lg-offset-1">
<h1 itemprop="name" t-field="product.name">Product Name</h1>
<span itemprop="url" style="display:none;" t-esc="'/shop/product/%s' % slug(product)"/>
@ -603,7 +603,7 @@
<ul class="media-list" id="comments-list" t-if="product.website_message_ids">
<li t-foreach="product.website_message_ids" t-as="message" class="media">
<div class="media-body oe_msg">
<img class="media-object pull-left oe_msg_avatar" t-attf-src="/website/image/res.partner/{{ message.author_id.id }}/image_small" style="width: 50px; margin-right: 10px;"/>
<img class="media-object pull-left oe_msg_avatar" t-att-src="website.image_url(message.author_id, 'image_small')" style="width: 50px; margin-right: 10px;"/>
<div class="media-body oe_msg_content">
<t t-call="website.publish_short">
<t t-set="object" t-value="message"/>
@ -633,7 +633,7 @@
</ul>
<div class="css_editable_mode_hidden">
<form id="comment" t-attf-action="/shop/product/comment/#{product.id}" method="POST">
<img class="img pull-left img-rounded" t-attf-src="/website/image/res.partner/{{ user_id.partner_id.id }}/image_small" style="width: 50px; margin-right: 10px;"/>
<img class="img pull-left img-rounded" t-att-src="website.image_url(user_id.partner_id, 'image_small')" style="width: 50px; margin-right: 10px;"/>
<div class="pull-left mb32" style="width: 75%%">
<textarea rows="3" name="comment" class="form-control" placeholder="Write a comment..."></textarea>
<a class="btn btn-primary mt8 a-submit">Post</a>