diff --git a/example/app.py b/example/app.py index 27a6edd6..f1f5c3e0 100644 --- a/example/app.py +++ b/example/app.py @@ -6,7 +6,7 @@ from flask.ext.mongorest.views import ResourceView from flask.ext.mongorest.resources import Resource from flask.ext.mongorest import operators as ops -from flask.ext.mongorest.methods import * +from flask.ext.mongorest.methods import Create, Update, Fetch, List, Delete, BulkUpdate from flask.ext.mongorest.authentication import AuthenticationBase from example import schemas, documents @@ -27,8 +27,8 @@ }, ) -db = MongoEngine(app) -api = MongoRest(app) +db = MongoEngine() +api = MongoRest() class UserResource(Resource): document = documents.User @@ -304,6 +304,8 @@ class DictDocView(ResourceView): resource = DictDocResource methods = [Fetch, List, Create, Update] +db.init_app(app) +api.init_app(app) if __name__ == "__main__": port = int(os.environ.get('PORT', 8000)) diff --git a/flask_mongorest/__init__.py b/flask_mongorest/__init__.py index c1648057..b7ed1a7e 100644 --- a/flask_mongorest/__init__.py +++ b/flask_mongorest/__init__.py @@ -1,17 +1,61 @@ from flask import Blueprint from flask_mongorest.methods import Create, BulkUpdate, List +class _DelayedApp(object): + """ + Stores URL rules for later merging with application URL map. + + """ + + def __init__(self): + self.url_rules = [] + + def add_url_rule(self, *args, **kwargs): + self.url_rules.append((args, kwargs)) + class MongoRest(object): - def __init__(self, app, **kwargs): - self.app = app + def __init__(self, app=None, template_folder='templates', **kwargs): + """ + Takes optional Flask application instance. If supplied, `init_app` will be + called to update application url map. + + """ + self.url_prefix = kwargs.pop('url_prefix', '') - app.register_blueprint(Blueprint(self.url_prefix, __name__, template_folder='templates')) + self.template_folder = template_folder + if app is not None: + self.init_app(app, **kwargs) + else: + self.app = _DelayedApp() + + def init_app(self, app): + """ + Provides delayed application instance initialization to support + Flask application factory pattern. For further details on application + factories see: + + http://flask.pocoo.org/docs/dev/patterns/appfactories/ + + and + + http://mattupstate.com/python/2013/06/26/how-i-structure-my-flask-applications.html + """ + + app.register_blueprint( + Blueprint(self.url_prefix, __name__, template_folder=self.template_folder)) + + if hasattr(self, 'app') and isinstance(self.app, _DelayedApp): + for args, kwargs in self.app.url_rules: + app.add_url_rule(*args, **kwargs) + + self.app = app def register(self, **kwargs): def decorator(klass): - # Construct a url based on a 'name' kwarg with a fallback to a Mongo document's name + # Construct a url based on a 'name' kwarg with a fallback to a + # Mongo document's name document_name = klass.resource.document.__name__.lower() name = kwargs.pop('name', document_name) url = kwargs.pop('url', '/%s/' % document_name) @@ -24,11 +68,16 @@ def decorator(klass): pk_type = kwargs.pop('pk_type', 'string') view_func = klass.as_view(name) if List in klass.methods: - self.app.add_url_rule(url, defaults={'pk': None}, view_func=view_func, methods=[List.method], **kwargs) + self.app.add_url_rule( + url, defaults={'pk': None}, view_func=view_func, methods=[List.method], **kwargs) if Create in klass.methods or BulkUpdate in klass.methods: - self.app.add_url_rule(url, view_func=view_func, methods=[x.method for x in klass.methods if x in (Create, BulkUpdate)], **kwargs) - self.app.add_url_rule('%s<%s:%s>/' % (url, pk_type, 'pk'), view_func=view_func, methods=[x.method for x in klass.methods if x not in (List, BulkUpdate)], **kwargs) + methods = [x.method for x in klass.methods if x in (Create, BulkUpdate)] + self.app.add_url_rule(url, view_func=view_func, methods=methods, **kwargs) + + methods = [x.method for x in klass.methods if x not in (List, BulkUpdate)] + self.app.add_url_rule( + '%s<%s:%s>/' % (url, pk_type, 'pk'), view_func=view_func, methods=methods, **kwargs) + return klass return decorator -