【问题标题】:When using Pony ORM or sqlalchemy, where to create Database object?使用 Pony ORM 或 sqlalchemy 时,在哪里创建数据库对象?
【发布时间】:2018-12-12 17:53:40
【问题描述】:

我开始玩一些对象关系映射器(Pony ORM)。

Pony 中,所有实体定义都继承自 db.Entity 类。然而,为了做到这一点,db 对象当然需要先在某个地方创建。 (db.Entity 有点类似于 sqlalchemy 中的声明性基础,所以我相信我下面的问题对于 sqlalchemy 也同样有效)

我在 Pony ORM 文档中看到的所有示例都显示了内联示例,其中数据库对象 db 只是在声明实体之前在解释器提示中声明。

这给我留下了一个问题:我应该在“真实”项目中的哪里创建我的 db 对象?

特别考虑我想将我的实体定义与我实际使用这些实体的位置分开的情况(比如我只想构建一个不错的 ORM 包装器包来访问数据库,然后应该在多个不同的其他项目中使用它)。然后我可能希望用户提供自己的 db 对象,该对象根据他们的需要进行配置,以便访问数据库。

一些示例代码:

假设我有一个存储 personsaddresses 的数据库,我的包 my_orm 应该为数据库提供 ORM,然后将在 app.py 中使用:

my_orm/init.py

from my_orm.person import Person
from my_orm.address import Address

my_orm/person.py:

from pony.orm import Required

class Person(db.Entity): # Where should `db` be defined?
    name = Required(str)
    age = Required(int)

my_orm/address.py:

from pony.orm import Required

class Address(db.Entity): # Where should `db` be defined?. Must be the same `db` object as in person.py
    street_name = Required(str)
    zip_code = Required(int)

app.py

from pony.orm import Database
db = Database()
import my_orm

除了看起来很丑,因为它将导入与数据库的创建混合在一起,这也会引发错误NameError: name 'db' is not defined。那我应该怎么做呢?

【问题讨论】:

    标签: python orm sqlalchemy ponyorm


    【解决方案1】:

    有几种组织代码的方法。

    1。将所有实体放在一个文件中

    这是简单和中型项目的便捷方式。这是最简单的,可能你可以这样开始。您可以在实体定义之前在此文件中定义 Database 对象:

    models.py

    from pony.orm import Database, Required, Optional
    
    db = orm.Database()
    
    class Person(db.Entity):
        name = Required(str)
        addresses = Set('Address') # or Set(lambda: Address)
    
    class Address(db.Entity):
        street_name = Required(str)
        persons = Set('Person')
    

    main.py

    from models import db, Person, Address
    from settings import db_params
    from pony.orm import db_session, select
    
    db.bind(**db_params)
    db.generate_mapping(create_tables=True)
    
    with db_session:
        persons = select(p for p in Person if p.age > 20)[:]
    

    这种方式简单,适合中型项目,可以入手

    2。在函数内定义实体

    如果您想在同一程序中连接到多个不同的 Database 实例,这可能会很有用

    models.py

    from pony.orm import Required, Optional
    
    def define_entities(db):
        class Person(db.Entity):
            name = Required(str)
            addresses = Set('Address')
    
        class Address(db.Entity):
            street_name = Required(str)
            persons = Set('Person')
    

    main.py

    from models import define_entities
    from settings import db_params
    from pony.orm import Database, db_session, select
    
    db = Database()
    define_entities(db)
    db.bind(**db_params)
    db.generate_mapping(create_tables=True)
    
    with db_session:
        persons = select(p for p in db.Person if p.age > 20)[:]
    

    请注意,可以将实体类作为数据库对象的属性进行访问:db.Person。这可能很方便,因为不需要导入Person 实体——访问db 对象就足够了。缺点是像 PyCharm 这样的 IDE 不理解 db.Person 是什么,也不提供像 Person.name 这样的属性的代码完成建议。

    也可以在从不同文件导入的几个函数之间拆分实体定义:

    models1.py

    from pony.orm import Required, Optional
    
    def define_entities(db):
        class Person(db.Entity):
            name = Required(str)
            addresses = Set('Address') # or: Set(lambda: db.Address)
    

    models2.py

    from pony.orm import Required, Optional
    
    def define_entities(db):
        class Address(db.Entity):
            street_name = Required(str)
            persons = Set('Person')  # or: Set(lambda: db.Person)
    

    main.py

    import models1, models2
    from settings import db_params
    from pony.orm import Database, db_session, select
    
    db = Database()
    models1.define_entities(db)
    models2.define_entities(db)
    db.bind(**db_params)
    db.generate_mapping(create_tables=True)
    
    with db_session:
        persons = select(p for p in db.Person if p.age > 20)[:]
    

    这可能有点矫枉过正,但有时可用于可插拔架构,即在应用程序启动后动态定义确切的实体集。

    3。在单独的文件中定义实体(不在函数内部)

    您可以遵循我在相应答案中描述的架构: PonyORM - multiple model files

    【讨论】:

      【解决方案2】:

      您可以使用元类来定义实体。

      文件 1:

      class LazyEntityMeta(type):
          def __new__(mcs, name, bases, attrs):
              entity = mcs._entities[name] = LazyEntity(bases, attrs)
              return entity
      
          @classmethod
          def attach(mcs, db):
              for name, lazy in mcs._entities.items():
                  lazy.entity = type(name, lazy.bases + (db.Entity,), attrs)
      
          _entities = {}
      
      class LazyEntity:
          def __init__(self, bases, attrs):
              self.bases = bases
              self.attrs = attrs
      

      文件 2:

      class A(metaclass=LazyEntityMeta):
          id = PrimaryKey(int, auto=True)
      

      文件 3:

      db = Database()
      
      LazyEntityMeta.attach(db)
      db.bind('sqlite', ':memory:')
      db.generate_mapping(create_tables=True)
      
      with db_session:
          a1 = db.A()
          a2 = A.entity()
      

      【讨论】:

        猜你喜欢
        • 2014-08-31
        • 1970-01-01
        • 1970-01-01
        • 2020-02-14
        • 1970-01-01
        • 2019-01-06
        • 1970-01-01
        • 2011-01-02
        • 1970-01-01
        相关资源
        最近更新 更多