不同蓝图的不同模型 resource_fields

Different model resource_fields for different blueprints

我有一个基于 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: Table '' is already defined for this MetaData instance. Specify 'extend_existing=True' to redefine options and columns on an existing Table object.

我知道这是因为我实际上是在为每个蓝图定义相同的数据库表。我真正想要的只是更改每个蓝图的 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) }

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

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