Using static images with sorl-thumbnail
I am trying to serve the thumbnail of a file that resides in my STATIC_ROOT folder. It doesn't really matter if it ends up in MEDIA_URL/cache, but sorl-thumbnail will not load the image from the static folder.
current code:
{% thumbnail "开发者_StackOverflow社区images/store/no_image.png" "125x125" as thumb %}
hack that works
{% thumbnail "http://localhost/my_project/static/images/store/no_image.png" "125x125" as thumb %}
I don't like the hack because A) It is not dry (my project is actually served from a sub-directory of / B) It is using http to grab a file that is only 3 directories away, seems pointlessly inefficient
I worked around this by passing through a file to the template context from my view.
Here is an example util function I called from my views:
def get_placeholder_image():
from django.core.files.images import ImageFile
from django.core.files.storage import get_storage_class
storage_class = get_storage_class(settings.STATICFILES_STORAGE)
storage = storage_class()
placeholder = storage.open(settings.PLACEHOLDER_IMAGE_PATH)
image = ImageFile(placeholder)
image.storage = storage
return image
You could probably do something similar as a custom template tag.
Template filter works. But I am not sure, whether there is each time reading from storage. If so, it is unreasonably...
from django.template import Library
from django.core.files.images import ImageFile
from django.core.files.storage import get_storage_class
register = Library()
@register.filter
def static_image(path):
"""
{% thumbnail "/img/default_avatar.png"|static_image "50x50" as img %}
<img src="{{ MEDIA_URL }}{{img}}"/>
{% endthumbnail %}
"""
storage_class = get_storage_class(settings.STATICFILES_STORAGE)
storage = storage_class()
image = ImageFile(storage.open(path))
image.storage = storage
return image
Assuming you are using Django 1.3 you should take a look at the docs about Managing static files
If you setup everything correctly, you can include your images like this:
<img src="{{ STATIC_URL }}images/store/no_image.png" />
I ended up hijacking the fact that it can get from a URL, and wrote my own tag that overrides the _render method on the ThumbnailNode:
from django.template import Library
from django.contrib.sites.models import Site
from django.contrib.sites.models import get_current_site
from sorl.thumbnail.templatetags.thumbnail import ThumbnailNode as SorlNode
from sorl.thumbnail.conf import settings
from sorl.thumbnail.images import DummyImageFile
from sorl.thumbnail import default
register = Library()
class ThumbnailNode(SorlNode):
"""allows to add site url prefix"""
def _render(self, context):
file_ = self.file_.resolve(context)
if isinstance(file_, basestring):
site = get_current_site(context['request'])
file_ = "http://" + site.domain + file_
geometry = self.geometry.resolve(context)
options = {}
for key, expr in self.options:
noresolve = {u'True': True, u'False': False, u'None': None}
value = noresolve.get(unicode(expr), expr.resolve(context))
if key == 'options':
options.update(value)
else:
options[key] = value
if settings.THUMBNAIL_DUMMY:
thumbnail = DummyImageFile(geometry)
elif file_:
thumbnail = default.backend.get_thumbnail(
file_, geometry, **options
)
else:
return self.nodelist_empty.render(context)
context.push()
context[self.as_var] = thumbnail
output = self.nodelist_file.render(context)
context.pop()
return output
@register.tag
def thumbnail(parser, token):
return ThumbnailNode(parser, token)
Then from the template:
{% with path=STATIC_URL|add:"/path/to/static/image.png" %}
{% thumbnail path "50x50" as thumb %}
<img src="{{ thumb.url }}" />
...
Not the neatest solution... :-/
The default value of setting sorl THUMBNAIL_STORAGE is the same settings.DEFAULT_FILE_STORAGE.
You must create storage that uses STATIC_ROOT, for example you can use 'django.core.files.storage.FileSystemStorage' and instantiate with location=settings.STATIC_ROOT and base_url=settings.STATIC_URL
Only THUMBNAIL_STORAGE set in settings for a 'MyCustomFileStorage' did not work. So I had to do to DEFAULT_FILE_STORAGE and it worked.
Define in settings.py:
DEFAULT_FILE_STORAGE = 'utils.storage.StaticFilesStorage'
utils/storage.py:
import os
from datetime import datetime
from django.conf import settings
from django.core.files.storage import FileSystemStorage
from django.core.exceptions import ImproperlyConfigured
def check_settings():
"""
Checks if the MEDIA_(ROOT|URL) and STATIC_(ROOT|URL)
settings have the same value.
"""
if settings.MEDIA_URL == settings.STATIC_URL:
raise ImproperlyConfigured("The MEDIA_URL and STATIC_URL "
"settings must have different values")
if (settings.MEDIA_ROOT == settings.STATIC_ROOT):
raise ImproperlyConfigured("The MEDIA_ROOT and STATIC_ROOT "
"settings must have different values")
class TimeAwareFileSystemStorage(FileSystemStorage):
def accessed_time(self, name):
return datetime.fromtimestamp(os.path.getatime(self.path(name)))
def created_time(self, name):
return datetime.fromtimestamp(os.path.getctime(self.path(name)))
def modified_time(self, name):
return datetime.fromtimestamp(os.path.getmtime(self.path(name)))
class StaticFilesStorage(TimeAwareFileSystemStorage):
"""
Standard file system storage for static files.
The defaults for ``location`` and ``base_url`` are
``STATIC_ROOT`` and ``STATIC_URL``.
"""
def __init__(self, location=None, base_url=None, *args, **kwargs):
if location is None:
location = settings.STATIC_ROOT
if base_url is None:
base_url = settings.STATIC_URL
if not location:
raise ImproperlyConfigured("You're using the staticfiles app "
"without having set the STATIC_ROOT setting. Set it to "
"the absolute path of the directory that holds static files.")
# check for None since we might use a root URL (``/``)
if base_url is None:
raise ImproperlyConfigured("You're using the staticfiles app "
"without having set the STATIC_URL setting. Set it to "
"URL that handles the files served from STATIC_ROOT.")
if settings.DEBUG:
check_settings()
super(StaticFilesStorage, self).__init__(location, base_url, *args, **kwargs)
Reference:
https://github.com/mneuhaus/heinzel/blob/master/staticfiles/storage.py
https://docs.djangoproject.com/en/dev/ref/settings/#default-file-storage
精彩评论