Why are we passing flask.views.MethodView in the class?
app.add_url_rule > in this snippet, add_url_rule is this something predefined property?
Similarly view_func, View.as_view > are they predefined?
import flask, flask.views
app = flask.Flask(__name__)
class View(flask.views.MethodView):
def get(self):
return "Hello World!"
app.add_url_rule('/',view_func=View.as_view('main'))
app.debug = True
app.run()
View is a subclass of the flask.views.MethodView class. The latter provides base functionality, like the as_view() method:
Converts the class into an actual view function that can be used with the routing system. Internally this generates a function on the fly which will instantiate the View on each request and call the dispatch_request() method on it.
Also see Pluggable Views.
Because this is not a function-based view, you cannot use the #app.route() decorator on it. You use the alternative app.add_url_rule() method instead in that case:
Connects a URL rule. Works exactly like the route() decorator. If a view_func is provided it will be registered with the endpoint.
view_func is a documented keyword argument for this method; when the registered path is requested (in your example /), then whatever as_view() returned is called by Flask. That in turn calls dispatch_request(), which then calls the View().get() method if the HTTP request used a GET method.
Related
When is decorator in Flask's route method executed? Specifically, I want to know when self.add_url_rule() is executed.
from flask import Flask
app = Flask(__name__)
#app.route("/")
def root_of_app():
load_root_of_app()
Is add_url_rule executed when the module containing root_of_app is first imported, or when root_of_app is first called by a web request?
Here is the source for the route function:
def route(self, rule, **options):
def decorator(f):
endpoint = options.pop('endpoint', None)
self.add_url_rule(rule, endpoint, f, **options)
return f
return decorator
You can verify this yourself by adding print statements to the route decorator.
When route is called, it builds a decorator. That decorator is then applied to the view by calling it. Both these happen at import, because importing executes module-level code.
Using #app.route() registers the view, it is not deferred until the first request. The blueprint version of route is deferred until the blueprint is registered on the app, which also happens before the first request.
I'm need opportunity to add http-header(X-Accel-Expires) for each add_view.
And for add_static_view.
Ideally would be pass parameter, something like add_view(..., x_accel_expires=100), add_static_view(..., x_accel_expires=100), but the pyramid can't this.
I can do Base View, where add http-header X-Accel-Expires.
I will only need to add an attribute in each view, something like: add_headers = (('X-Accel-Expires', '100'),).
But how can add this header for add_static_view?
For the case of add_view you can use the decorator argument as documented by view configuration parameters:
A dotted Python name to a function (or the function itself) which will be used to decorate the registered view callable. The decorator function will be called with the view callable as a single argument. The view callable it is passed will accept (context, request). The decorator must return a replacement view callable which also accepts (context, request). The decorator may also be an iterable of decorators, in which case they will be applied one after the other to the view, in reverse order.
This is the example given in the documentation:
#view_config(..., decorator=(decorator2, decorator1))
def myview(request):
pass
Is similar to doing:
#view_config(...)
#decorator2
#decorator1
def myview(request):
pass
This would allow you to write the following for example:
def accel_headers_factory(expires=100):
def add_accel_headers(view):
def wrapped_view(context, request):
resp = view(context, request)
resp.headers.append(('X-Accel-Expires', expires))
return wrapped_view
return add_accel_headers
Then use:
#view_config(..., decorator=(accel_headers_factory(500),))
def myview(request):
return {}
This would then always add the X-Accel-Expires header to the response as returned from the view.
Unfortunately it doesn't look like add_static_view allows you to pass it a decorator argument.
While trying the new CORS feature on flask-restful, I found out that the decorator can be only applied if the function returns a string.
For example, modifying the Quickstart example:
class HelloWorld(restful.Resource):
#cors.crossdomain(origin='*')
def get(self):
return {'hello': 'world'}
Throws:
TypeError: 'dict' object is not callable
Am I doing something wrong?
I recently came across this issue myself. #MartijnPieters is correct, decorators can't be called on single methods of the view.
I created an abstract base class that contained the decorator list. The class that consumes Resource (from flask-restful) also inherits the base class, which is the class actually applying the decorator list to the view.
class AbstractAPI():
decorators = [cors.crossdomain(origin='*')]
class HelloWorld(restful.Resource, AbstractAPI):
#content
nope.
just add the decorator list to the parameters after you create the Api instance
api = Api(app)
api.decorators=[cors.crossdomain(origin='*')]
The return value of the wrapped function is passed (as one argument) to flask.make_response(); anything that a normal Flask view can return is acceptable. The decorator is essentially the same as this Flask snippet.
Because the Flask-restful Resource is a subclass of flask.views.MethodView you should really not put decorators directly on the methods here. As documented in Decorating Views you should list view decorators in a special class attribute, decorators which is a list:
class HelloWorld(restful.Resource):
decorators = [cors.crossdomain(origin='*')]
def get(self):
return {'hello': 'world'}
and Flask will apply the view to the actual view method returned by HelloWorld.as_view(), which is what Flask actually calls when dispatching the route to the view.
Applying them directly to the methods will only server to confuse the restful.Resource dispatcher as it is expecting methods to return python datastructures suitable for encoding to JSON, which is not what cors.crossdomain() returns anyway.
I found that you can still use the decorator provided you return a string or JSON response (which is probably good practice for an API anyway). This is important if you want to do route-specific CORS headers, using the decorator makes life much easier. See this merged pull req for more information: https://github.com/flask-restful/flask-restful/pull/131
Here's an example:
from . import app
from flask_restful import reqparse, abort, Api, Resource
from flask.ext.cors import cross_origin
from datetime import datetime
from flask import jsonify
api = Api(app)
class DateTime(Resource):
#cross_origin(origins="http://localhost:63342*")
def get(self):
return jsonify({'DateTime': str(datetime.today())})
api_root = '/api/v1/'
api.add_resource(DateTime, api_root + 'DateTime')
If you're using flask-security, adding auth decorators had some weird behavior in my testing. I recommend assert current_user.is_authenticated instead. If you are allowing credentials, make sure to CSRF protect.
I am using django class based view
class MyView(TemplateView):
def return_JSON(self, object_id):
parent = models.UserForm.objects.get(pk=object_id)
url(r'^return/(?P<object_id>\d+)/json/', views.MyView().return_JSON, name="return_json")
I get this error
return_JSON() got multiple values for keyword argument 'object_id'
You're doing something very odd here.
You're using CBVs, but passing a function as the view function. Remember, the normal signature for CBVs is to pass in MyCBV.as_view(). No CBV machinery runs without running it through as_view() or dispatch().
But if you insist, you just need to add a new argument to your function...
def return_JSON(self, request, object_id):
# ^^^^^^^ this
return http.HttpResponse("Foo!")
i have a decorator named "auth"
def auth(check_func=validate_login):
def decorator(view):
def wrapper(*args, **kwargs):
auth = check_func()
if auth:
return view(*args, **kwargs)
return bottle.redirect('/login.html')
return wrapper
return decorator
the auth decorator is used like this
#get('/')
#view("someview")
#auth()
def handler():
#myhandlercode
so the auth decorator calls the view function which renders my template in bottle.py.
But now i want to return json instead of rendering a view. So what changes do i have to make to the auth decorator code to make this happen? I am confused as to how to call the handler instead of the view from the auth code.
EDIT 1 : Bottle allows you to return dict, it directly converts it to json. And i dont want to use the view at all, i just want to return json to the user from my handlers. So should i just remove the #view decorator? and what should i call instead in the auth decorator?
Bottle route decorators are able to apply decorators to you without destroy auto json feature.
#get('/', apply=[auth])
def handler():
...
If you don't want a view, just remove your #view decorator, Bottle handle dicts gracefully, converting it to a JSON answer.
I dont believe its right to have auth shoehorning in json dumping.
Here's an example with plain ol python of using decorators
def validate():
return True
def auth(valid=validate):
def _auth(f):
def _auth_wrap():
if not valid():
raise Exception('redirect')
return f()
return _auth_wrap
return _auth
def view(tmpl):
def _view(f):
def _view_wrap():
return tmpl.format(f())
return _view_wrap
return _view
#view('Hello, {0}')
#auth()
def handler():
return 'World'
handler
# outputs: __main__._view_wrap
handler()
# outputs: 'Hello, World'
and also the line
return tmpl.format(f())
The f func is __main__._auth_wrap which is calling validate and returning the executed handler.
so then you would handle dumping json by doing something else besides tmpl.format in the above, such as calling a seperate method and passing needed info, or shoehorning into view decorator, which either way will be more appropriate.
So to answer the end question a little better, if you want to dynamically decide whether or not to dump json based on the request and bottle.py's view func doesn't support this, then you could make a view wrapper similar to the above that does the checks on the request object or whatever you want to use to determine json output, and then either call bottle.py's view or json.dumps on f() within _view_wrap
If you want to make a func always dump json, then delete the view decorator and create a json decorator similar to the view decorator above that will return json.dumps(f())
The main point here is to keep auth doing what it's name implies.
You are returning Json (or rather a python dictionary) from your view, right? In that case you don't have to change anything in the decorator. That which the view returns is not immediately forwarded to the user's browser, it is first processed by bottle then returned to the user. When you return a dictionary from the view it is treated as Json, when returning a template string it is treated as Html.