2013-06-21 13 views
9

Öğrenme alıştırması olarak Python ve Flask toplamaya başladı ve PHP/Symfony2'den geliyordu, POST yöntemini bir DELETE ile geçersiz kılmak için gizli bir _method alanı ekleyebilirim. KOYMAK.Flask'ta gizli alan _method kullanılarak istek yöntemi değiştirme

Flask bunu yerel olarak desteklemiyor gibi gözüküyor ve http://flask.pocoo.org/snippets/38/ da dahil olmak üzere çeşitli fikirlerle uğraşıyor, ancak IMO'nun yaptığı gizli alan yerine form eylemine geçersiz kılmayı içeriyor URL çirkin görünüyor.

Yukarıdaki adresin yorumlarında, bir yönlendirme perspektifinden _method işini yapan bir pasaj var, ancak orada da tartışıldığı gibi, isteklere erişmek için istekte bulunun. .

Bunun için bir çözüm var mı? Değilse, ben sadece her şeyi POST olarak ele alacağım, ama işe almak için bir yol bulabilmek güzel olurdu.

Şerefe.


DÜZENLEME:

Şablon:

<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> 

uygulama/__ 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 

Görünüm İşte bakmak isteyen herkes için kod:

from flask import render_template 
@app.route('/user/login', methods=['GET','POST','PUT']) 
def login(): 
    emailvalue = '[email protected]' 
    if request.method == 'PUT': 
     emailvalue = request.form['email'] 
    return render_template('login.html', email=emailvalue) 
+0

[request.form] (http: Muhtemelen ben asla gerçek uygulamasında aşağıdaki çalışırken riski neden olan kendim bilmiyorum ayrıca bazı tehlikeli kenar vakası vardır // flask.pocoo.org/docs/quickstart/#the-request-object) bazı kullanımlarınız olabilir. – John

+0

Merhaba @johnthexiii, yorumunuz için teşekkürler. Ben gerçekten _method ayarlanmış olup olmadığını kontrol etmek için request.form kullanıyorum, ancak bunu yaptığınızda ve middleware içinde REQUEST_METHOD değiştirdikten sonra, request.form görünümlerine erişemiyorum (uygulama sadece kilitleniyor). Bu, denediğim öneri ile bir bağlantıdır: http://flask.pocoo.org/snippets/38/#comment-box (ikinci yorum) – aleayr

+0

Bazı kodları neyin daha iyi bir genel görünümü vermek için koydum Başarmaya çalışıyorum. – aleayr

cevap

4

, senin katman request.form sonra boş hale getirir. Bunun nedeni, request.form dosya benzeri bir nesneden okuyor olmasıdır. PEP 333 alıntı:

wsgi.input - HTTP isteği gövdesi okunabilir olan bir giriş akışı (dosya benzeri nesne). (Sunucu veya ağ geçidi, uygulama tarafından talep edildiğinde istek üzerine istekleri okuyabilir veya istemcinin istek gövdesini önceden okuyup belleğe veya diske yedekleyebilir veya böyle bir giriş akışı sağlamak için başka herhangi bir teknik kullanabilir. tercih edilir.)

Bu paragrafın, "dosya benzeri nesne" işaretçisini dosyanın başlangıcına sıfırlama olasılığını sağlayıp sağlayamayacağını bize bildirmediğini unutmayın. Aslında, biz şu uygulama denerseniz:

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) 

Bu dosya nesnesi seek yöntemi olan herhangi indeksleri göstermez.

Yani, neler yapabileceğinidata adında bir bytestring içine her şeyi okunur ve bir kullanabileceği bir seek yöntemi var ki, BytesIO(data) ile wsgi.input değiştirin.Bunu yapmak, ile bir takım dezavantajları beraberinde getirmektedir; en belirgin olanı, yüklenen tüm verilerin, uygulamaya aktarılmadan önce belleğe tamamen okunması garantilidir.

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) 
+0

Teşekkürler Markus, durum böyle görünüyor. Django'nun kendisi de desteklemiyor gibi görünüyor. TastyPie (bir _method kullanmadan, ancak bir üstbilgi geçersiz kılma kullanarak değil) yapar, ancak formlar için uyarlanmış olabilir. Bu nedenle, formlardan yazıyı kullanıyorum ve Flask görünümünde PUT/POST/DELETE mantığını yapıyorum. Yönlendirme dekoratörünü kullanabilme kadar zarif değil, ama yapmak zorunda olacak. Girişiniz için teşekkürler. – aleayr

1

MethodView'u flask.views'dan kullanabilir ve doğru yöntemlere gönderebilirsiniz. Bunu göstermek için basit bir Flask uygulaması oluşturdum. Zaten belirttiği gibi

from flask import Flask, jsonify, request 
from flask.views import MethodView 

app = Flask(__name__) 

class MyView(MethodView): 

    def get(self): 
     return jsonify({'method': 'GET'}) 

    def post(self): 
     method = request.form.get('_method', 'POST') 
     if method == 'POST': 
      return jsonify({'method':method}) 
     else: 
      if hasattr(self, method.lower()):    
       return getattr(self, method.lower())() 
      else: 
       return jsonify({'method': 'UNKNOWN'}) 

    def put(self): 
     return jsonify({'method': 'PUT'}) 

    def delete(self): 
     return jsonify({'method': 'DELETE'}) 

    def create(self): 
     # NOT A HTTP VERB 
     return jsonify({'method': 'CREATE'}) 

app.add_url_rule('/', view_func=MyView.as_view('myview')) 

if __name__ == "__main__": 
    app.run(debug=True) 
İlgili konular