Reputation: 1360
The django-file-resubmit module (file widgets.py) makes this import:
from django.forms import ClearableFileInput
and then it defines class based on ClearableFileInput:
class ResubmitBaseWidget(ClearableFileInput):
# ...some code
I try to use the module with different base class and it works well. But I have to patch the import command in module code. (DBAdminClearableFileInput is inherited from django.forms.ClearableFileInput in an other 3rd party module):
from db_file_storage.form_widgets import DBAdminClearableFileInput as ClearableFileInput
My question is: Could the code of django-file-resubmit module be rewritten more clever, so it could be used with DBAdminClearableFileInput as parameter?
Note: I'm not sure if this is not duplicate question. However I think here are special problems of modules design and a question if some Pull Request could be made or what is the best approach how to use both modules without changing them.
Upvotes: 0
Views: 68
Reputation: 6190
It sounds like what you might really want is co-operative multiple inheritance. E.g. You want to have
class MyFileInput(DBAdminClearableFileInput, ResubmitBaseWidget):
pass
For that to work, both DBAdminClearableFileInput
and ResubmitBaseWidget
would need to be written with co-operative multiple inheritance in mind. It may not even be (theoretically) possible depending on how the end-state behaviour has to look. E.g. if DBAdminClearableFileInput
wants to render the widget as <foo>
and ResubmitBaseWidget
wants to render the widget as <bar>
, one of them has to 'win' (in the absence of additional code you might write yourself in MyFileInput
.
It's possible (though probably unlikely) that multiple inheritance will 'just work', depending on what methods etc both those classes override and whether they make they already make the correct calls to super()
.
It's probably worth a try at least, in the worst case scenario you can add some 'glue' to your MyFileInput
class to make it work.
Here's a trite example
class Elephant: # Represents ClearableFileInput
def colour(self):
return "Grey"
class BrownElephant(Elephant): # Represents ResubmitBaseWidget
def colour(self):
return "Brown"
class PinkElephant(Elephant): # Represents DBAdminClearableFileInput
def colour(self):
return "Pink"
Now, at the moment, these classes do not cooperate, and so if you do multiple inheritance, you get:
class BrownAndPinkElephant(BrownElephant, PinkElephant):
pass
nelly = BrownAndPinkElephant()
print(nelly.colour())
Will print "Brown", since the Method Resolution Order starts with BrownElephant
, which returns "Brown" without ever calling super().colour()
, and so Pink and 'default' Elephant's methods are never even called.
You could 'fix' this in a very limited (but might be enough for your purposes) with a hacky 'glue' method like this:
class BrownAndPinkElephant(BrownElephant, PinkElephant):
def colour(self):
colours = [
BrownElephant.colour(self),
PinkElephant.colour(self),
]
return " and ".join(colours)
nelly = BrownAndPinkElephant()
print(nelly.colour())
Now the printed output is "Brown and Pink", which is more sensible (at least within the context of this example!). Hopefully you can see that you attempt to implement similar things for a subclass of DBAdminClearableFileInput
, ResubmitBaseWidget
to give you control over what aspects of each class end up being used in the final class.
It's worth saying, there are an awful lot of pitfalls with this approach and I wouldn't recommend it for anything 'serious'. However, when you have 2 classes with a common base class, that you want to combine, and you don't control the source code of either, then this may be a possible solution.
Upvotes: 1