| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Heavily based on django-versatileimagefield, but with a few important differences:
Replacing existing uses of django-versatileimagefield requires the following steps:
If you used e.g. instance.image.crop.200x200 and instance.image.thumbnail.800x500 before, you should add the following setting:
IMAGEFIELD_FORMATS = {
# image field path, lowercase
'yourapp.yourmodel.image': {
'square': ['default', ('crop', (200, 200))],
'full': ['default', ('thumbnail', (800, 500))],
# The 'full' spec is equivalent to the following format
# specification in terms of image file produced (the
# resulting file name is different though):
# 'full': [
# 'autorotate', 'process_jpeg', 'process_png',
# 'process_gif', 'autorotate',
# ('thumbnail', (800, 500)),
# ],
# Note that the exact list of default processors may
# change in the future.
},
}After running ./manage.py process_imagefields --all once you can now use use instance.image.square and instance.image.thumbnail in templates instead. Note that the properties on the image file do by design not check whether thumbs exist.
Install from PyPI: pip install django-imagefield.
For faster image processing with pyvips (optional):
pip install django-imagefield[vips]
Then add imagefield to your project's INSTALLED_APPS:
# settings.py INSTALLED_APPS = [ ... "imagefield", ... ]
django-imagefield supports two image processing backends:
An optional backend using the libvips library through pyvips. Offers significantly better performance:
To use the pyvips backend:
Install the optional dependency:
pip install django-imagefield[vips]
Configure the backend in your settings:
# settings.py IMAGEFIELD_BACKEND = "vips" # default is "pillow"
Both backends support all the same features and processors. You can switch between backends without changing your code or reprocessing existing images.
While both backends provide the same API, there are some subtle differences in how images are processed:
These differences are generally transparent and result in equivalent or improved output quality. The vips backend is optimized for better performance and smaller file sizes where possible.
When writing custom processors, you work directly with the native image objects of your chosen backend:
Pillow backend - processors receive PIL.Image.Image objects:
from imagefield.processing_pillow import register_pillow
from PIL import ImageDraw, ImageFont
@register_pillow
def add_watermark(get_image, text="© Copyright"):
def processor(image, context):
image = get_image(image, context)
# Use full PIL API
draw = ImageDraw.Draw(image)
font = ImageFont.truetype("arial.ttf", 36)
draw.text((10, 10), text, font=font, fill=(255, 255, 255, 128))
return image
return processor
pyvips backend - processors receive pyvips.Image objects:
from imagefield.processing_vips import register_vips
import pyvips
@register_vips
def add_watermark(get_image, text="© Copyright"):
def processor(image, context):
image = get_image(image, context)
# Use full pyvips API
text_img = pyvips.Image.text(text, font="sans 36", rgba=True)
return image.composite(text_img, 'over', x=10, y=10)
return processor
For processors that only manipulate context (like changing format or quality), you can register them for both backends:
from imagefield.processing_pillow import register_pillow
try:
from imagefield.processing_vips import register_vips
except ImportError:
register_vips = lambda fn: fn
@register_pillow
@register_vips
def force_quality(get_image, quality=95):
def processor(image, context):
context.save_kwargs["quality"] = quality
return get_image(image, context)
return processor
Once imagefield is added to INSTALLED_APPS, add ImageField instances to your Django models in the usual way:
from django.db import models
from imagefield.fields import ImageField
class ImageModel(models.Model):
image = ImageField(
upload_to="images",
formats={
"thumb": ["default", ("crop", (300, 300))],
"desktop": ["default", ("thumbnail", (300, 225))],
},
auto_add_fields=True,
)
A widget for selecting the PPOI is automatically used in the Django Admin.
To use an ImageField in your own Django Form, you should ensure that the image_ppoi field is added the form:
from django.form import modelform_factory form_cls = modelform_factory(ImageModel, fields=['image', 'image_ppoi'])
You should make sure to add the form.media to your page template's <head>.
Retrieve the image URL in your template like, instance.image.thumb.
Access image URLs in templates by using the format names defined in formats or IMAGEFIELD_FORMATS:
<!-- Direct URL access -->
<img src="{{ instance.image.thumb }}" alt="Thumbnail">
<img src="{{ instance.image.desktop }}" alt="Desktop">
<!-- In a background image -->
<div style="background-image: url({{ instance.image.thumb }})"></div>
<!-- Get width/height from auto-added fields -->
<img src="{{ instance.image.thumb }}"
width="{{ instance.image_width }}"
height="{{ instance.image_height }}"
alt="Image">The IMAGEFIELD_FORMATS setting maps field paths to format specifications:
IMAGEFIELD_FORMATS = {
# Key: "app_label.model_name.field_name" (lowercase)
"yourapp.yourmodel.image": {
# Value: Dict of format_name -> processor_list
"format_name": [processor1, processor2, ...],
},
}Each format specification is a list of processors. Processors can be:
Common processor arguments:
Example:
IMAGEFIELD_FORMATS = {
"blog.post.header_image": {
"thumbnail": ["default", ("thumbnail", (400, 300))],
"square": ["default", ("crop", (200, 200))],
},
}The form widget builds on top of the default Django image field which allows resetting the value of the field; it additionally shows a preview image, and if there's a linked PPOI field, a PPOI picker.
The default preview is a max. 300x300 thumbnail. You can customize this by adding a preview format spec to the list of formats.
To use a different widget while keeping the preview and PPOI functionality, pass the widget class (not an instance) in your ModelForm:
from django import forms
from myapp.models import MyModel
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
fields = ['image']
widgets = {
'image': forms.FileInput, # ✓ Pass the class, not FileInput()
}To completely disable the preview and PPOI widget, override the field entirely with a regular Django forms.ImageField:
class MyModelForm(forms.ModelForm):
image = forms.ImageField() # Replaces the auto-generated field
class Meta:
model = MyModel
fields = ['image']See test_custom_widget_via_meta_widgets and test_custom_widget_without_preview in the test suite for working examples.
To serialize image fields with their various formats in DRF, use SerializerMethodField:
from rest_framework import serializers
class MyModelSerializer(serializers.ModelSerializer):
image_urls = serializers.SerializerMethodField()
class Meta:
model = MyModel
fields = ['id', 'image_urls']
def get_image_urls(self, obj):
if not obj.image:
return None
return {
'thumb': obj.image.thumb,
'desktop': obj.image.desktop,
}This returns a dictionary of URLs for each defined format.
When an image field is cleared or a model instance is deleted, django-imagefield automatically removes all generated/processed images. However, the original uploaded file is not automatically deleted, following Django's default behavior to prevent accidental data loss.
If you need to delete original files, you can implement a custom signal handler. See Django's documentation on signals for details on handling the post_delete signal.
django-imagefield uses an image processing pipeline modelled after Django's middleware.
The following processors are available out of the box:
Processors can be specified either using their name alone, or if they take arguments, using a tuple where the first entry is the processors' name and the rest are positional arguments.
You can easily register your own processors or even override built-in processors if you want to:
from imagefield.processing import register
# You could also write a class with a __call__ method, but I really
# like the simplicity of functions.
@register
def my_processor(get_image, ...):
def processor(image, context):
# read some information from the image...
# or maybe modify it, but it's mostly recommended to modify
# the image after calling get_image
image = get_image(image, context)
# modify the image, and return it...
modified_image = ...
# maybe modify the context...
return modified_image
return processorThe processor's name is taken directly from the registered object.
An example processor which converts images to grayscale would look as follows:
from PIL import ImageOps
from imagefield.processing import register
@register
def grayscale(get_image):
def processor(image, context):
image = get_image(image, context)
return ImageOps.grayscale(image)
return processorNow include "grayscale" in the processing spec for the image where you want to use it.
The context is a namespace with the following attributes (feel free to add your own):
The ppoi, extension, processors and name attributes cannot be modified when running processors anymore. Under some circumstances extension and name will not even be there.
If you want to modify the extension or file type, or create a different processing pipeline depending on facts not known when configuring settings you can use a callable instead of the list of processors. The callable will receive the fieldfile and the context instance and must at least set the context's processors attribute to something sensible. Just as an example here's an image field which always returns JPEG thumbnails:
from imagefield.processing import register
@register
def force_jpeg(get_image):
def processor(image, context):
image = get_image(image, context)
context.save_kwargs["format"] = "JPEG"
context.save_kwargs["quality"] = 90
return image
return processor
def jpeg_processor_spec(fieldfile, context):
context.extension = ".jpg"
context.processors = [
"force_jpeg",
"autorotate",
("thumbnail", (200, 200)),
]
class Model(...):
image = ImageField(..., formats={"thumb": jpeg_processor_spec})Of course you can also access the model instance through the field file by way of its fieldfile.instance attribute and use those informations to customize the pipeline.
django-imagefield supports a few settings to customize aspects of its behavior.
The default settings are as follows:
# Automatically generate and delete images when saving and deleting models.
# Can either be a boolean or a list of "app.model.field" strings. It's
# recommended to set this to False for some types of batch processing since
# updating the images may slow things down a lot.
IMAGEFIELD_AUTOGENERATE = True
# The image field doesn't generally need a cache, but it's definitely
# useful for admin thumbnails and the versatile image proxy. The timeout
# can be configured here. By default, a random duration between 170 and
# 190 days is used, so that the cache doesn't expire at the same time for
# all images when running several server processes.
IMAGEFIELD_CACHE_TIMEOUT = lambda: randint(170 * 86400, 190 * 86400)
# See above.
IMAGEFIELD_FORMATS = {}
# Whether images should be deeply validated when saving them. It can be
# useful to opt out of this for batch processing.
IMAGEFIELD_VALIDATE_ON_SAVE = True
# Errors while processing images lead to exceptions. Sometimes it's
# desirable to only log those exceptions but fall back to the original
# image. This setting let's you do that. Useful when you have many images
# which haven't been verified by the image field.
IMAGEFIELD_SILENTFAILURE = False
# Add support for instance.image.crop.WxH and instance.image.thumbnail.WxH
# An easier path to migrate away from django-versatileimagefield.
IMAGEFIELD_VERSATILEIMAGEPROXY = False
# How many folders and subfolders are created for processed images. The
# default value is 1 for backwards compatibility, it's recommended to
# increase the value to 2 or 3.
IMAGEFIELD_BIN_DEPTH = 1django-imagefield uses pre-commit to keep the code clean and formatted.
The easiest way to build the documentation and run the test suite is also by using tox:
tox -e docs # Open docs/build/html/index.html
tox -l # To show the available combinations of Python and Django| Back | FazBrowse Home | New Git URL |