Reputation: 10850
I'm using Flask-Classy to write a Flask app using class based views.
My base class is called SlugView. It catches URLs like example.com/124/catchy-article-name
:
class SlugView(FlaskView):
@route('/<id>')
@route('/<id>/<slug>')
def get(self, id, slug=None)
raise NotImplementedError
My second class is called ArticleView:
class ArticleView(SlugView):
def get(self, id, slug=None):
return render_template('article.html', article=get_article_by_id(id))
What decorator magic can I use to have the subclassed function inherit the same decorators as the parent class?
Upvotes: 0
Views: 319
Reputation: 159895
Magic? Yes. Decorator magic? No. Do you object to metaclass magic?
class InheritableRoutesMeta(type):
def __new__(cls, cls_name, bases, attributes):
for name, value in attributes.items():
if not callable(value):
continue
for base in bases:
super_method = getattr(base, name)
if super_method and hasattr(super_method, "_rule_cache"):
value._rule_cache = super_method._rule_cache
break
return super(InheritableRoutesMeta, cls).__new__(cls, cls_name,
bases, attributes)
Then you should be able to do something like this:
class ArticleView(SlugView, metaclass=InheritableRoutesMeta):
# Use the keyword argument metaclass for Python 3
# For Python 2, remove the argument and uncomment the below
# __metaclass__ = InheritableRoutesMeta
def get(self, id, slug=None):
return render_template('article.html', article=get_article_by_id(id))
Warning: This is based on an internal property. If Flask-Classy
chooses to change how it stores these decorators the above code will break (assuming that it works in the first place). If you really need this, it is worth filing an issue with the creator(s) to either make this property part of the public API or to provide another way of doing what you are doing. They may choose not to do either, but at least then they are aware of the use case.
Upvotes: 1