将flask restful api端点重构为单独的链接资源



我正在API上重构一些代码,我不确定如何在Flask-Restful和SQLAlchemy中构建相关的模型。半页的部分解决方案。

我基本上要做的是与这个SQL等效的

SELECT tags.name
FROM events, tags, events_tags 
WHERE events.id = events_tags.event_id 
AND tags.id = events_tags.tag_id
AND events.id = 1

我的路由最初有一个带有嵌套标签集的事件,api.add_resource(Events, '/events/<int:event_id>')返回的JSON的结构如下:

{  
"event_id":"1",
"title":"Sample title",
"tags":[
{"name":"earthquake"},
{"name":"infrastructure"}
]
}

这是tags,我想把它分离成一个单独的端点:

因此,我们最终得到两个JSON输出

api.add_resource(Event, '/events/<int:event_id>')

[
{  
"event_id":"1",
"title":"Sample title",
}
]

api.add_resource(Tags, '/events/<int:event_id>/tags')

[
{"name":"earthquake"},
{"name":"infrastructure"}
]

当我正在处理这个问题,并且意识到任何给定的标记都可能属于多个事件时,我认为解决方案需要完成以下操作:

  1. 数据库中的事件/标记联接表
  2. api中tag_association_table的函数
  3. 一个TagsListModel(但我不确定这是否引用了这个tag_association_table

欢迎任何帮助。

标记模型

class TagsListModel(db.Model):
__tablename__ = "tags"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, nullable=False)
events = db.relationship("EventModel", secondary=tag_association_table, backref="tag")

标签串行器

class TagSchema(SQLAlchemyAutoSchema):
class Meta:
model = TagModel
load_instance = True
include_fk = True
id = auto_field(load_only=True)

标签加载器

class Tags(Resource):
# GET
def get(self, event_id):
schema = TagsListSchema()
result = db.session.query(TagsListModel).filter(TagsListModel.event_id == event_id)
return schema.dump(result, many=True), 200
# POST
def post(self, event_id):
event_id = event_id
name = request.json['name']
tag = TagsListModel(name=name)

db.session.add(tag)
db.session.commit()
data = ({'id' :tag.id,
'name': tag.name
})
#print(data)
response = jsonify(data)
response.status_code = 200 # or 400 or whatever
return response

路线

# Route_1
## GET (RETURNS) A LIST OF EVENTS
## POST (CREATES) AN EVENT
api.add_resource(Events, '/events')
# Route_2
## GET (RETURNS) A SINGLE EVENT
# PUTS (UPDATES) A SINGLE EVENT
api.add_resource(Events, '/events/<int:event_id>')
# Route_3
## GET (RETURNS) ALL TAGS FOR AN EVENT
api.add_resource(Tags, '/events/<int:event_id>/tags')

部分解

我已经能够检索联接表上的值。这些经过正确过滤,并提供以下输出:

[
{
"tag_id": 1, 
"event_id": 1
}, 
{
"tag_id": 2,
"event_id": 1
}
]

端点

我用1int:event_id值调用以下端点:

# Route_3
## GET (RETURNS) ALL TAGS FOR AN EVENT
api.add_resource(EventTags, '/events/<int:event_id>/tags')

装载机

class EventTags(Resource):
# GET
def get(self, event_id):
schema = TagSchema()
result = db.session.query(TagModel).filter(TagModel.event_id == event_id)
return schema.dump(result, many=True), 200
# POST
def post(self, event_id):
event_id = event_id
tag_id = request.json['id']
tag = TagsListModel(id=id)

db.session.add(tag)
db.session.commit()
data = ({'id' :tag.id
})
#print(data)
response = jsonify(data)
response.status_code = 200 # or 400 or whatever
return response

架构

class TagSchema(SQLAlchemyAutoSchema):
class Meta:
model = TagModel
load_instance = True
include_fk = True
tag_id = auto_field(load_only=False)
event_id = auto_field(load_only=False)

型号

class TagModel(db.Model):
__tablename__ = "events_tags"
tag_id = Column(Integer, primary_key=True)
event_id = Column(Integer, primary_key=True)

修复它。

我不得不:

  1. 为不存在的每个表创建一个模型:(EventTag,Tag(
  2. 修改我的标记模式以匹配我想从Tag表中隐藏的值
  3. 修改我的EventTags Loader以筛选三个表中的列

型号

class TagModel(db.Model):
__tablename__ = "tags"
id = Column(Integer, primary_key=True)
name = Column(db.String, nullable=False)

class EventTagModel(db.Model):
__tablename__ = "events_tags"
tag_id = Column(Integer, primary_key=True)
event_id = Column(Integer, primary_key=True)

模式

class TagSchema(SQLAlchemyAutoSchema):
class Meta:
model = TagModel
load_instance = True
include_fk = True
id = auto_field(load_only=True)  # Only one field removed so this remained pretty identical. 

装载机

result = db.session.query(TagModel)
.filter(TagModel.id == EventTagModel.tag_id)
.filter(EventModel.id == EventTagModel.event_id)
.filter(EventTagModel.event_id == event_id)
#   result = db.session.query(TagModel).         # REMOVED
#       filter(TagModel.event_id == event_id).   # REMOVED

最新更新