模块化Peewee

4
假设我有一些简单模型存在于food.py文件中:
import peewee as pw

db = pw.SqliteDatabase('food.db')

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

class Taco(BaseModel):
    has_cheese = pw.BooleanField()

class Spaghetti(BaseModel):
    has_meatballs = pw.BooleanField()

db.connect()

# populate with some data if table doesn't exist
from random import random
if not Taco.table_exists():
    db.create_table(Taco)
    for _ in range(10):
        Taco.create( has_cheese = (random() < 0.5) )
    db.commit()
if not Spaghetti.table_exists():
    db.create_table(Spaghetti)
    for _ in range(10):
        Spaghetti.create( has_meatballs = (random() < 0.5) )
    db.commit()

接下来,我有food.pyfood.db。但是假设和模型变得越来越大且复杂,因此我想将它们拆分成不同的文件。具体而言,我想在我的PYTHONPATH中创建一个food文件夹,其典型层次结构如下:

food/
    - __init__.py
    - BaseModel.py
    - Taco.py
    - Spaghetti.py
    - db/
        - food.db

我想把模型放到它们各自的 .py 文件中,并创建一个类似以下的 __init__.py 文件:

import peewee as pw

db = pw.SqliteDatabase('./db/food.db')

from . import BaseModel
from . import Taco
from . import Spaghetti

db.connect()

然而,这显然行不通,因为 BaseModel.py 无法访问 db。如果可能以这种方式模块化多个peewee模型,正确的方法是什么?

3个回答

5
显然,关键是在BaseModel.py文件中连接到数据库。我将提供模块内容的完整概述。假设顶层文件夹命名为food,并位于PYTHONPATH中。最后假设food.db存在于food/db/food.db中,并已填充(例如,正如问题中第一个代码块底部所示)。
以下是模块文件:

__init__.py

from Taco import Taco
from Spaghetti import Spaghetti

BaseModel.py

import peewee as pw
db = pw.SqliteDatabase('/abs/path/to/food/db/food.db')

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

Taco.py

import peewee as pw
from BaseModel import BaseModel

class Taco(BaseModel):
    has_cheese = pw.BooleanField()

Spaghetti.py

import peewee as pw
from BaseModel import BaseModel

class Spaghetti(BaseModel):
    has_meatballs = pw.BooleanField()

现在,例如,您可以编写一个脚本(当然,它应该位于模块文件夹外面),如下所示:

main.py

import food

for t in food.Taco.select():
    print "Taco", t.id, ("has" if t.has_cheese else "doesn't have"), "cheese"

产生:

Taco 1 has cheese
Taco 2 has cheese
Taco 3 has cheese
Taco 4 doesn't have cheese
Taco 5 doesn't have cheese
Taco 6 has cheese
Taco 7 has cheese
Taco 8 has cheese
Taco 9 doesn't have cheese
Taco 10 doesn't have cheese

我已经尝试了模块化,但当我没有任何外键时它可以工作,因为它会抱怨循环导入。如果我有外键,我该如何进行模块化呢? - Isaac Obella
这里是我在处理循环依赖时卡住的地方:BaseModel 需要 db | db.create_tables() 需要 Models | Models 需要 BaseModel... 而 BaseModel 又需要 db。 - Kermit

0
您在路径中遇到了问题:
__location__ = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__)))
db = pw.SqliteDatabase(os.path.join(__location__, 'db/food.db'));

也尝试实现类的__init__方法并将db作为参数传递给它:

class BaseModel(pw.Model):
    def __init__(self, db = None)
        self.database = db

比在 __init__.py 中更好:

from BaseModel import BaseModel
db = pw.SqliteDatabase('./db/food.db')
bm = BaseModel(db)

这行代码不起作用。如果我用 Taco.py 相同的方式操作,当我尝试访问模型属性时会出现 peewee.OperationalError: no such table: taco 的错误。实际上,如果我的 __init__.py 文件只包含以下内容:import peewee as pw; db = pw.SqliteDatabase('./db/food.db'); db.connect(),那么我会收到 peewee.OperationalError: unable to open database file 的错误提示。 - Matt Hancock
尝试使用 db = pw.SqliteDatabase('food/db/food.db') - Assem
我不知道你的意思。我正在将它们用作类。除非我漏掉了什么,否则这根本行不通(无论路径是否固定)。你能解释一下你的解决方案如何与__init__.py文件中的其他类文件相关联吗? - Matt Hancock
先解决路径问题,尝试使用 __location__ 了吗? - Assem
是的,这没问题。问题出现在我尝试在BaseModel之后的模型中工作时。 - Matt Hancock
显示剩余2条评论

0

我是通过谷歌看到你的帖子的!不幸的是,我没有使用Flask,所以你的方法不太适用(请参见我的答案(上面还是下面?))。我试图实现的确切事情是将模型分成单独的文件。你的方法似乎将所有模型放在一个文件中,而且不清楚每个模型文件如何共享数据库实例或者应该在哪里实例化数据库实例来完成这个操作。这就是我在上面解决的问题。谢谢! - Matt Hancock
嗨。在多个SO帖子中看到了这个链接,阅读了它,但它没有解决将每个模型/表类放入单独文件的问题,这是我认为人们想要的。我阅读了一些peewee文档来寻找答案。像https://dev59.com/ypLea4cB1Zd3GeqPyy_9#34347404这样的示例对于像我们这样的新手来说是很好的。我一直在拖延这个模块化,现在已经有了大约8K行代码,并因此受到了排斥。感谢您的一切 =) - Kermit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接