ale*_*ayr 9 python werkzeug flask
开始学习Python和Flask作为学习练习,来自PHP/Symfony2,我可以在表单中添加一个隐藏的_method字段,用DELETE或PUT覆盖POST方法.
似乎Flask本身并不支持这种做法,而且我一直在讨论包括http://flask.pocoo.org/snippets/38/在内的各种想法,这些想法有效,但涉及将覆盖放在表单动作中,而不是而不是作为隐藏字段,IMO使URL看起来不雅观.
上述地址的注释中有一个片段,它使_method从路由角度工作,但正如在那里讨论的那样,如果您尝试访问视图中的request.form,则会导致请求挂起.
有人有解决方法吗?如果没有,我会把所有的东西都当作POST来处理,但能够找到一种让它工作的方法会很好.
干杯.
编辑:这是任何想要看一看的人的代码:
模板:
<form action="{{ url_for('login') }}" method="POST">
<input type="hidden" name="_method" value="PUT">
<input class="span12" name="email" type="text" placeholder="E-mail address" value="{{ email }}">
<input class="span12" name="password" type="password" placeholder="Your password">
<a href="{{ url_for('reset_password') }}" class="forgot">Forgot password?</a>
<div class="remember">
<input id="remember-me" type="checkbox">
<label for="remember-me">Remember me</label>
</div>
<input class="btn-glow primary login" type="submit" name="submit" value="Log in">
</form>
Run Code Online (Sandbox Code Playgroud)
应用程序/ __ init__.py
from flask import Flask
from werkzeug.wrappers import Request
class MethodRewriteMiddleware(object):
def __init__(self, app, input_name='_method'):
self.app = app
self.input_name = input_name
def __call__(self, environ, start_response):
request = Request(environ)
if self.input_name in request.form:
method = request.form[self.input_name].upper()
if method in ['GET', 'POST', 'PUT', 'DELETE']:
environ['REQUEST_METHOD'] = method
return self.app(environ, start_response)
app = Flask(__name__)
app.wsgi_app = MethodRewriteMiddleware(app.wsgi_app)
from app import views
Run Code Online (Sandbox Code Playgroud)
视图:
from flask import render_template
@app.route('/user/login', methods=['GET','POST','PUT'])
def login():
emailvalue = 'test@test.com'
if request.method == 'PUT':
emailvalue = request.form['email']
return render_template('login.html', email=emailvalue)
Run Code Online (Sandbox Code Playgroud)
正如您已经指出的那样,您的中间件使后者为request.form空。这是因为request.form正在从类似文件的对象中读取。引用PEP 333:
wsgi.input —— 一个输入流(类文件对象),可以从中读取 HTTP 请求正文。(服务器或网关可以根据应用程序的请求按需执行读取,或者它可以预读客户端的请求主体并将其缓冲在内存或磁盘上,或者使用任何其他技术来提供这样的输入流,根据其偏好。)
请注意,这一段并没有告诉我们这个“类文件对象”是否提供了将指针重置到文件开头的任何可能性。事实上,如果我们尝试以下应用程序:
from werkzeug.serving import run_simple
def app(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/plain')])
yield str(dir(environ['wsgi.input']))
run_simple('localhost', 5000, app)
Run Code Online (Sandbox Code Playgroud)
它没有显示此文件对象具有seek方法的任何索引。
因此,您可以做的是将所有内容读入一个名为 的字节串data,并替换wsgi.input为BytesIO(data),它确实有seek一个可以使用的方法。这样做会带来几个缺点,最明显的是,所有上传的数据在传递给应用程序之前都必须完全读入内存。可能还有一些我自己不知道的危险边缘情况,这就是为什么我绝不会冒险在实际应用程序中尝试以下操作:
from werkzeug.formparser import parse_form_data
from werkzeug.wsgi import get_input_stream
from io import BytesIO
class MethodMiddleware(object):
"""Don't actually do this. The disadvantages are not worth it."""
def __init__(self, app):
self.app = app
def __call__(self, environ, start_response):
if environ['REQUEST_METHOD'].upper() == 'POST':
environ['wsgi.input'] = stream = \
BytesIO(get_input_stream(environ).read())
formdata = parse_form_data(environ)[1]
stream.seek(0)
method = formdata.get('_method', '').upper()
if method in ('GET', 'POST', 'PUT', 'DELETE'):
environ['REQUEST_METHOD'] = method
return self.app(environ, start_response)
Run Code Online (Sandbox Code Playgroud)