问题描述
我正在重构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",}
]
api.add_resource(Tags,'/events/<int:event_id>/tags')
[
{"name":"earthquake"},{"name":"infrastructure"}
]
在解决问题时,我意识到任何给定标签都可能属于多个事件,因此我认为解决方案需要完成以下工作:
欢迎任何帮助。
标签模型
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")
TAG SERIALISER
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
}
]
端点
我用int:event_id
的{{1}}值呼叫以下端点:
1
加载程序
# 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,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)
解决方法
解决了。
我必须:
- 为不存在的每个表创建一个模型:(EventTag,Tag)
- 修改我的标签架构以匹配我想从
Tag
表中隐藏的值 - 修改我的EventTags加载程序以过滤三个表中的列
模型
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)
SCHEMA
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.
LOADER
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