2013-06-21 8 views
9

में छिपे हुए फ़ील्ड _method का उपयोग कर अनुरोध विधि बदलना एक सीखने के अभ्यास के रूप में पाइथन और फ्लास्क चुनना शुरू किया, और PHP/Symfony2 से आना शुरू किया, मैं एक छिपी हुई _method फ़ील्ड को एक विधि में जोड़ सकता हूं ताकि POST विधि को किसी भी DELETE के साथ ओवरराइड किया जा सके या डाल।फ्लास्क

ऐसा लगता है कि फ्लास्क इस मूल रूप से समर्थन नहीं करता है, और मैं http://flask.pocoo.org/snippets/38/ सहित विभिन्न विचारों के साथ हैकिंग कर रहा हूं, जो काम करता है, लेकिन इसमें छिपे हुए क्षेत्र के बजाय फॉर्म एक्शन में ओवरराइड डालना शामिल है, जो आईएमओ बनाता है यूआरएल अस्पष्ट दिखता है।

उपर्युक्त पते की टिप्पणियों में एक स्निपेट है, जो रूटिंग परिप्रेक्ष्य से _method काम करता है, लेकिन जैसा कि वहां भी चर्चा की गई है, अगर आप अनुरोध में request.form तक पहुंचने का प्रयास करते हैं तो अनुरोध लटकने का कारण बनता है ।

क्या किसी के पास इसके लिए कोई कामकाज है? यदि नहीं, तो मैं सबकुछ पोस्ट के रूप में संभाल दूंगा, लेकिन यह काम करने के लिए एक रास्ता खोजने में सक्षम होना अच्छा होगा।

चीयर्स।


संपादित करें:

खाका:

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

एप्लिकेशन/__ 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 

देखें यहाँ जो एक बार देख ले जाना चाहता है किसी के लिए कोड है:

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: शायद वहाँ भी कुछ खतरनाक बढ़त मामलों है कि मैं अपने आप की पता नहीं है, जिसके कारण मैं कभी नहीं एक असली आवेदन में निम्नलिखित की कोशिश कर रहा जोखिम होता हैं // flask.pocoo.org/docs/quickstart/#the-request-object) आपके लिए कुछ उपयोग हो सकता है। – John

+0

हाय @johnthexiii, आपकी टिप्पणी के लिए धन्यवाद। मैं वास्तव में अनुरोध कर रहा हूं कि _method सेट है या नहीं, लेकिन एक बार जब मैं ऐसा करता हूं और मिडलवेयर में REQUEST_METHOD बदलता हूं, तो मैं दृश्यों में request.form तक नहीं पहुंच सकता (ऐप बस लटकता है)। यह सुझाव है कि मैं जिस सुझाव का प्रयास कर रहा था उसका लिंक है: http://flask.pocoo.org/snippets/38/#comment-box (दूसरी टिप्पणी) – aleayr

+0

मैंने कुछ कोड डाला है जो कि एक बेहतर अवलोकन देने के लिए है मैं हासिल करने की कोशिश कर रहा हूँ। – aleayr

उत्तर

4

जैसा कि आपने पहले ही बताया है, आपका मिडलवेयर बाद में 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) 

यह किसी भी सूचकांक इस फाइल वस्तु एक seek विधि है कि नहीं दिखाती है।

तो, आप क्या कर सकते हैं एक bytestring data कहा जाता है में सब कुछ पढ़ा है, और BytesIO(data) साथ wsgi.input की जगह है, जो एक 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) 
+0

धन्यवाद मार्कस, ऐसा लगता है। Django खुद या तो इसका समर्थन नहीं प्रतीत होता है। TastyPie हालांकि (_method का उपयोग नहीं कर रहा है, लेकिन हेडर ओवरराइड का उपयोग कर), लेकिन फ़ॉर्म के लिए अनुकूलित किया जा सकता है। जैसा कि यह खड़ा है, मैं सिर्फ फॉर्म से पोस्ट का उपयोग कर रहा हूं और फ्लास्क व्यू में पुट/पोस्ट/डिलीट लॉजिक कर रहा हूं। रूटिंग सजावट का उपयोग करने में सक्षम होने के रूप में सुरुचिपूर्ण नहीं है, लेकिन करना होगा। आपके इनपुट के लिए धन्यवाद। – aleayr

1

आप flask.views से उपयोग कर सकते हैं और इसे सही तरीकों से भेज सकते हैं। मैंने इसे प्रदर्शित करने के लिए एक सरल फ्लास्क ऐप बनाया है।

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)