当前位置: 首页 > 面试题库 >

使用SQLAlchemy从应用程序正确分离模型的Python方法

东方智敏
2023-03-14
问题内容

我很难让我的应用程序运行。每当我尝试将软件包中的模块分开时,Flask-SQLAlchemy扩展都会创建一个空数据库。为了更好地解释我在做什么,让我展示一下我的项目的结构:

Project
|
|-- Model
|   |-- __init__.py
|   |-- User.py
|
|-- Server
|   |-- __init__.py
|
|-- API
|   |-- __init__.py

这个想法很简单:我想为我的模型创建一个程序包,因为我不希望将代码分散在一个程序包中,而希望将代码分别放在各个“子”项目(如API)中,因为将来我将使用蓝图来更好隔离子应用。

代码很简单:

首先,Model.__init__.py

from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()

请注意,我创建此文件仅是为了SQLAlchemy()在整个包中使用单个对象。不,我们去Model.User

from Model import db

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    Name = db.Column(db.String(80))
    Age = db.Column(db.Integer)
    ...

再次注意来自模型导入数据库的信息,该模型用于允许相同的数据库对象。

最后,Server.init.py像这样:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import Model, API
db = Model.db


def main():
    app = Flask("__main__")
    db = SQLAlchemy(app)
    db.create_all()
    API.SetAPIHookers(app)
    app.run(host="0.0.0.0", port=5000, debug=True)

if __name__ == "__main__":
    main()

从我的角度来看,db = SQLAlchemy(app)允许我传递我的应用程序对象而无需创建循环引用。

问题是,每当我运行此代码时,sqlite数据库文件都会被创建为空。那让我认为也许Python不会像我想的那样导入东西。因此,我通过删除导入模型并直接在Server中创建用户来测试我的理论……瞧瞧,它起作用了!

现在出现了我的问题:是否存在一种“ pythonic”方式来正确分离所需的模块,还是应该将所有内容都放在同一软件包中?


问题答案:

现在,你已使用大致等同于“ Application Factory ”模式(由Flask文档称为)的方式设置了应用程序。这是Flask的想法,而不是Python。它具有一些优点,但也意味着你需要做一些事情,例如使用init_app方法而不是SQLAlchemy构造函数来初始化SQLAlchemy对象。这样做没有什么“错”,但是这意味着你需要像create_all()在应用程序上下文中那样运行方法,而如果你尝试在该main()方法中运行它,那么当前不是。

有几种方法可以解决此问题,但是要由你决定要哪种方法(没有正确的答案):

不要使用Application Factory模式
这样,你无需在函数中创建应用程序。相反,你将其放在某个地方(如中的project/__init__.py)。你的project/__init__.py文件可以导入models包,而models包可以app从导入project。这是一个循环引用,但只要没关系app对象在所创建的project包之前,首先model尝试导入app从package。有关示例的信息,请参见“ 大型应用程序模式”中的Flask文档,在该示例中,你可以将程序包拆分为多个程序包,但仍然可以使这些其他程序包app通过循环引用来使用该对象。文档甚至说:

每个Python程序员都讨厌它们,但我们只是添加了一些:循环导入。[…]一般而言,这是个坏主意,但在这里确实可以。

如果执行此操作,则可以更改Models/__init__.py文件以SQLAlchemy使用构造函数中对应用程序的引用来构建对象。这样,你可以使用对象的create_all()drop_all()方法SQLAlchemy,如Flask-SQLAlchemy的文档中所述。

保持你现在的状态,但是构建一个request_context()
如果继续进行现有操作(在函数中创建应用程序),则需要SQLAlchemy在Models包中构建对象,而无需将该app对象用作构造函数的一部分(已完成)。在你的主要方法中,更改…

db = SQLAlchemy(app)

…到…

db.init_app(app)

然后,你需要将create_all()方法移至应用程序上下文内部的函数中。在项目的早期阶段执行此操作的常用方法是利用before_first_request()装饰器…。

app = Flask(...)

@app.before_first_request
def initialize_database():
    db.create_all()

Flask处理第一个请求之前,将运行“ initialize_database”方法。你还可以通过使用app_context()方法在任何时候执行此操作:

app = Flask(...)
with app.app_context():
    # This should work because we are in an app context.
    db.create_all()

意识到如果你将继续使用Application Factory模式,那么你应该真正了解应用程序上下文是如何工作的。起初可能会造成混淆,但有必要认识到诸如“应用程序未在数据库实例上注册且没有应用程序绑定到当前上下文”之类的错误。



 类似资料:
  • 问题内容: 我一直在使用该功能来暂停脚本: 有正式的方法吗? 问题答案: 对我来说似乎很好(或在Python 2.X中)。或者,如果您想暂停一定的秒数,则可以使用。

  • 问题内容: 它是否正确?有没有更好的方法来构造它?这会覆盖我所有的基地吗? 问题答案: 看一下Requests 异常文档。简而言之: 如果出现网络问题(例如DNS故障,连接被拒绝等),请求将引发异常。 如果发生罕见的无效HTTP响应,则请求将引发HTTPError异常。 如果请求超时,Timeout则会引发异常。 如果请求超过配置的最大重定向数,则会引发异常。 请求显式引发的所有异常都继承自。 要

  • 我在应用程序中使用Activiti框架。Activiti通过Activiti API进行管理。 真是个问题: 我需要重新启动服务器wtih应用程序。这意味着两件事: 我需要正确暂停/停止所有活动 目前,我的应用程序已通过系统停止。退出(0) 问题: 我怎么会那样做呢?(意指以上两项) System.exit(0)会遇到什么问题? 编辑: 是的,谢谢。但我使用嵌入式Activiti。这些适用于嵌入式

  • 问题内容: 我有基于Cordova和Ionic的移动应用程序。在应用程序启动后加载的默认页面上,需要使用SQLLite插件。 https://github.com/brodysoft/Cordova- SQLitePlugin 问题是视图包含 哪个调用了与SQL Lite插件一起使用的控制器方法。并且由于该方法在未初始化deviceready事件之前调用该方法(只能在deviceready事件之后

  • 问题内容: 我有一个正在运行的Flask应用程序,该应用程序是根据我们在网上和Miguel Grinberg的“ Flask Web开发”书中找到的最佳实践组合设置的。 现在,我们需要第二个Python应用程序,它不是Web应用程序,并且需要访问与Flask应用程序相同的模型。我们想重复使用相同的课程模型,因此两个应用程序都可以从共享代码中受益。 我们删除了关于flask- sqlalchemy扩

  • 问题内容: 我正在尝试使用蓝图在Flask中创建一个“模块化应用程序”。 但是,在创建模型时,我遇到了必须引用该应用程序才能获取dbFlask-SQLAlchemy提供的-object的问题。我希望能够在多个应用程序中使用一些蓝图(类似于Django应用程序的使用方式),所以这不是一个好的解决方案。* 可以进行切换,让蓝图创建db实例,然后由应用程序将其与其余的蓝图一起导入。但是随后,任何其他希望