atom对象的数据库抽象层
atom-db的Python项目详细描述
Atom DB是 atom框架。这个包提供了 从基于json的文档数据库无缝保存和恢复atom对象 以及(即将推出)sqlalchemy支持的sql数据库。
为什么?
构建此数据库的主要原因是为了简化数据库集成 使用enaml应用程序。没有这个, 需要一个单独的框架来定义数据库模型,它是 重复工作。
这原本是enaml-web的一部分 但已被单独打包。
结构
这个设计有点基于django。使用Model.objects
检索
用于创建查询的对象类型的管理器。不
对使用哪种类型的管理器进行了限制,将其留给
首选哪个数据库库(例如motor、txmongo、sqlalchemy…)。
除了Model.objects
之外,序列化程序还作为
Model.serializer
用于序列化和反序列化对象
到数据库和从数据库。
使用MongoDB和Motor
的示例只需使用atom成员定义模型,但要对nosqlmodel进行子类化。
fromatom.apiimportUnicode,Int,Instance,Listfromatomdb.nosqlimportNoSQLModel,NoSQLModelManagerfrommotor.motor_asyncioimportAsyncIOMotorClient# Set DBclient=AsyncIOMotorClient()mgr=NoSQLModelManager.instance()mgr.database=client.test_dbclassGroup(NoSQLModel):name=Unicode()classUser(NoSQLModel):name=Unicode()age=Int()groups=List(Group)
然后我们可以创建一个实例并保存它。它将执行upsert或replace 现有条目。
admins=Group(name="Admins")awaitadmins.save()# It will save admins using it's ObjectIDbob=User(name="Bob",age=32,groups=[admins])awaitbob.save()tom=User(name="Tom",age=34,groups=[admins])awaittom.save()
要从数据库中获取数据,每个模型都有一个名为ModelManager
的objects
的
只需返回模型类型的集合。例如。
# Fetch from db, you can use any MongoDB queries herestate=awaitUser.objects.find_one({'name':"James"})ifstate:james=awaitUser.restore(state)# etc...
还原是异步的,因为它将自动获取任何相关对象 (不包括本例中的组)。它在存在时使用objectid保存对象。
最后,您可以直接使用管理器上的查询删除,或者 调用对象。
awaittom.delete()assertnotawaitUser.objects.find_one({'name':"Tom"})
通过标记成员,可以将其从保存到数据库中排除
用.tag(store=False)
。
带aiomysql/aiopg的sql
只需使用atom成员定义模型,但要对sqlmodel进行子类化。
使用sqlalchemy表所需的信息标记成员,例如
Str().tag(length=40)
将生成一个sa.String(40)
。
见https://docs.sqlalchemy.org/en/latest/core/type_basics.html。标记
store=False
将使该成员从数据库中排除。
atomdb将尝试确定正确的列类型,但如果需要更多
控件,可以标记成员以指定列类型。
type=sa.<type>
或使用
column=sa.Column(...)
。有关示例,请参见测试。
可以用primary_key=True
标记成员,使其成为pk。Atomdb将
查找这些并将其分配给类的__pk__
。如果未指定
它将创建并使用_id
作为主键。如果指定了其他成员
作为主键,_id
成员将被重新定义为实际主键的别名。
通过设置__model__ = "<table name>"
,可以通过
默认情况下,它使用类的fqdn。
DB发动机
在访问数据库之前,必须将“数据库引擎”分配给管理器 这样地。
importrefromaiomysql.saimportcreate_enginefromatomdb.sqlimportSQLModelManager# Parse the DB urlm=re.match(r'mysql://(.+):(.*)@(.+):(\d+)/(.+)',DATABASE_URL)user,pwd,host,port,db=m.groups()# Create the engineengine=awaitcreate_engine(db=db,user=user,password=pwd,host=host,port=port)# Assign it to the managermgr=SQLModelManager.instance()mgr.database=engine
然后,管理器将使用它来执行查询。
表格创建/删除
将表定义为Atom模型后,使用 sqlalchemy引擎上的异步包装器。
fromatomdb.sqlimportSQLModel,SQLModelManager# Call create_tables to create sqlalchemy tables. This does NOT write them to# the db but ensures that all ForeignKey relations are createdSQLModelManager.instance().create_tables()# Now actually drop/create for each of your models# Drop the table for this model (will raise sqlalchemy's error if it doesn't exist)awaitUser.objects.drop()# Create the user tableawaitUser.objects.create()
类似orm的查询
只有非常基本的orm风格的查询才被实现用于常见的用例。这些
分别是get
、get_or_create
、filter
和all
。这些都接受
“django样式”查询使用<name>=<value>
或<name>__<op>=<value>
。
例如:
john,created=awaitUser.objects.get_or_create(name="John Doe",email="jon@example.com",age=21,active=True)assertcreatedjane,created=awaitUser.objects.get_or_create(name="Jane Doe",email="jane@example.com",age=48,active=False,rating=10.0)assertcreated# Startswithu=awaitUser.objects.get(name__startswith="John")assertu.name==john.name# In queryusers=awaitUser.objects.filter(name__in=[john.name,jane.name])assertlen(users)==2# Is queryusers=awaitUser.objects.filter(active__is=False)assertlen(users)==1andusers[0].active==False
见sqlachemy's ColumnElement 可以用这种方式使用的查询。测试还检查这些 实际按计划工作。
高级/原始查询
使用连接等进行更高级的查询。必须使用
然后执行sqlalchemy。可以检索原子模型的sa.Table
使用Model.objects.table
可以在其上使用select、where等…建造
提出你需要的任何问题。
然后使用fetchall
、fetchone
、fetchmany
或execute
进行查询。
这些方法不返回对象,而是返回数据库,所以他们 必须手动还原。
加入时,您通常希望通过use_labels=True
。例如:
q=Job.objects.table.join(JobRole.objects.table).select(use_labels=True)forrowinawaitJob.objects.fetchall(q):# Restore each manually, it handles pulling out the fields that are it's ownjob=awaitJob.restore(row)role=awaitJobRole.restore(row)
根据这些关系,您可能需要对它们进行后期处理,以便 可以用更像Python的方式访问。这是复杂的权衡。 使用方便。
贡献
这是早期的发展,可能有问题。拉取请求, 功能要求,欢迎!