Metadata-Version: 2.1
Name: django-backblaze-b2
Version: 2.0.0
Summary: A Django app to use backblaze b2 as storage.
Home-page: https://github.com/ehossack/django-backblaze-b2/
License: BSD-2-Clause
Keywords: django,storage,backblaze,b2,cloud
Author: Etienne H
Author-email: django_backblaze_b2@internet-e-mail.com
Maintainer: Etienne H
Maintainer-email: django_backblaze_b2@internet-e-mail.com
Requires-Python: >=3.6.1,<4.0.0
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Web Environment
Classifier: Framework :: Django
Classifier: Framework :: Django :: 3.0
Classifier: Framework :: Django :: 3.1
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Dist: b2sdk (>=1.3.0)
Requires-Dist: django (>=3.0)
Project-URL: Repository, https://github.com/ehossack/django-backblaze-b2/
Description-Content-Type: text/markdown

# django-backblaze-b2

[![pypi version](https://img.shields.io/pypi/v/django-backblaze-b2)](https://pypi.org/project/django-backblaze-b2/)
[![python version](https://img.shields.io/pypi/pyversions/django-backblaze-b2)](https://pypi.org/project/django-backblaze-b2/)
[![django version](https://img.shields.io/pypi/djversions/django-backblaze-b2)](https://pypi.org/project/django-backblaze-b2/)

A storage backend for Django that uses [Backblaze's B2 APIs](https://www.backblaze.com/b2/cloud-storage.html).

Implementation wraps [Official Python SDK](https://github.com/Backblaze/b2-sdk-python)

## How to use

1. Install from this repo, or install from PyPi: `pip install django-backblaze-b2`
As tested, requires python 3.6 or greater but solely due to type annotations. PRs welcome :)
1. Configure your django `settings`. The absolute minimum config would be:
```python
BACKBLAZE_CONFIG = {
    "application_key_id": os.getenv("BACKBLAZE_KEY_ID"), # however you want to securely retrieve these values
    "application_key": os.getenv("BACKBLAZE_KEY"),
}
```

Theoretically you may now refer to the base storage class as a storage class.  
e.g.
```python
from django_backblaze_b2 import BackblazeB2Storage

class MyModel(models.Model):
    fileField = models.FileField(
        upload_to="uploads",
        storage=BackblazeB2Storage
    )
```
### Caching

Because the SDK will authorize/request with the b2 server to retrieve file info, the library caches these account information lookups.  
By default, the `accountInfo` configuration uses a cache by the name of `django-backblaze-b2` which you must have in your `CACHES` section of your `settings.py`. This is the recommended caching implementation as it leverages the django framework and with that comes thread-safety. You can then use whichever cache implementation you want. It is not recommended to cache with the `default` django cache, as the `clear()` method may be called during the backblaze lifecycle.  
If you do not wish to use this, you can use a sqlite database on disk for caching, or use a non-thread-safe in-memory implementation. This is only recommended for single-threaded deployments. (remember in most deployments a new thread serves each request).
### Public/Logged-In/Private storage

1. Add `django_backblaze_b2` to your `INSTALLED_APPS`
1. Add the urls to your `urlpatterns` in the root `urls.py`:
```python
    urlpatterns = [
        ...
        path('', include('django_backblaze_b2.urls')),
    ]
```

### Configurations

You may want to use your own bucket name, or set further configuration such as lazy authorization/validation, or specifying file metadata.  
Refer to [the options](./django_backblaze_b2/options.py) for all options.  
You can modify the settings dict, but additionally override any setting with the `opts` keyword argument to the storage classes.

To specify different buckets to use for your public, logged-in, staff storage, you can set the 
`specificBucketNames` attribute of the settings dict.
## Why

There are several Django storage packages out there already which support B2, but none met my needs. These are:

* [django-storages](https://github.com/jschneier/django-storages)
    * Large community engagement ✅
    * Well-tested ✅
    * [Second-class support](https://github.com/jschneier/django-storages/issues/765) via [Apache Libcloud](https://github.com/apache/libcloud) ❌
    * Disconnect in configuration and actual use ❌
    * PR list with low turnaround ❌
* [django-b2](https://github.com/pyutil/django-b2)
    * Similar aim to this project, around official backblaze SDK ✅
    * Mixed goals (storage, scripts) ❌
    * Tests?? ❌
* [django-backblazeb2-storage](https://github.com/royendgel/django-backblazeb2-storage)
    * Simple configuration ✅
    * Not based around python SDK (potentially harder to keep up with version changes) ❌
    * Tests?? ❌

### S3 Compatible API

Backblazed can be used with an [S3-compatible API](https://www.backblaze.com/b2/docs/s3_compatible_api.html)
This is great, but most packages use an older version of the S3 Api (v2). Backblaze uses v4.

### What this package offers

* Type Annotations
* Tested
* No hacks required to get up and running around API deficiencies (any hacks are not exposed in API)
* Support for public/private files, restricted via Django user permissions

## How it works

* A simple implementation of the `django.core.files.storage.Storage` class provides handling for storage behaviour within your Django application
* Three url routes are appended to the root of your application:  
    1. `/b2/`
    2. `/b2l/`
    3. `/b2s/`
These routes act as a proxy/intermediary between the requester and backblaze b2 apis. The public `/b2/` allows exposing files from a private bucket, and the logged-in and staff routes will perform the known validations of a django app to prevent unauthorized access.

### Gotchas

* The original filename + any upload paths is stored in the database. Thus your column name must be of sufficient length to hold that (unchanged behaviour from `FileSystemStorage`)
*  When retrieving files from the `PublicStorage`, `LoggedInStorage` or `StaffStorage`, you may not override the `"bucket"` or authorization options, or else when the app proxies the file download, it will be unable to retrieve the file from the respective bucket.
* Simply using `LoggedInStorage` or `StaffStorage` is not enough to protect your files if your bucket is not public. If any individual gains access to the file ids/urls for these files, there is no authentication around them. It is up to the implementer to ensure the security of their application.
* Once the file is uploaded, and someone obtains a file url (e.g. http://djangodomain.com/b2l/uploads/image.png), the model will no longer be checked for the file. This means that if you share the bucket between multiple use-cases, you could in theory find finds that don't belong to your django app, or similarly if you delete/change your models, the files could still be downloaded. Consider using an app like [django-cleanup](https://github.com/un1t/django-cleanup) if this is important to you

## Contributing

Contributions welcome!

* Please ensure test coverage does not decrease in a meaningful way.
* Ensure formatting is compliant (`make lint`)
* Use [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/)

## Setting up for development

### Requires

* python
* pyenv - align local version
* GNU Make
* (optional) docker - run sample app

#### Version compatibility reminder

| Ver  | Status   |  EOL       |
| ---- | -------- | ---------- |
| 3.9  | bugfix   | 2025-10    |
| 3.8  | bugfix   | 2024-10    |
| 3.7  | security | 2023-06-27 |
| 3.6  | security | 2021-12-23 |

### Running

1. `make setup`

* You can run django with `make run-django` to test django app.
* You can run tests with `make test`
* You can view test coverage with `make test-coverage`, then see in the terminal, 
open `test/htmlcov/index.html`
or use `cov.xml` in your favourite IDE like VSCode

### Releasing

1. `make publish-to-pypi`

### Cleanup

1. `make cleanup`

