不同蓝图的不同模型 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)以适应类型您可能想要获得的输出。
我有一个基于 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)以适应类型您可能想要获得的输出。