【问题标题】:AttributeError: 'DummySession' object has no attribute 'query' when loading M2M schema with Click/FlaskAttributeError:“DummySession”对象在使用 Click/Flask 加载 M2M 模式时没有属性“query”
【发布时间】:2020-05-22 16:52:15
【问题描述】:

我正在使用应用程序工厂模式,并且我有一个与 M2M 关系中的类别相关的 Article 对象。到目前为止,API 中的所有路由都按预期工作。我可以通过 POST MethodViews 创建带有类别的文章。

但是,我正在尝试通过单击单独的文件将一些示例数据播种到我的数据库中。起初我认为问题出在 Flask CLI 和应用程序上下文,我最初在蓝图中有,但后来我意识到问题更深了一些。我看到了这个问题,但我已经将我的 Marshmallow/Flask-Marshmallow/Marshmallow-Sqlalchemy 更新到了最新版本:

https://github.com/marshmallow-code/marshmallow-sqlalchemy/issues/20#issuecomment-136400602

// 模型.py

class CRUDMixin():

    @classmethod
    def find_by_id(cls, _id):
        return cls.query.filter_by(id=_id).first()

    @classmethod
    def find_all(cls):
        return cls.query.all()

    def save_to_db(self):
        db.session.add(self)
        return db.session.commit()

    def update(self):
        return db.session.commit()

    def delete_from_db(self):
        db.session.delete(self)
        return db.session.commit()

class CategoryModel(db.Model, CRUDMixin):
    __tablename__ = "api_category"

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80), nullable=False)

    def __repr__(self):
        return '<id {}>'.format(self.id)


class ArticleModel(db.Model, CRUDMixin):
    __tablename__ = 'api_article'

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80), nullable=False)
    description = db.Column(db.Text)

    categories = db.relationship('CategoryModel', secondary=api_category_article, lazy='subquery',
                             backref=db.backref('articles', lazy=True))

    def __repr__(self):
        return '<id {}>'.format(self.id)

// schema.py

class CategoryPostSchema(ma.SQLAlchemyAutoSchema):
    class Meta:
        model = CategoryModel
        dump_only = ("name", )
        load_only = ("articles", )
        load_instance = True


class ArticlePostSchema(ma.SQLAlchemyAutoSchema):
    categories = ma.Nested(CategoryPostSchema, many=True)

    class Meta:
        model = ArticleModel
        dump_only = ("id",)
        include_fk = True
        load_instance = True
        include_relationships = True
        sqla_session = db.session

//资源.py

class ArticleListView(MethodView):

    def __init__(self):
        pass

    @classmethod
    def get(cls):
        data = ArticleModel.find_all()
        return jsonify({"data": article_list_schema.dump(data),
                        "count": len(data),
                        "status": 200
                        })

    @classmethod
    def post(cls):

        req_json = request.get_json()
        errors = article_post_schema.validate(req_json)

        if errors:
            response = jsonify({'errors': errors, "status": 400})
            response.status_code = 400
            return response

        data = article_post_schema.load(req_json)
        data.save_to_db()

        response = jsonify({"data": article_post_schema.dump(data), "errors": {}, "status": 201})
        response.status_code = 201
        return response

//initialize.py(在根目录下)

import click

from marshmallow import ValidationError

from api import create_app
from api.db import db
from api.schemas import ArticlePostSchema


app = create_app()

@click.group()
def cli():
    pass

@cli.command()
def article():
    with app.app_context():

        article_post_schema  = ArticlePostSchema()

        entry = {"name":"My Family Vacation 5",
                "description":"That time we took a road trip to Europe",
                "categories":[{"id": 1}]
                }

        data = article_post_schema.load(entry, session=db.session)
        data.save_to_db()
        print("Success")

if __name__ == '__main__':
    cli()

// 错误

Traceback (most recent call last):
  File "initialize.py", line 41, in <module>
    cli()
...
  File "initialize.py", line 29, in article
    data = article_post_schema.validate(entry)
...
    return self.session.query(self.opts.model).filter_by(**filters).first()
AttributeError: 'DummySession' object has no attribute 'query'

【问题讨论】:

    标签: python flask click marshmallow flask-marshmallow


    【解决方案1】:

    好的!我想我想通了。我最终在 Flask 中遇到了两个问题:1)Application Context 和 2)Request Context。这个问题与 Marshmallow Schemas 无关,但我会说没有 M2M 关系的对象工作非常令人困惑,但是对于 M2M 关系,它需要一个请求上下文。如果有人愿意解释,那就太好了。

    我在这个过程中遇到了以下错误:

    AttributeError: 'DummySession' object has no attribute 'query'
    RuntimeError: No application found. Either work inside a view function or push an application context.
    AssertionError: Popped wrong app context.
    

    我基本上需要在我的__init__.py 文件中添加app.app_context(),在我的initialize.py 文件中添加with current_app.test_request_context('/path/to/route/')@with_appcontext。我还需要将函数导入我的__init__.py。为了保持整洁,我将文件移到了我的应用程序文件夹中

    // 初始化.py

    def create_app():
    
        app = Flask(__name__)
    
        # Config
        ...
    
        # Initialize DB and Marshmallow
        db.init_app(app)
        ma.init_app(app)
    
        with app.app_context():
    
            # Import Models
            ...
    
            # Import MethodViews
            ...
    
            # Import Blueprints
            ...
    
            # Commands
    
            from api.initialize import article
    
            app.cli.add_command(article)
    
            return app
    

    // initialize.py(现在在/api目录下)

    @click.command()
    @with_appcontext
    def article():
        article_post_schema  = ArticlePostSchema()
        entry = {"name":"My Family Vacation 5",
                    "description":"That time we took a road trip to Europe",
                    "categories":[{"id": 1}]
                    }
    
        with current_app.test_request_context('/article/'):
            try:
                data = article_post_schema.load(entry)
                data.save_to_db()
                print("Success")
            except ValidationError as err:
                print("Errors...", err)
    

    现在运行 flask article 就可以了。

    注意:Flask-Click 有很多使用单页文件并在create_app() 中定义命令的示例。这对于简单的示例或阐明基本思想或功能非常有用。然而,这也很令人困惑,因为似乎任何生产环境中的大多数人都将使用蓝图和应用程序工厂模式作为他们的默认模式。 test_request_context 唯一有用的地方是 Testing Flask Applications

    所以澄清一下,如果您将所有内容都放入您的create_app,您需要使用with app.test_request_context('/path/to/route/') 而不是您的__init__.py。否则,如上例所示,如果将其分离到其他文件中,则需要使用 current_app

    我发现这篇文章对于解释应用程序上下文以及文档中缺乏明确性非常有用:

    https://hackingandslacking.com/demystifying-flasks-application-context-c7bd31a53817

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-07-01
      • 2022-12-05
      • 2019-09-06
      • 2022-10-08
      • 2014-11-11
      • 1970-01-01
      • 2012-06-28
      • 2014-04-15
      相关资源
      最近更新 更多