I would like to minimally document that, in order to officially make it available to third-party package maintainers.
Packages need to provide storage instances, and in order to opt-in to the new storages API need to be able to allow users to provide a storage for a known alias (the name of which is most easily given by a setting). If the user provides such a storage that should be used, otherwise the third-party package should provide a default.
That would look something like this:
alias = # From e.g. settings
storage_class = # Default class to use if not overridden.
try:
# Did the user provide the alias?
return storages[alias]
except InvalidStorageError:
# Update storages to provide a default.
storages.backends[alias] = {
"BACKEND": storage_class
}
return storages[alias]
This works perfectly, but, in order to be safe, the backends dict should be documented.
The create_storage() method is also useful, and should be made available.
FWIW this comes up Updating django-compressor to use the new API but the same would be necessary for any third-party package wanting to allow users to use the storages API in order to provide optional configuration overrides.
I am not so hot on encouraging the pattern of inserting backends into the handler class. Why canāt the package require users to define the key in STORAGES? That seems more transparent to me, and more aligned with the other āhandlersā (caches / databases).
Thatās a good question. The answer is that 99% of users are never going to customise the storage here, theyāre just going to use the default. So itās adding a quite a big extra boilerplatey-horrible-pointlessness to make them add the STORAGES entry.
The pattern we want is āDid they override?ā If so use, otherwise provide the default. We could not add the storage to storages but then next call we canāt easily re-use the instance.
Adding it to the backends dict, and then accessing it works just nicely and resolves all these issues.
Iām still open to another way of letting folks opt-in to the storages API with third-party packages providing the default, if there are any (but this have been bubbling on the compressor repo since 4.2, and this is the least touch solution thatās presented so far).
All I really want with the PR here is the stability guarantee that we can use the StorageHandler as implemented without a non-deprecation path breaking change. (i.e. We could just mention backends and not have the example, for example.)
Update: FWIW I was thinking about an alternate for compressor not updating backends, for which weād need to instantiate a storage ourselves. That would work, but weād loose the caching. For that though weād need the create_storage() method, or weād have to vendor that, with the complications on keeping it up to date that that would entail, so it would still be better to have it part of Djangoās public API.
As an extra data point, Iāve helped a couple of people on separate projects, who hit the underlying issue here, and needed the StorageHandler API. (I asked both to comment here, but that hasnāt happened )
Hey @carltongibson, I have been following along this thread and thinking about it.
Iām currently in that awkward place where the proposed solution does not feel ārightā but I donāt have a better counterproposal to offer, so I feel somehow blocked.
There are a few storage-related improvements pending, such as revisiting the API which is a bit confusing at times, specifically the file name and file path validation. Perhaps we could plan for brainstorm session to consider an API change that would most āofficiallyā support this requirement?
Hey @nessitaā¦ Yes, the storages API. Thatās a bigger discussion We can chat at DjangoCon (though I canāt promise I have any great thoughts on itā¦ ā youāre well ahead of me, having been in there recently.)
As I read @adamchainzās reply he was +1 but with the query about the example. So, the question isā¦
i.e. We could just mention backends and not have the example, for example.
Iām totally happy to drop the example if itās a bit shifty
@adamchainz also wanted to document django.db.connections ā Iād be +1 for that, but it seems like a separate Ticket and PR.