在 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。
我有两个 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。