Skip to main content

Wrapper around Cloudflare Images API

Project description

cloudflare-images

Github CI

Wrapper around Cloudflare Images API, with instructions to create a usable custom Django storage class such wrapper.

Development

See documentation.

  1. Run poetry install
  2. Run poetry shell
  3. Run pytest

Note: pytest will work only if no .env file exists with the included values. See docstrings.

Changes

  • 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_api to v1
  • Renamed: .get() to .get_image_details()
  • Renamed: .post() to .upload_image()
  • Renamed: .delete() to .delete_image()
  • Renamed: .upsert() to .delete_then_upload_image()
  • Renamed: CloudflareImagesAPIv1 to CloudflareImagesAPI

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')

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cloudflare_images-0.1.3.tar.gz (7.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cloudflare_images-0.1.3-py3-none-any.whl (7.8 kB view details)

Uploaded Python 3

File details

Details for the file cloudflare_images-0.1.3.tar.gz.

File metadata

  • Download URL: cloudflare_images-0.1.3.tar.gz
  • Upload date:
  • Size: 7.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.5.1 CPython/3.10.6 Darwin/22.5.0

File hashes

Hashes for cloudflare_images-0.1.3.tar.gz
Algorithm Hash digest
SHA256 113ae7dfacad3235f4065287aa54797de9e1e3e1465e397aaa3bab98b960cb69
MD5 1268afc4631665dfcf95798d3b805288
BLAKE2b-256 90f6abba240c3ae74c6de2834c7f6c9a8c741043c869677b7f2c787fc213c07c

See more details on using hashes here.

File details

Details for the file cloudflare_images-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: cloudflare_images-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 7.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.5.1 CPython/3.10.6 Darwin/22.5.0

File hashes

Hashes for cloudflare_images-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 f7cbd93765be0c0c4a13460fc6e8f7392fa984b157d0a695cd7258971bf6c86f
MD5 55853277c1f0b3bd30e004542f59446f
BLAKE2b-256 9d175875a0ee5890d023a25fb552156404ff8f9f6899fc1ab65e0a07e902a7c3

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page