在 peewee 中跨多个数据库使用多个 M2M 关系

Using multiple M2M relationship across multiple database in peewee

我有两个 python 项目,它们维护着不同的数据库连接和 sqlite 文件。 model1.py在低级项目中,model2.py在高级项目中,使用model1.py的模型class。以下是示例代码:

model1.py

from os.path import join, dirname

from peewee import *
from playhouse.sqlite_ext import *

_db = SqliteDatabase(join(dirname(__file__), 'db1.sqlite'))

class Student(Model):
    name = CharField()
    sex = CharField()

    class Meta:
        database = _db

    def __str__(self):
        return 'student name: %s, sex: %s' % (self.name, self.sex)

_db.connect()
_db.create_tables([
    Student,
])

model2.py

from os.path import join, dirname

from peewee import *
from playhouse.sqlite_ext import *

from model1 import *

_db = SqliteDatabase(join(dirname(__file__), 'db2.sqlite'))

class Teacher(Model):
    name = CharField()
    age = IntegerField()

    sample_student = ForeignKeyField(Student, null=True, backref='sample_teacher')
    students = ManyToManyField(Student, backref='teachers')

    class Meta:
        database = _db

    def __str__(self):
        return 'teacher name: %s, age: %d' % (self.name, self.age)

_db.connect()
_db.create_tables([
    Teacher,
    Teacher.students.get_through_model(),
])

main.py

from model1 import *
from model2 import *

if __name__ == '__main__':
    Teacher.students.through_model.delete().execute()
    Teacher.delete().execute()
    Student.delete().execute()

    s1 = Student.create(name='s1', sex='male')
    s2 = Student.create(name='s2', sex='female')

    t1 = Teacher.create(name='t1', age=20)
    t1.students.add(s1)
    t1.students.add(s2)

    t1.sample_student = s1
    t1.save()

    print(t1.sample_student)  # ForeignKeyField works!

    [print(s) for s in Student.select()]
    [print(t) for t in Teacher.select()]

    for s in t1.students:    # crash here: peewee.OperationalError: no such table: teacher_student_through
        print(s)

对于tableteacher_student_through,它实际上存在于db2.sqlite数据库中。那么,这是 peewee 的错误还是我的错误用法?

我没有使用 Meta.database 的数据库对象,而是使用 数据库代理 为我的 python 包重新设计了元模型初始化。

_db_proxy = DatabaseProxy()

class PeeweeModel(Model):
    class Meta:
        database = _db_proxy

# skip the other subclass models implementation here...

def setup_database(dbpath):
    '''Initialize database.'''

    database = SqliteDatabase(dbpath)
    _db_proxy.initialize(database)

    database.connect(reuse_if_open=True)
    database.create_tables([
        Model1,
        Model2,
    ])

    return database

包调用者现在有责任初始化数据库对象,see more documentation about this

public PeeweeModel 也可用于高级 python 包来扩展数据库表,只需将其用作普通超级模型 class。