针对不同蓝图

时间:2016-05-06 08:11:14

标签: flask flask-sqlalchemy flask-restful

我有一个基于Flask-RESTful的API,目前有两个蓝图,允许我使用向后不兼容的更改来对API进行版本控制。

from api_1_0 import api_bp as api_1_0_blueprint
app.register_blueprint(api_1_0_blueprint, url_prefix='/api/v1.0')

from api_1_1 import api_bp as api_1_1_blueprint
app.register_blueprint(api_1_1_blueprint, url_prefix='/api/v1.1')

每当我需要进行向后不兼容的更改(例如删除端点)时,我都会创建一个新的蓝图。目前,蓝图共享相同的models.py文件,定义数据库表和每个模型的JSON表示。

我现在需要创建一个新版本的API,其中特定资源字段email将从string数据类型更改为array[string]。 API的现有版本必须保留原始资源表示。

我尝试在每个蓝图文件夹中放置一个models.py文件,以便较新的蓝图v1.2可以拥有自己的resource_fields定义,但这样做我最终会遇到此错误:

  

sqlalchemy.exc.InvalidRequestError:已为此MetaData实例定义了表''。将'extend_existing = True'指定为   重新定义现有Table对象上的选项和列。

我理解这种情况正在发生,因为我实质上是为每个蓝图定义相同的数据库表。我真正想要的是改变每个蓝图的resource_fields,因为所有API版本的数据库模式总是相同的,它只是可能改变的JSON响应。 (我将使用@property装饰器来创建新字段)

鉴于此设置,如何更改每个蓝图的resource_fields

以下是我项目中的一些示例(简化)代码。

app / models.py - https://gist.github.com/MattHealy/4c9d2c03615e3381774235bbbc398437

from app import db
from flask.ext.restful import fields

@swagger.model
class Contact(db.Model):

      resource_fields = {
        'email': fields.String
      }

      email = db.Column(db.String(100))

app / api_1_1 / resources / contacts.py - https://gist.github.com/MattHealy/556c93fe33a929e469ae18bf76db83b1

from flask.ext.restful import Resource, marshal, reqparse
from ... models import Contact

class ContactAPI(Resource):

    "Retrieve details of a single contact"
    @swagger.operation(
        nickname = "contact",
        responseClass=Contact.__name__,
        parameters=[
            {
              "name": "id",
              "description": "ID of the contact",
              "required": True,
              "allowMultiple": False,
              "dataType": "int",
              "paramType": "path"
            },
        ],
        responseMessages=[
            {
              "code": 200,
              "message": "Contact retrieved"
            },
          ],
        summary="Get details of a single contact",
        )
    def get(self, id):
        contact = Contact.query.get(id)
        return { 'contact': marshal(contact, Contact.resource_fields) }

1 个答案:

答案 0 :(得分:1)

您可以在每个蓝图中使用不同的(本地生成的)resource_fields dict。在您的特定情况下,您可以使用resource_fields作为ContactAPI类的属性并将其传递给编组函数。

在上面显示的特定情况下(电子邮件字段的类型更改)我认为您还需要构建一个自定义Fields类(基于fields.Raw)以适应您可能想要获得的输出类型。