Изменение метода запроса с использованием скрытого поля _method в Flask

Начав собирать Python и Flask в качестве учебного упражнения, и, исходя из PHP / Symfony2, я мог бы добавить скрытое поле _method в форму, чтобы переопределить метод POST с помощью DELETE или PUT.

Кажется, что Flask не поддерживает это изначально, и я взламывал различные идеи, в том числе http://flask.pocoo.org/snippets/38/ , который работает, но включает в себя замещение в форме действия, а чем как скрытое поле, которое IMO делает URL-адрес неприглядным.

В комментариях вышеприведенного адреса есть фрагмент, который делает работу _method с точки зрения маршрутизации, но, как обсуждалось там, вызывает запрос на зависание, если затем попытаться получить доступ к request.form в представлениях.

У кого-нибудь есть обходной путь для этого? Если нет, я просто буду обрабатывать все как POST, но было бы неплохо найти способ заставить его работать.

Приветствия.


EDIT: Вот код для тех, кто хочет взглянуть:

Шаблон:

<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 = 'test@test.com' if request.method == 'PUT': emailvalue = request.form['email'] return render_template('login.html', email=emailvalue) 

  • Маршрутизация домена в колбе
  • IOError: на устройстве нет места - какое устройство?
  • Безопасен ли сервер в комплекте с Flask для использования в производстве?
  • Получение массива как параметров запроса GET в Python
  • структура структуры и формы сообщения с флягой
  • Сохранение загруженных данных base64 дает TypeError: необходим байтовый объект, а не 'str'
  • RuntimeError: работает вне контекста приложения
  • Parse X-Forwarded-For, чтобы получить ip с werkzeug на Heroku
  • 2 Solutions collect form web for “Изменение метода запроса с использованием скрытого поля _method в Flask”

    Как вы уже указывали, ваше промежуточное ПО делает более поздний 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 .

    Итак, что вы можете сделать, это прочитать все в байтовое имя, называемое 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) 

    Вы можете использовать MethodView из flask.views и отправить его в нужные методы. Я продемонстрировал это простое приложение Flask.

     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) 
    Interesting Posts

    getrandbits не производит номера постоянной длины

    Проверка того, находятся ли какие-либо элементы в одном списке в другом

    Создание и поддержка нескольких сеансов ssh в Python

    MySQL INSERT … ON DUPLICATE KEY UPDATE с django 1.4 для объемной вставки

    Python: как избежать numpy RuntimeWarning в определении функции?

    когда я пытаюсь установить Flask-bcrypt, он вызывает ошибку: команда «x86_64-linux-gnu-gcc» не удалась с статусом выхода 1

    pyrouge: «pyrouge_set_rouge_path» не распознается как внутренняя или внешняя команда

    Django: как создать модель динамически только для тестирования

    Можно ли вызывать модуль Python из ObjC?

    Поиск расположения элементов массива в столбце кадра pandas (aka pd.series)

    Преобразование строк ввода пользователя в исходный строковый литерал для создания регулярного выражения

    Упрощение французского набора тегов POS с NLTK

    Разбор значений из файла JSON?

    Сохранять регистр в ConfigParser?

    В чем разница между mat и matND?

    Python - лучший язык программирования в мире.