如何正确构建 SQLAlchemy(声明式风格)Python 项目及其单元测试

发布于 2025-01-04 01:36:45 字数 2872 浏览 2 评论 0原文

我正在为一些网络应用程序开发大型后端。这是我的第一个 python 和 SQLAlchemy 项目,所以我对一些事情感到困惑。与 python 相比,Java 编程工具和 IDE 有点被宠坏了(无论如何我在 eclipse 中使用 pydev)。我需要有关如何构建项目和编写测试的帮助。我先描述一下情况。

在 PyDev 中,我将我的项目命名为“ProjectName”,下面我显示了我当前的文件夹/包和文件结构。

  • 项目名称
    • 项目名称
      • __init__.py
      • 一些_包
        • __init__.py
        • Foo.py
        • 酒吧.py
    • 测试
      • 单元测试
        • __init__.py
        • 一些_包
          • __init__.py
          • TestFoo.py
          • TestBar.py
      • 加载测试
      • 集成测试
      • __init__.py

我在 SQLAlchemy 中使用声明式风格 Foo 和 Bar 是一些类,例如 Foo 扩展了 SQLAlchemy 声明性 Base,而 Bar 扩展了 Foo。在 __init__.py 中的“projectname.some_package”下,我有以下代码:

engine = create_engine('mysql+mysqldb://user:pass@localhost:3306/SomeDataBase', pool_recycle=3600)
Session = sessionmaker(bind=engine)
Base = declarative_base()

因此,Foo 导入此 Base 并扩展它,Bar 导入 Foo 并扩展它。我的第一个问题是,我应该将 Base 存储在 __init__.py 中并像我开始使用这两个类一样使用它吗?这个 create_engine 只是临时的,我想要配置文件并从那里加载它的设置,该怎么做?我应该在哪里调用 Base.metadata.create_all() ,以便它可以一次创建所有数据库表?

接下来,在测试类中,例如在 TestFoo 中,我有以下代码:

def setUp(self):
    #create database tables and session object
    self.engine = create_engine('mysql+mysqldb://user:pass@localhost:3306/SomeDatabase', pool_recycle=3600)
    Session = sessionmaker(bind=self.engine)
    Foo.metadata.create_all(bind=self.engine)
    self.session = Session()

def tearDown(self):
    #drop all tables and close session object
    self.session.close()
    meta = MetaData(self.engine)
    meta.reflect()
    meta.drop_all()

End 然后我在该测试类中有一些测试方法,并且运行良好。在 TestBar 类中,区别在于

Foo.metadata.create_all(bind=self.engine)

Bar.metadata.create_all(bind=self.engine)

当我运行 TestBar 时,它也运行良好。但是,当我选择两个测试类并运行它们时,我收到错误:

/usr/local/lib/python2.7/dist-packages/sqlalchemy/ext/declarative.py:1336: SAWarning: The classname 'Foo' is already in the registry of this declarative base, mapped to <class 'projectname.some_package.Foo.Foo'>
  _as_declarative(cls, classname, cls.__dict__)
/usr/local/lib/python2.7/dist-packages/sqlalchemy/engine/default.py:330: Warning: Field 'id' doesn't have a default value
 cursor.execute(statement, parameters)

这里有什么问题?我尝试使用鼻子和 pydev 跑步者运行测试并得到相同的错误。然后我尝试将数据库表创建移动到unit_tests下some_package中的__init__.py中,但我无法让它工作。另外,我对 python import 的工作原理感到困惑。例如,如果我在 TestBar 类中添加 Foo 导入,我也会收到与我已经显示的类似的错误。如何同时运行多个测试 SQLAlchemy 类的单元测试?

因此,再次提取最重要的问题:

  1. 如何正确构建使用 SQLAlchemy 声明式风格和单元测试的 python 项目。顺便说一句,我在 Foo 和 Bar 中有许多与数据库交互的类方法,在它们各自的类的上下文中,我希望这样可以吗?
  2. 在哪里存储基本声明类以及如何在整个项目中正确使用它,以及如何在项目中的任何位置提取所有数据库架构(我在类中以声明方式定义)并使用它?
  3. 如何最好地使用 SQLAlchemy 的单元测试并同时运行多个单元测试?
  4. 如果您还有其他建议,请随时添加?

非常感谢您的帮助。

I am developing large backend for some web apps. This is my first python and SQLAlchemy project, so I am confused with some things. And was kind of spoiled by Java programming tools and IDE`s, compared to python`s (I use pydev in eclipse anyway). I need help with how to structure the project and write tests. I`ll describe situation first.

In PyDev i named my project for example "ProjectName", and below I have shown my current folder/package and files structure.

  • ProjectName
    • projectname
      • __init__.py
      • some_package
        • __init__.py
        • Foo.py
        • Bar.py
    • tests
      • unit_tests
        • __init__.py
        • some_package
          • __init__.py
          • TestFoo.py
          • TestBar.py
      • load_tests
      • integration_tests
      • __init__.py

I use declarative style in SQLAlchemy. Foo and Bar are some classes, such that Foo extends SQLAlchemy declarative Base and Bar extends Foo. Under 'projectname.some_package' in it`s __init__.py I have this code :

engine = create_engine('mysql+mysqldb://user:pass@localhost:3306/SomeDataBase', pool_recycle=3600)
Session = sessionmaker(bind=engine)
Base = declarative_base()

So, Foo imports this Base and extends it, and Bar imports Foo and extends it. My first question is, should I store Base in that __init__.py and use it like I started with this 2 classes? This create_engine is just temporary there, I would like to have config file and load it`s settings from there, how to do that? Where should I call Base.metadata.create_all(), so it can create all database tables at once?

Next, in testing classes, for example in TestFoo I have this code :

def setUp(self):
    #create database tables and session object
    self.engine = create_engine('mysql+mysqldb://user:pass@localhost:3306/SomeDatabase', pool_recycle=3600)
    Session = sessionmaker(bind=self.engine)
    Foo.metadata.create_all(bind=self.engine)
    self.session = Session()

def tearDown(self):
    #drop all tables and close session object
    self.session.close()
    meta = MetaData(self.engine)
    meta.reflect()
    meta.drop_all()

End then I have some test methods in that test class and it runs fine. In TestBar class difference is that

Foo.metadata.create_all(bind=self.engine)

is :

Bar.metadata.create_all(bind=self.engine)

When I run TestBar, it also runs fine. But, when I select both test classes and run them, I get errors :

/usr/local/lib/python2.7/dist-packages/sqlalchemy/ext/declarative.py:1336: SAWarning: The classname 'Foo' is already in the registry of this declarative base, mapped to <class 'projectname.some_package.Foo.Foo'>
  _as_declarative(cls, classname, cls.__dict__)
/usr/local/lib/python2.7/dist-packages/sqlalchemy/engine/default.py:330: Warning: Field 'id' doesn't have a default value
 cursor.execute(statement, parameters)

What is the problem here? I tried to run tests with nose and pydev runners and get same errors. Then I tried to move database tables creation in __init__.py in some_package under unit_tests but I could not get it working. Also, I`m confused about how python import works. For example if I add Foo import in TestBar class I also get errors similar to that that I have shown already. How can I run many unit tests that test SQLAlchemy classes, all at once?

So to extract most important questions again :

  1. How to structure python project that uses SQLAlchemy declarative style and unittests correctly. BTW I have many class methods in Foo and Bar that interact with database, in context of their respective classes, I hope that is OK?
  2. Where to store Base declarative class and how to properly use it in whole project, and how to extract all database schema (that I defined declaratively in my classes) anywhere in project and use it?
  3. How to best use unit tests with SQLAlchemy and run multiple unittests at once?
  4. If u have any other suggestions feel free to add it?

Thank you very much for the help.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

腹黑女流氓 2025-01-11 01:36:45

快速回答(抱歉,时间不够):使用单个 MetaData 实例,而不是 Foo 和 Bar 都使用一个实例。一般来说,多个 MetaData 实例是一种您几乎不需要的高级技巧。

Quick answer (lack of time, sorry): use a single MetaData instance instead of having one for both Foo and Bar. In general multiple MetaData instances is an advanced trick that you almost never need.

寄风 2025-01-11 01:36:45

后面是 zzzeek 的评论,是架构/模型的文件“__init__.py”可以使用包来代替常规的 Python 文件。它适用于 SQLAlchemy 1.4.32。

Following by zzzeek's comment, a file "__init__.py" of the schema/model package can be used, instead of regular Python file. It works on SQLAlchemy 1.4.32.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文