cloudflare-images
Wrapper around Cloudflare Images API, with instructions to create a usable custom Django storage class such wrapper.
Development
See documentation.
- Run
just start - Run
just dumpenv - Run
pytest
Note: pytest will work only if no .env file exists with the included values. See docstrings.
Changes
Dec. 2, 2023
- Compatibility: python 3.12
- Compatibility: pydantic 2.5
Initial
- Removed: Django as a dependency
- Added: Instructions to create Django custom storage class
- Added:
.enable_batch() - Added:
.list_images() - Added:
.get_batch_token() - Added:
.get_usage_statistics() - Added:
.update_image() - Added:
.v2 - Renamed:
.base_apitov1 - Renamed:
.get()to.get_image_details() - Renamed:
.post()to.upload_image() - Renamed:
.delete()to.delete_image() - Renamed:
.upsert()to.delete_then_upload_image() - Renamed:
CloudflareImagesAPIv1toCloudflareImagesAPI
Django Instructions
Starting with Django 4.2, add a Custom Storage class to the STORAGES setting like so:
STORAGES = { # django 4.2 and above
"default": { # default
"BACKEND": "django.core.files.storage.FileSystemStorage",
},
"staticfiles": { # default
"BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage",
},
"cloudflare_images": { # add location of custom storage class
"BACKEND": "path.to.storageclass",
},
}
The path to the custom storage class should resemble the following:
from http import HTTPStatus
import httpx
from django.core.files.base import File
from django.core.files.storage import Storage
from django.utils.deconstruct import deconstructible
from cloudflare_images import CloudflareImagesAPI
@deconstructible
class LimitedStorageCloudflareImages(Storage):
def __init__(self):
super().__init__()
self.api = CloudflareImagesAPI()
def __repr__(self):
return "<LimitedToImagesStorageClassCloudflare>"
def _open(self, name: str, mode="rb") -> File:
return File(self.api.get(img_id=name), name=name)
def _save(self, name: str, content: bytes) -> str:
res = self.api.delete_then_upload_image(name, content)
return self.api.url(img_id=res.json()["result"]["id"])
def get_valid_name(self, name):
return name
def get_available_name(self, name, max_length=None):
return self.generate_filename(name)
def generate_filename(self, filename):
return filename
def delete(self, name) -> httpx.Response:
return self.api.delete(name)
def exists(self, name: str) -> bool:
res = self.api.get(name)
if res.status_code == HTTPStatus.NOT_FOUND:
return False
elif res.status_code == HTTPStatus.OK:
return True
raise Exception("Image name found but http status code is not OK.")
def listdir(self, path):
raise NotImplementedError(
"subclasses of Storage must provide a listdir() method"
)
def size(self, name: str):
return len(self.api.get(name).content)
def url(self, name: str):
return self.api.url(name)
def url_variant(self, name: str, variant: str):
return self.api.url(name, variant)
def get_accessed_time(self, name):
raise NotImplementedError(
"subclasses of Storage must provide a get_accessed_time() method"
)
def get_created_time(self, name):
raise NotImplementedError(
"subclasses of Storage must provide a get_created_time() method"
)
def get_modified_time(self, name):
raise NotImplementedError(
"subclasses of Storage must provide a get_modified_time() method"
)
Can then define a callable likeso:
from django.core.files.storage import storages
def select_storage(is_remote_env: bool):
return storages["cloudflare_images"] if is_remote_env else storages["default"]
class MyModel(models.Model):
my_img = models.ImageField(storage=select_storage)
Can also refer to it via:
from django.core.files.storage import storages
cf = storages["cloudflare_images"]
# assume previous upload done
id = <image-id-uploaded>
# get image url, defaults to 'public' variant
cf.url(id)
# specified 'avatar' variant, assuming it was created in the Cloudflare Images dashboard / API
cf.url_variant(id, 'avatar')
Release files for cloudflare-images 0.1.8
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| cloudflare_images-0.1.8.tar.gz | 9.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| cloudflare_images-0.1.8-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 17.4 kB
Release files / cloudflare_images-0.1.8.tar.gz
| Download URL | cloudflare_images-0.1.8.tar.gz |
|---|---|
| Size | 9.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
95426031ed818c052ccae47e77b614740e8b38a12fb71aa7b3f3cbb00550d143
|
|
BLAKE2b-256 checksum How to use checksums |
e52ac03b66eeef353cba305d3d1e8118137b95a48519769baa0522826be7be87
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/5.1.1 CPython/3.12.3
|
Release files / cloudflare_images-0.1.8-py3-none-any.whl
| Download URL | cloudflare_images-0.1.8-py3-none-any.whl |
|---|---|
| Size | 8.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6a34d2d907fd19692d4db5396d56384b0d96ad0bdc834fa2d4e044e6347e5449
|
|
BLAKE2b-256 checksum How to use checksums |
d25b2e874f56c557d9d1ad34de1c910e4555d83f83fd0d1c2dcb4ad6c7298420
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/5.1.1 CPython/3.12.3
|