属性错误:当使用ClickFlask加载M2M模式时,'DummySession'对象没有属性'query'。

问题描述 投票:0回答:1

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

然而,我试图在一个单独的文件中通过点击将一些样本数据播种到我的数据库中。起初我认为问题出在Flask CLI和应用上下文上,我原本在蓝图中就有这个问题,但后来我意识到这个问题有点深。我看到了这个问题,但我已经将我的MarshmallowFlask-MarshmallowMarshmallow-Sqlalchemy更新为最新版本。

https:/github.commarshmallow-codemarshmallow-sqlalchemyissues20#issuecomment-136400602。

/ model.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

/ resource.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个回答
0
投票

好吧!我想我明白了。我想我想通了。我最终在Flask中遇到了两个问题:1) 应用环境 和2) 请求背景. 这个问题与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.

我基本上需要添加 app.app_context() 对我 __init__.py 档和 with current_app.test_request_context('/path/to/route/')@with_appcontext 在我 initialize.py 文件。我还需要将这些函数导入到我的 __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 在这里 测试Flask应用.

因此,为了澄清,如果你把所有的东西都放到你的 create_app 你需要使用 with app.test_request_context('/path/to/route/') 而不是在你 __init__.py. 否则,就像上面的例子一样,你需要使用 current_app 如果你把它分离到其他文件中。

我发现这篇文章非常有用,可以解释应用上下文以及文档中对这个问题的不明确。

https:/hackingandslacking.comdemystifying-flasks-application-context-c7bd31a53817。

© www.soinside.com 2019 - 2024. All rights reserved.