- Notifications
You must be signed in to change notification settings - Fork63
Django Standardized Image Field
License
codingjoe/django-stdimage
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
This package has been deprecated in favor ofdjango-pictures.
First, make sure you understand the differences between the two packages andhow to serve images in a modern web application via thepicture-Element.
Next, follow the setup instructions fordjango-pictures.
Once you are set up, change your models to use the newPictureField
and provide theaspect_ratios
you'd like to serve. Do create migrations just yet.
This step should be followed by changing your templates and frontend.The new placeholders feature for local development should help youto do this almost effortlessly.
Finally, runmakemigrations
and replace theAlterField
operation withAlterPictureField
.
We highly recommend to use Django'simage_width
andimage_height
fields, to avoidunnecessary IO. If you can add these fields to your model, you can use the followingsnippet to populate them:
importdjango.core.files.storagefromdjango.dbimportmigrations,modelsimportpictures.modelsfrompictures.migrationsimportAlterPictureFielddefforward(apps,schema_editor):forobjinapps.get_model("my-app.MyModel").objects.all().iterator():obj.image_width=obj.logo.widthobj.image_height=obj.logo.heightobj.save(update_fields=["image_height","image_width"])defbackward(apps,schema_editor):apps.get_model("my-app.MyModel").objects.all().update(image_width=None,image_height=None, )classMigration(migrations.Migration):dependencies= [ ('my-app','0001_initial'), ]operations= [migrations.AddField(model_name="mymodel",name="image_height",field=models.PositiveIntegerField(editable=False,null=True), ),migrations.AddField(model_name="mymodel",name="image_width",field=models.PositiveIntegerField(editable=False,null=True), ),migrations.RunPython(forward,backward),AlterPictureField(model_name="mymodel",name="image",field=pictures.models.PictureField(aspect_ratios=["3/2","3/1"],breakpoints={"desktop":1024,"mobile":576},container_width=1200,file_types=["WEBP"],grid_columns=12,height_field="image_height",pixel_densities=[1,2],storage=django.core.files.storage.FileSystemStorage(),upload_to="pictures/",verbose_name="image",width_field="image_width", ), ), ]
This is a drop-in replacement for theDjango ImageField that provides a standardized way to handle image uploads.It is designed to be as easy to use as possible, and to provide a consistent interface for all image fields.It allows images to be presented in various size variants (eg:thumbnails, mid, and hi-res versions)and it provides a way to handle images that are too large with validators.
Django Standardized Image Field implements the following features:
- Django-Storages compatible (eg: S3, Azure, Google Cloud Storage, etc)
- Resizes images to different sizes
- Access thumbnails on model level, no template tags required
- Preserves original images
- Can be rendered asynchronously (ie as aCelery job)
- Restricts acceptable image dimensions
- Renames a file to a standardized name format (using a callable
upload_to
function, see below)
Simply install the latest stable package using the following command:
pip install django-stdimage# orpipenv install django-stdimage
and add'stdimage'
toINSTALLED_APP
s in your settings.py, that's it!
Now it's instally you can use either:StdImageField
orJPEGField
.
StdImageField
works just like Django's ownImageFieldexcept that you can specify different size variations.
TheJPEGField
is identical to theStdImageField
but all images areconverted to JPEGs, no matter what type the original file is.
Variations are specified within a dictionary. The key will be the attribute referencing the resized image.A variation can be defined both as a tuple or a dictionary.
Example:
fromdjango.dbimportmodelsfromstdimageimportStdImageField,JPEGFieldclassMyModel(models.Model):# works just like django's ImageFieldimage=StdImageField(upload_to='path/to/img')# creates a thumbnail resized to maximum size to fit a 100x75 areaimage=StdImageField(upload_to='path/to/img',variations={'thumbnail': {'width':100,'height':75}})# is the same as dictionary-style callimage=StdImageField(upload_to='path/to/img',variations={'thumbnail': (100,75)})# JPEGField variations are converted to JPEGs.jpeg=JPEGField(upload_to='path/to/img',variations={'full': (None,None),'thumbnail': (100,75)}, )# creates a thumbnail resized to 100x100 croping if necessaryimage=StdImageField(upload_to='path/to/img',variations={'thumbnail': {"width":100,"height":100,"crop":True} })## Full ammo here. Please note all the definitions below are equalimage=StdImageField(upload_to='path/to/img',blank=True,variations={'large': (600,400),'thumbnail': (100,100,True),'medium': (300,200), },delete_orphans=True)
To use these variations in templates usemyimagefield.variation_name
.
Example:
<ahref="{{ object.myimage.url }}"><imgalt=""src="{{ object.myimage.thumbnail.url }}"/></a>
You can use a function for theupload_to
argument. Using [Django Dynamic Filenames][dynamic_filenames].[dynamic_filenames]:https://github.com/codingjoe/django-dynamic-filenames
This allows images to be given unique paths and filenames based on the model instance.
Example
fromdjango.dbimportmodelsfromstdimageimportStdImageFieldfromdynamic_filenamesimportFilePatternupload_to_pattern=FilePattern(filename_pattern='my_model/{app_label:.25}/{model_name:.30}/{uuid:base32}{ext}',)classMyModel(models.Model):# works just like django's ImageFieldimage=StdImageField(upload_to=upload_to_pattern)
TheStdImageField
doesn't implement any size validation out-of-the-box.However, Validation can be specified using the validator attributeand using a set of validators shipped with this package.Validators can be used for both Forms and Models.
Example
fromdjango.dbimportmodelsfromstdimage.validatorsimportMinSizeValidator,MaxSizeValidatorfromstdimage.modelsimportStdImageFieldclassMyClass(models.Model):image1=StdImageField(validators=[MinSizeValidator(800,600)])image2=StdImageField(validators=[MaxSizeValidator(1028,768)])
CAUTION: The MaxSizeValidator should be used with caution.As storage isn't expensive, you shouldn't restrict upload dimensions.If you seek prevent users form overflowing your memory you should restrict the HTTP upload body size.
Djangodropped supportfor automated deletions in version 1.3.
Since version 5, this package supports adelete_orphans
argument. It will deleteorphaned files, should a file be deleted or replaced via a Django form and the object withtheStdImageField
be deleted. It will not delete files if the field value is changed orreassigned programatically. In these rare cases, you will need to handle proper deletionyourself.
fromdjango.dbimportmodelsfromstdimage.modelsimportStdImageFieldclassMyModel(models.Model):image=StdImageField(upload_to='path/to/files',variations={'thumbnail': (100,75)},delete_orphans=True,blank=True, )
Tools like celery allow to execute time-consuming tasks outside of the request. If you don't wantto wait for your variations to be rendered in request, StdImage provides you the option to pass anasync keyword and a 'render_variations' function that triggers the async task.Note that the callback is not transaction save, but the file variations will be present.The example below is based on celery.
tasks.py
:
fromdjango.appsimportappsfromceleryimportshared_taskfromstdimage.utilsimportrender_variations@shared_taskdefprocess_photo_image(file_name,variations,storage):render_variations(file_name,variations,replace=True,storage=storage)obj=apps.get_model('myapp','Photo').objects.get(image=file_name)obj.processed=Trueobj.save()
models.py
:
fromdjango.dbimportmodelsfromstdimage.modelsimportStdImageFieldfrom .tasksimportprocess_photo_imagedefimage_processor(file_name,variations,storage):process_photo_image.delay(file_name,variations,storage)returnFalse# prevent default renderingclassAsyncImageModel(models.Model):image=StdImageField(# above task definition can only handle one model object per image filenameupload_to='path/to/file/',# or use a functionrender_variations=image_processor# pass boolean or callable )processed=models.BooleanField(default=False)# flag that could be used for view querysets
You might have added or changed variations to an existing field. That means you will need to render new variations.This can be accomplished using a management command.
python manage.py rendervariations'app_name.model_name.field_name' [--replace] [-i/--ignore-missing]
Thereplace
option will replace all existing files.Theignore-missing
option will suspend 'missing source file' errors and keeprendering variations for other files. Otherwise, the command will stop on first missing file.
About
Django Standardized Image Field
Topics
Resources
License
Code of conduct
Security policy
Stars
Watchers
Forks
Languages
- Python100.0%