我开始使用Object Relational Mappers(特别是 Pony ORM )玩。
在 Pony 中,所有实体定义都继承自db.Entity
类。但是,为了做到这一点,当然需要首先在某个地方创建db
对象。 (db.Entity
与 sqlalchemy 中的声明性基础有些相似,所以我相信下面的问题对 sqlalchemy 也同样有效)
我在Pony ORM文档中看到的所有示例都是内联的示例,其中在声明实体之前,只需在解释器提示中声明数据库对象db
。
这给我留下了一个问题:我应该在“真实”项目中的什么地方创建数据库对象?
特别考虑以下情况:我要将实体定义与实际使用这些实体的位置分开(例如,我只想构建一个不错的ORM包装程序包来访问数据库,然后应在多个其他项目中使用该程序包) )。然后,我可能希望用户提供自己的db
对象,该对象根据他们的需要进行配置以便访问数据库。
说我有一个存储个人和地址的数据库,我的软件包my_orm
应该为数据库提供一个ORM,然后将其用于{ {1}}:
my_orm / 初始化 .py
app.py
my_orm / person.py:
from my_orm.person import Person
from my_orm.address import Address
my_orm / address.py:
from pony.orm import Required
class Person(db.Entity): # Where should `db` be defined?
name = Required(str)
age = Required(int)
app.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)
除了看起来很丑陋,因为它混合了导入和db的创建,这还会引发错误from pony.orm import Database
db = Database()
import my_orm
。那我该怎么办呢?
答案 0 :(得分:2)
有几种组织代码的方法。
这是用于中小型项目的便捷方法。这是最简单的方法,也许您可以以此方式开始。您可以在实体定义之前在此文件中定义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)[:]
这种方法很简单,适合中型项目,您可以从它开始
如果您要在同一程序中连接到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
之类的属性的代码完成提供建议。
还可以在从不同文件导入的多个函数之间拆分entiti定义:
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)[:]
这可能是矫kill过正,但是当在应用程序启动后动态定义确切的实体集时,有时可以用于可插拔体系结构。
您可以遵循我在相应答案中描述的架构: PonyORM - multiple model files
答案 1 :(得分:1)
您可以使用元类来定义实体。
文件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()