【问题标题】:Peewee created new a entry successfully but lost the foreign-key value from select() queryPeewee 成功创建了一个新条目,但从 select() 查询中丢失了外键值
【发布时间】:2020-01-12 15:32:47
【问题描述】:

Python 版本 3.6.8, peewee 版本 3.10.0

我使用 peewee 在 sqlite 数据库中设置了 3 个表。

Plan:
- id : int (primary key)
- plan_name : varchar (unique)
- status : int (foreign key for PlanStatus)
- category : int (foreign key for PlanCategory)

PlanStatus:
- id : int (primary key)
- value : varchar (unique)

PlanCategory:
- id : int (primary key)
- value : varchar (unique)

PlanStatus 是一个枚举引用表,PlanCategory 是另一个枚举引用表。在下面的代码中,PlanStatus 天真地实现了许多样板文件,这些样板文件必须为每个其他枚举表复制。 相比之下,PlanCategory 继承自父类 EnumBaseModel,包括 2 个类方法。目标是通过继承减少样板。

结果是两个枚举表都已成功填充,您可以通过查询访问它们中的值。但是,在创建计划条目时,会在数据库中添加一行(在 sqlite 中检查),但选择查询会返回缺少 PlanCategory 外键值的行。

创建表格并添加行:

from peewee import *

DATABASE = SqliteDatabase('test.db')

# Base class with the inner Meta class defined
class BaseModel(Model):
    class Meta:
        database = DATABASE

# PlanStatus class, used with the following 2 methods
class PlanStatus(BaseModel):
    value = CharField(unique=True)

# Helper function for PlanStatus
def init_plan_status_values(values):
    for value in values:
        if not PlanStatus.select().where(PlanStatus.value == value).exists():
            PlanStatus.create(value=value)

# Helper function for PlanStatus
def get_plan_status(value):
    try:
        return PlanStatus.get(PlanStatus.value == value)
    except DoesNotExist as err:
        return None

# Base class with 2 classmethods
class EnumBaseModel(BaseModel):
    value = CharField(unique=True)

    @classmethod
    def init_values(cls, values):
        for value in values:
            if not cls.select().where(cls.value == value).exists():
                cls.create(value=value)

    @classmethod
    def get(cls, value):
        try:
            return cls.select().where(cls.value == value).get()
        except DoesNotExist as err:
            return None

# PlanCategory inherits EnumBaseModel class and its 2 classmethods
class PlanCategory(EnumBaseModel):
    pass

# Plan has 2 foreign keys
class Plan(BaseModel):
    plan_name = CharField(unique=True)
    status = ForeignKeyField(model=PlanStatus, backref='plans')
    category = ForeignKeyField(model=PlanCategory, backref='plans')

DATABASE.connect()
DATABASE.create_tables(
    [
        PlanStatus,
        PlanCategory,
        Plan
    ],
    safe=True
)

# Populating the enum values PlanStatus the explicit way above
init_plan_status_values(('STATUS-1', 'STATUS-2', 'STATUS-3'))

# Find status_2 the explicit way above
status_2 = get_plan_status('STATUS-2')

# Populating the enum values in PlanCategory using the inherited classmethod above
PlanCategory.init_values(('CATEGORY-1', 'CATEGORY-2', 'CATEGORY-3'))

# Find category_3 using the inherited classmethod above
category_3 = PlanCategory.get('CATEGORY-3')

# Add one plan
try:
    Plan.create(
        plan_name='not bad plan',
        status=status_2,
        category=category_3,
    )
except IntegrityError as err:
    print(err)

现在我们看到在 sqlite3 中成功添加了行:

SQLite version 3.22.0 2018-01-22 18:45:57
Enter ".help" for usage hints.
sqlite> .tables
plan          plancategory  planstatus
sqlite> select * from planstatus;
1|STATUS-1
2|STATUS-2
3|STATUS-3
sqlite> select * from plancategory;
1|CATEGORY-1
2|CATEGORY-2
3|CATEGORY-3
sqlite> select * from plan;
1|not bad plan|2|3
sqlite>

现在检查 select() 查询中的计划条目,'a_plan.status' 是有效的,但 'a_plan.category' 是 None。

# We see the references status_2 and category_3 are valid
print('status_2 = ', type(status_2), status_2, status_2.value)
print('category_3 = ', type(category_3), category_3, category_3.value)
print()

# We check the one plan in the table and see now the foreign-key value "category" is missing
a_plan = Plan.get()
print('a_plan: plan_name={}, status={}, category={}'.format(
    a_plan.plan_name,
    a_plan.status,
    a_plan.category
))
print()

打印结果:

status_2 =  <Model: PlanStatus> 2 STATUS-2
category_3 =  <Model: PlanCategory> 3 CATEGORY-3

a_plan: plan_name=not bad plan, status=2, category=None

另外,我发现了 peewee 创建的属性 'status_id' 和 'category_id'。至少 'category_id' 仍然保留外键 int 值。

# After inspecting dir(a_plan), found these attributes:
print('status = ', type(a_plan.status), a_plan.status)
print('status_id = ', type(a_plan.status_id), a_plan.status_id)
print('category = ', type(a_plan.category), a_plan.category)
print('category_id = ', type(a_plan.category_id), a_plan.category_id)

打印结果:

status =  <Model: PlanStatus> 2
status_id =  <class 'int'> 2
category =  <class 'NoneType'> None
category_id =  <class 'int'> 3

有什么办法可以解决这个问题,以便解决“a_plan.category”?

【问题讨论】:

    标签: python python-3.x sqlite peewee


    【解决方案1】:

    您正在覆盖 Peewee 使用的方法 (.get)。不要那样做!我认为你让事情变得太神奇了(并且在整个过程中引入了查询)。

    尝试简化。我几乎可以保证问题出在您对 Peewee 所依赖的类方法所做的覆盖中。

    【讨论】:

    • 哇,原来如此!我将我的类方法重命名为 get_value,现在一切正常!谢谢你,先生!你救了我!
    猜你喜欢
    • 1970-01-01
    • 2012-02-08
    • 1970-01-01
    • 2017-07-07
    • 2020-01-03
    • 2016-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多