当使用Pony ORM或sqlalchemy时,在哪里创建数据库对象



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

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

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

这给我留下了一个问题:在"真实"项目中,我应该在哪里创建数据库对象

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

一些示例代码:

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

my_orm/init.py

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

my_orm/pers.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。那么我该怎么办呢?

有几种方法可以组织代码。

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

对于中小型项目来说,这是一种方便的方式。这是最简单的,也许你可以这样开始。您可以在实体定义之前在此文件中定义Database对象:

型号.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的几个不同实例,这可能会很有用

型号.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这样的属性的代码完成提供建议。

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

型号1.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)

型号2.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-多个模型文件

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

文件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()

相关内容

最新更新