将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",}
]

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")

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)

解决方法

解决了。

我必须:

  1. 为不存在的每个表创建一个模型:(EventTag,Tag)
  2. 修改我的标签架构以匹配我想从Tag表中隐藏的值
  3. 修改我的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