【问题标题】:Return empty JSON object with Flask-Restful Nested field object for SQLAlchemy association if association is None如果关联为无,则返回带有 Flask-Restful 嵌套字段对象的空 JSON 对象以用于 SQLAlchemy 关联
【发布时间】:2015-01-08 03:32:09
【问题描述】:

摘要可能很混乱,但我不知道如何更简洁地表述它。

我拥有的模型:

class Movie(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(
    imdb_data = db.relationship('IMDBData', uselist=False)

class IMDBData(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(255))
    rating = db.Column(db.Float)
    movie_id = db.Column(db.Integer, db.ForeignKey('movie.id'))

使用 Flask-Restful 字段,我正在编组这样的响应:

imdb_data_fields = {
    'id': fields.Integer,
    'title': fields.String,
    'rating': fields.Float
}

movie_fields = {
    'id': fields.Integer,
    'title': fields.String
}

class MovieListAPI(Resource):
    def __init__(self):
        self.parser = reqparse.RequestParser()
        super(MovieListAPI, self).__init__()

    def get(self):
        self.parser.add_argument('imdb_data', type=str, location='args')
        args = self.parser.parse_args()

        m_fields = copy.copy(movie_fields)

        # TODO: Return empty object if movie.imdb_data = None
        if args['imdb_data']:
            m_fields['imdb_data'] = fields.Nested(imdb_data_fields)

        movies = Movie.query.all()
        return {'movies': marshal(movies, m_fields)}

现在,如果电影没有对应的imdb_data 记录,即Movie.query.filter_by(id=123).first().imdb_data = None,那么电影的对象会像这样编组:

{
    "id": 1302, 
    "imdb_data": {
        "id": 0, 
        "rating": null, 
        "title": null
    },     
    "title": "F 63 9 Love Sickness"
}

我希望响应看起来像这样:

{
    "id": 1302, 
    "imdb_data": {},     
    "title": "F 63 9 Love Sickness"
}

当我返回一部电影(通过 id)时,我知道如何破解这个:

if args['imdb_data']:
    if movie.imdb_data:
        m_fields['imdb_data'] = fields.Nested(imdb_data_fields)
    else:
        m_fields['imdb_data'] = fields.Nested({})

但是我如何为电影列表做到这一点?也许我可以自己遍历数组并手动更改它,但必须有更有效的方法。

【问题讨论】:

    标签: flask flask-sqlalchemy flask-restful


    【解决方案1】:

    这可以通过创建自定义字段来实现,如下所示:

    class NestedWithEmpty(Nested):
        """
        Allows returning an empty dictionary if marshaled value is None
        """
        def __init__(self, nested, allow_empty=False, **kwargs):
            self.allow_empty = allow_empty
            super(NestedWithEmpty, self).__init__(nested, **kwargs)
    
        def output(self, key, obj):
            value = get_value(key if self.attribute is None else self.attribute, obj)
            if value is None:
                if self.allow_null:
                    return None
                elif self.allow_empty:
                    return {}
    
            return marshal(value, self.nested)
    

    然后用它来编组传递allow_empty=True的对象:

    m_fields['imdb_data'] = NestedWithEmpty(imdb_data_fields, allow_empty=True)
    

    我什至用这个功能创建了一个拉取请求:https://github.com/twilio/flask-restful/pull/328

    【讨论】:

      【解决方案2】:

      阅读 PR #328(感谢@Andriy)并遵循它后,我的解决方法是添加 default arg

      foo['bar'] = fields.Nested(nested_fields, default={})
      

      在文档中并不明显。

      【讨论】:

        【解决方案3】:

        从 0.11.0 开始,您可以使用选项 skip_none=True 返回一个空对象而不是 null。

        @marshal_with 为例:

        from flask_restplus import Model, fields, marshal_with
        model = Model('Model', {
            'name': fields.String,
            'address_1': fields.String,
            'address_2': fields.String
        })
        @marshal_with(model, skip_none=True)
            def get():
                return {'name': 'John', 'address_1': None}
        

        指定嵌套字段:

        from flask_restplus import Model, fields
        model = Model('Model', {
            'name': fields.String,
            'location': fields.Nested(location_model, skip_none=True)
        })
        

        来源:https://flask-restplus.readthedocs.io/en/0.11.0/marshalling.html#skip-fields-which-value-is-none

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-08-30
          • 1970-01-01
          • 2019-05-15
          • 2021-10-26
          • 2018-12-31
          • 2013-11-13
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多