New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PRE / POST hooks #627
base: master
Are you sure you want to change the base?
PRE / POST hooks #627
Conversation
from django.core.files.base import File | ||
from django.core.files.storage import Storage | ||
|
||
class BaseFile(File): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the purpose of BaseFile
if it provides no hooks?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jdufresne It doesn't provide hooks at this moment as this is just a skeleton proposal, but it will certainly have hooks if we agree that this is a good approach.
@@ -37,7 +37,7 @@ | |||
|
|||
|
|||
@deconstructible | |||
class S3Boto3StorageFile(File): | |||
class S3Boto3StorageFile(BaseFile): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the plan to do this for all backends?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. This should be transparent and shouldn't create any bugs, as the Base*
classes are just proxies.
@@ -469,6 +469,7 @@ def _open(self, name, mode='rb'): | |||
return f | |||
|
|||
def _save(self, name, content): | |||
name, content = self.pre_save(name, content) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As pre_save
is the very first line of the method, I don't see the need for this at all. Couldn't a backend do the following?
class MyS3Boto3Storage(S3Boto3Storage):
def _save(self, name, content):
name, content = self.do_my_special_thing()
return super()._save(name, conent)
This is just as flexible, requires no special hooks and is compatible with recent releases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The entire idea of a hook in a library is to provide a way in which developers can run their own code in a guaranteed-to-be-stable way. This means that your proposal of directly subclassing the backends is not feasible, as there is no guarantee that the code in that method won't change (and break the subclass-patch).
@jdufresne Are we good on this proposal? Do you have any objections? Should I keep working on this approach? |
I'm fine with the proposal. I think one could add functionality in this way to a subclass today, but if the stable API helps with documentation and ensures long term compatibility, that makes sense. |
@jdufresne Great news! So let's move on with this :) I have a few questions:
|
ping @jdufresne |
1 similar comment
ping @jdufresne |
If we're going to add the feature to one backend, might as well make it universal and document it as such. IMO, the backends should behavior similarly to one another when possible. |
@jdufresne You misunderstood my third question (and didn't reply to the first two!). Can you re-read, please? |
|
What's the current status? |
@withthelemons I have been extremely busy the last couple of months, but I do plan on continuing the work on this shortly. |
The idea of this proposal is to allow developers to hook their own actions into some of the methods (
read
andwrite
for example).The way I think this could be achieved without making huge changes to the code is by using
django-storages
s current OOP design. Currently all backend storages implement Django's
Storage` class.This proposal creates a dummy proxy class that implements the hooks that could be used by developers.
The code as-it-is now implements only
pre_save
, which receivesname, content
and returnsname, content
without modifying them in any way. This allows the code to work as expected by default ifpre_save
isn't overwritten.If a developer chooses to override the behaviour of a particular hook, it would be as simple as overriding only that particular method. As an example, I'll show how to override the
pre_save
method and convert all uploaded files tobase64
:First, create a new class, anywhere in your app/project:
Then set the default storage to that class: