If you want to use sorl-thumbnail, then you don't need to do anything in your model code. Just have a class like this:
class Photo(models.Model):
user = models.ForeignKey(User)
image = models.ImageField(
upload_to=get_upload_file_name,
width_field="width",
height_field="height",
blank=True
)
width = models.IntegerField(default=0)
height = models.IntegerField(default=0)
And whenever you need a 470px image, do like this in your template:
{% load thumbnail %}
...
{# Specifying width only here. #}
{# If you want a height constraint as well use e.g. "470x1000". #}
{% thumbnail photo.image "470" as im %}
<img src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}">
{% endthumbnail %}
That's it — sorl-thumbnail will take care of the rest (scaling on first request, handling the cache, etc). It operates on-demand, i.e. the resizing will be done on the first access (when the template tag is encountered) - which is normally fine. The only thing you should keep in mind is that sorl-thumbnail won't work well if your storage is slow. If you store media on a local drive - that's fine. If your storage backend is, say, Amazon S3 - don't do it.
The convenient part of this is shall you need other thumbnail sizes, you just tell sorl-thumnail you need them, right in your template code. No model changes necessary.
If you want to ensure the thumbnails are pre-generated with sorl-thumbnail, you can either call get_thumbnail
explicitly or use, e.g. a Celery task that would run get_thumbnail
(ignoring the result) for you, e.g.
@app.task
def ensure_thumbnail(photo_pk, size="470"):
photo = Photo.objects.get(pk=photo_pk)
get_thumbnail(photo.image, size)
And whenever you see a new upload, call ensure_thumbnail.delay(photo.pk)
.
Be sure to check out the examples for more information.
If you feel this this approach isn't how you want things to be, or you have a slow storage then use django-imagekit. I'm not much familiar with it (haven't used in production myself), but based on the documentation it looks like this:
Your model would look like:
from imagekit.models import ImageSpecField
from imagekit.processors import ResizeToFit
...
class Photo(models.Model):
user = models.ForeignKey(User)
image_original = models.ImageField(
upload_to=get_upload_file_name,
width_field="image_original_width",
height_field="image_original_height",
blank=True
)
image_original_width = models.IntegerField(default=0)
image_original_height = models.IntegerField(default=0)
# I haven't found a way to not specify the height.
image_470 = ImageSpecField(source="image_original",
processors=[ResizeToFit(470, 1000)],
format="JPEG")
(Like sorl-thumbnail, this won't actually create a database field. If you absolutely want a fully managed independent image file, with its own database field - seems that your best option is to explicitly generate thumbnails in Photo.save
using a bare Pillow library.)
Then it's just plain and simple:
<img src="{{ photo.image_470.url }}"
width="{{ photo.image_470.width }}"
height="{{ photo.image_470.height }}"
alt="..." />
Be sure to check out documentation on caching which explains how the caching works (and to generate thumnails asynchronously, shall you want it this way).