如何在单独的模块中管理peewee数据库?

我希望将我的数据库实现放在一个单独的模块或类中.但我正在努力解决一些细节问题.一个简单的例子:

from peewee import *

db = SqliteDatabase(':memory:')

class BaseModel(Model):
    class Meta:
        database = db

class User(BaseModel):
    name = CharField()

db.connect()
db.create_tables([User,])
db.commit()

@db.atomic()
def add_user(name):
    User.create(name=name).save()

@db.atomic()
def get_user(name):
    return User.get(User.name == name)

到目前为止,这工作正常.我可以在这里实现我的数据库接口并将其作为模块导入.

现在我希望能够在运行时选择数据库文件.所以我需要一种方法来定义Model类,而不需要先定义SqliteDatabase(‘somefile’).我试图将所有内容封装在一个新的Database类中,稍后我可以从中导入并创建一个实例:

from peewee import *

class Database:

    def __init__(self, dbfile):
        self.db = SqliteDatabase(dbfile)

        class BaseModel(Model):
            class Meta:
                database = self.db

        class User(BaseModel):
            name = CharField()

        self.User = User

        self.db.connect()
        self.db.create_tables([User,])
        self.db.commit()

    @self.db.atomic()    # Error as self is not known on this level
    def add_user(self, name):
        self.User.create(name=name).save()

    @self.db.atomic()    # Error as self is not known on this level
    def get_user(self, name):
        return self.User.get(self.User.name == name)

现在我可以调用例如database = Database(‘database.db’)或选择任何其他文件名.我甚至可以在同一个程序中使用多个数据库实例,每个实例都有自己的文件.

但是,这种方法存在两个问题:

>在定义Model类之前,我仍然需要指定数据库驱动程序(SqliteDatabase).为了解决这个问题,我在__init __()方法中定义了Model类,然后使用self.User = User创建了一个别名.我真的不喜欢这种方法(它只是感觉不像整洁的代码),但至少它是有效的.
>我不能使用@ db.atomic()装饰器,因为在类级别不知道self,我会在这里做一个实例.

因此,这种类方法似乎不能很好地工作.有没有更好的方法来定义Model类,而不必先选择存储数据库的位置?

最佳答案 如果您需要在运行时更改数据库驱动程序,那么
Proxy是一种可行的方法

# database.py
import peewee as pw

proxy = pw.Proxy()

class BaseModel(pw.Model):
  class Meta:
    database = proxy

class User(BaseModel):
  name = pw.CharField()

def add_user(name):
  with proxy.atomic() as txn:
    User.create(name=name).save()

def get_user(name):
  with proxy.atomic() as txn:
    return User.get(User.name == name)

从现在开始,每次加载模块时,都不需要初始化数据库.相反,您可以在运行时初始化它,并在多个之间切换,如下所示

# main.py

import peewee as pw
import database as db

sqlite_1 = pw.SqliteDatabase('sqlite_1.db')
sqlite_2 = pw.PostgresqlDatabase('sqlite_2.db')

db.proxy.initialize(sqlite_1)
sqlite_1.create_tables([db.User], safe=True)
db.add_user(name="Tom")

db.proxy.initialize(sqlite_2)
sqlite_2.create_tables([db.User], safe=True)
db.add_user(name="Jerry")

但如果连接是唯一重要的事情,那么init()方法就足够了.

点赞