我正在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"}
]
当我正在处理这个问题,并且意识到任何给定的标记都可能属于多个事件时,我认为解决方案需要完成以下操作:
- 数据库中的事件/标记联接表
- api中
tag_association_table
的函数 - 一个
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
}
]
端点
我用1
的int: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)
修复它。
我不得不:
- 为不存在的每个表创建一个模型:(EventTag,Tag(
- 修改我的标记模式以匹配我想从
Tag
表中隐藏的值 - 修改我的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