Peewee ORM一对一关联创建实例报错TypeError:无法转换Email对象为int
Peewee一对一关联创建实例报错原因分析
问题描述
使用Peewee作为ORM定义了具有一对一关联的模型,创建Email实例成功,但创建Linkedin实例时触发类型错误:TypeError: int() argument must be a string, a bytes-like object or a real number, not 'Email'。
模型代码
def __account_model(self) -> Type[Model]: db = self.__sql_db class AccountModel(Model): password = CharField(max_length=255) is_successful_authorized = BooleanField(null=True, default=None) class Meta: database = db return AccountModel def linkedin(self) -> Type[Model]: model = self.__account_model class Linkedin(model): email = ForeignKeyField(self.email, backref='linkedin') cookies = TextField(null=True, default=None) return Linkedin def email(self) -> Type[Model]: model = self.__account_model class Email(model): login = CharField(max_length=255) return Email
实例创建代码
password, email_login, email_password, cookies = account.values() email=controller.email.create(password=email_password,login=email_login) model.create(password=password, email=email, cookies=cookies)
错误栈
Traceback (most recent call last): File "/Users/blnkoff/PycharmProjects/gitcoin-passport-bot/accounts/build_database.py", line 17, in <module> db.build([ModelType.LINKEDIN, ModelType.FACEBOOK, ModelType.GOOGLE, File "/Users/blnkoff/PycharmProjects/gitcoin-passport-bot/accounts/database.py", line 66, in build model.create(password=password, email=email, cookies=cookies) File "/Users/blnkoff/PycharmProjects/gitcoin-passport-bot/venv/lib/python3.11/site-packages/peewee.py", line 6577, in create inst.save(force_insert=True) File "/Users/blnkoff/PycharmProjects/gitcoin-passport-bot/venv/lib/python3.11/site-packages/peewee.py", line 6787, in save pk = self.insert(**field_dict).execute() ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/blnkoff/PycharmProjects/gitcoin-passport-bot/venv/lib/python3.11/site-packages/peewee.py", line 1966, in inner return method(self, database, *args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/blnkoff/PycharmProjects/gitcoin-passport-bot/venv/lib/python3.11/site-packages/peewee.py", line 2037, in execute return self._execute(database) ^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/blnkoff/PycharmProjects/gitcoin-passport-bot/venv/lib/python3.11/site-packages/peewee.py", line 2842, in _execute return super(Insert, self)._execute(database) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/blnkoff/PycharmProjects/gitcoin-passport-bot/venv/lib/python3.11/site-packages/peewee.py", line 2555, in _execute cursor = database.execute(self) ^^^^^^^^^^^^^^^^^^^^^^ File "/Users/blnkoff/PycharmProjects/gitcoin-passport-bot/venv/lib/python3.11/site-packages/peewee.py", line 3253, in execute sql, params = ctx.sql(query).query() ^^^^^^^^^^^^^^ File "/Users/blnkoff/PycharmProjects/gitcoin-passport-bot/venv/lib/python3.11/site-packages/peewee.py", line 628, in sql return obj.__sql__(self) ^^^^^^^^^^^^^^^^^ File "/Users/blnkoff/PycharmProjects/gitcoin-passport-bot/venv/lib/python3.11/site-packages/peewee.py", line 2819, in __sql__ self._simple_insert(ctx) File "/Users/blnkoff/PycharmProjects/gitcoin-passport-bot/venv/lib/python3.11/site-packages/peewee.py", line 2669, in _simple_insert return self._generate_insert((self._insert,), ctx) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/blnkoff/PycharmProjects/gitcoin-passport-bot/venv/lib/python3.11/site-packages/peewee.py", line 2791, in _generate_insert return ctx.sql(CommaNodeList(all_values)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/blnkoff/PycharmProjects/gitcoin-passport-bot/venv/lib/python3.11/site-packages/peewee.py", line 628, in sql return obj.__sql__(self) ^^^^^^^^^^^^^^^^^ File "/Users/blnkoff/PycharmProjects/gitcoin-passport-bot/venv/lib/python3.11/site-packages/peewee.py", line 1832, in __sql__ ctx.sql(self.nodes[n_nodes - 1]) File "/Users/blnkoff/PycharmProjects/gitcoin-passport-bot/venv/lib/python3.11/site-packages/peewee.py", line 628, in sql return obj.__sql__(self) ^^^^^^^^^^^^^^^^^ File "/Users/blnkoff/PycharmProjects/gitcoin-passport-bot/venv/lib/python3.11/site-packages/peewee.py", line 1830, in __sql__ ctx.sql(self.nodes[i]) File "/Users/blnkoff/PycharmProjects/gitcoin-passport-bot/venv/lib/python3.11/site-packages/peewee.py", line 628, in sql return obj.__sql__(self) ^^^^^^^^^^^^^^^^^ File "/Users/blnkoff/PycharmProjects/gitcoin-passport-bot/venv/lib/python3.11/site-packages/peewee.py", line 1430, in __sql__ return ctx.value(self.value, self.converter) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/blnkoff/PycharmProjects/gitcoin-passport-bot/venv/lib/python3.11/site-packages/peewee.py", line 640, in value value = converter(value) ^^^^^^^^^^^^^^^^ File "/Users/blnkoff/PycharmProjects/gitcoin-passport-bot/venv/lib/python3.11/site-packages/peewee.py", line 5417, in db_value return self.rel_field.db_value(value) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/blnkoff/PycharmProjects/gitcoin-passport-bot/venv/lib/python3.11/site-packages/peewee.py", line 4744, in db_value return value if value is None else self.adapt(value) ^^^^^^^^^^^^^^^^^ File "/Users/blnkoff/PycharmProjects/gitcoin-passport-bot/venv/lib/python3.11/site-packages/peewee.py", line 4804, in adapt return int(value) ^^^^^^^^^^ TypeError: int() argument must be a string, a bytes-like object or a real number, not 'Email'
报错原因
1. 父模型重复创建
__account_model方法每次调用都会生成一个全新的AccountModel类,导致Email和Linkedin继承的是完全独立的父模型类。Peewee无法识别这两个模型之间的关联关系,数据库层面也无法共享主键约束。
2. ForeignKeyField参数错误
在Linkedin模型中,ForeignKeyField(self.email, backref='linkedin')传入的是self.email方法对象,而非实际的Email模型类。Peewee无法正确解析外键关联的目标模型,插入时尝试将整个Email实例转换为整数(主键类型),从而触发类型错误。
修复方案
1. 缓存父模型类
修改__account_model,确保只生成一次父模型类:
def __init__(self): self.__cached_account_model = None # 其他初始化逻辑... def __account_model(self) -> Type[Model]: if not self.__cached_account_model: db = self.__sql_db class AccountModel(Model): password = CharField(max_length=255) is_successful_authorized = BooleanField(null=True, default=None) class Meta: database = db self.__cached_account_model = AccountModel return self.__cached_account_model
2. 修正外键字段参数
在Linkedin模型中,正确传入Email模型类(调用self.email()方法获取):
def linkedin(self) -> Type[Model]: model = self.__account_model() # 调用方法获取父模型类 class Linkedin(model): email = ForeignKeyField(self.email(), backref='linkedin') # 传入实际的Email模型类 cookies = TextField(null=True, default=None) return Linkedin
3. 修正模型继承调用
Email模型的继承也需要调用__account_model()方法,确保继承的是缓存的父模型:
def email(self) -> Type[Model]: model = self.__account_model() class Email(model): login = CharField(max_length=255) return Email
内容的提问来源于stack exchange,提问作者blnk.off
相关产品推荐
相关产品推荐

