尝试构建 RESTless API 时出现“方法不允许”错误

Posted

技术标签:

【中文标题】尝试构建 RESTless API 时出现“方法不允许”错误【英文标题】:Getting Method Not Allowed error when trying to build a RESTless API 【发布时间】:2016-07-18 14:19:24 【问题描述】:

我正在学习 Flask,我发现了各种 sn-ps,它们展示了如何使用 SQLAlchemy 定义模型、使用 Flask-restless 定义 REST API 以及使用 Flask-wtf 定义表单(我对 REST API 不是很熟悉)。更准确地说,我的灵感来自:

Flask-restless Quickstart(来自文档) Automatically create a WTForms Form from model(可追溯到 2011 年) This SO question 用于基本模板

但是我无法创建一个完整的工作示例。基于您可以在网上找到的位,我想创建一个具有 2 个类 PersonComputer 的模型(Person 可以与多个 Computers 相关联)和一个添加新 Person 的表单.这是我组装的代码。

布局如下:

test_flask/
├── test_flask.py
├── config.py
└── templates
    └── new_person.html

主文件test_flask.py包含:

from flask import Flask, request, flash, redirect, render_template, url_for
import flask.ext.sqlalchemy
from wtforms.ext.sqlalchemy.orm import model_form
import flask.ext.restless
from flaskext.wtf import Form

# Create the Flask application and the Flask-SQLAlchemy object.
app = Flask(__name__)
app.config.from_object('config')
db = flask.ext.sqlalchemy.SQLAlchemy(app)

# Create the Flask-SQLALchemy models.
class Person(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.Unicode, unique=True)
    birth_date = db.Column(db.Date)


class Computer(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.Unicode, unique=True)
    vendor = db.Column(db.Unicode)
    purchase_time = db.Column(db.DateTime)
    owner_id = db.Column(db.Integer, db.ForeignKey('person.id'))
    owner = db.relationship('Person', backref=db.backref('computers',
                                                         lazy='dynamic'))

# Create the database tables.
db.create_all()

# Create the Flask-Restless API manager.
manager = flask.ext.restless.APIManager(app, flask_sqlalchemy_db=db)

# Create API endpoints.
manager.create_api(Person, methods=['GET', 'POST', 'DELETE'])
manager.create_api(Computer, methods=['GET'])

# Create a form class for class Person.
PersonForm = model_form(Person, base_class=Form)


@app.route('/')
def hello():
    return 'Hello World'


@app.route("/api/new_person")
def new_person():
    # The new person
    person = Person()
    # Create a form
    form = PersonForm(request.form, person)
    if form.validate_on_submit():
        form.populate_obj(person)
        person.post()
        flash("new person %s inserted updated" % person)
        return redirect(url_for("new_person"))
    return render_template("new_person.html", form=form)

if __name__ == '__main__':
    # start the flask loop
    app.run()

config.py 文件包含:

DEBUG = True
WTF_CSRF_SECRET_KEY = 'a random string'
SECRET_KEY = 'you-will-never-guess'
WTF_CSRF_ENABLED = True
SQLALCHEMY_DATABASE_URI = 'sqlite:////tmp/test.db'

模板new_person.html 包含:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
    "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
  <head>
    <meta http-equiv="content-type" content="application/json">
    <title>New person</title>
  </head>
% block body %
    <form action="new_person" method=post class=add-entry>
      <dl>
        <dt>Name:
        <dd>form.name
        <dt>Birth date:
        <dd>form.birth_date
        <dd><input type=submit value=submit>
      </dl>
    </form>
% endblock %
</html>

我可以在http://127.0.0.1:5000/api/new_person/ 看到添加新人的表单,但在提交时出现“方法不允许”错误。

【问题讨论】:

@Martijn Pieters 我将链接添加到我遵循的教程中(我不使用 WTF-Alchemy 这应该会更好一些)。我的问题恰恰是将所有的 sn-ps 粘合在一起。 我的直觉是person.post() 方法(我相信它是插入新Person 的方法)实际上从未被调用...我试图更改@987654345 的形式@ 到 api/person 但没有成功。 其实person.post()是从哪里来的?这不会将新实例添加到您的数据库中.. 我从here复制了这部分(并将model重命名为person)但我意识到他们实际上使用'put()'......我不认为改变任何事情,因为这段代码永远不会被调用。 确定代码永远不会被调用吗?虽然我怀疑您需要告诉表单 id 字段不是表单有效所必需的。 【参考方案1】:

您正在发布到new_person 路由,但尚未配置路由以接受POST 请求。默认只允许GETHEAD。将 methods 参数设置为 route() 装饰器:

@app.route("/api/new_person", methods=['GET', 'POST'])
def new_person():

请参阅 Flask 快速入门的HTTP Methods section。

接下来,如果您希望更改保持不变(例如添加新的Person),则需要提交事务;将新的 person 对象添加到您的会话并提交:

db.session.add(person)
db.session.commit()

请参阅 Flask-SQLAlchemy 选择、插入、删除一章的Inserting Records section。

或者,将 SQLAlchemy 会话设置为自动提交所有更改:

db = flask.ext.sqlalchemy.SQLAlchemy(app, session_options='autocommit': True)

不过,您仍需要将新对象添加到会话中。

【讨论】:

哼,我要methods=['GET', 'POST'](不然看不到表格)。但是,当我转到http://127.0.0.1:5000/api/person/ 时,我仍然看不到任何PersonPerson 类的GET 方法由Flask-restless 定义)。 @MathieuDubois:对,我只看表格,没有看表格的内容。 @Martjin Pieters 我认为数据库中仍然没有插入Person @MathieuDubois:您需要提交交易。让我查一下参考资料。 @Martjin Pieters 你能提供完整的sn-p吗?

以上是关于尝试构建 RESTless API 时出现“方法不允许”错误的主要内容,如果未能解决你的问题,请参考以下文章

尝试从反应应用程序连接到 graphcool 中继 API 时出现此错误:模块构建失败:错误:没有有效的 GraphQL 端点

使用 flask-restless 得到 404 错误

为啥在尝试将 UIPopover 附加到不同类中的 UIButton 时出现此构建错误?

在使用 node.js 和 Express 构建的 api 中使用 cors 中间件时出现 CORS 错误

构建 APK 时出现错误

启动活动时出现Google Maps API密钥错误