0

我在 Flask 应用程序中有一个简单的订阅和订阅者表/模型关系,我在开发过程中使用 SQLAlchemy 在本地查询 SQLite 数据库。

订阅通过subscriber_id如下定义的字段与订阅者建立关系:

subscriber_id = Column(db.Integer, ForeignKey('subscriber.id'))

这两个对象都有一个字段,定义为String(36)在数据库中创建它们时我将 UUID4 字符串写入其中。它们分别是subscription_idsubscriber_id,如下所示:

@dataclass
class Subscription(db.Model):
    __tablename__ = 'subscription'

    subscription: str
    subscriber: str

    id = Column(db.Integer, primary_key=True)
    subscription_id = Column(
        db.String(36),
        default=generate_uuid,  # a function that returns a uuid4
        unique=True
    )
    subscriber_id = Column(db.Integer, ForeignKey('subscriber.id'))

在使用 PyTest 执行测试期间,我遇到了一个奇怪的行为,其中subscriber_id实例Subscription的返回不是类中定义的整数,而是一个 UUID。

该测试运行一个查询订阅者的方法,然后尝试获取其订阅:

subscriber = Subscriber.query.filter(
    Subscriber.subscriber_id == subscriber_id
).first()

assert subscriber is not None

subscriptions = Subscription.query.filter(
    Subscription.subscriber_id == subscriber_id
).all()

subscriber_id1在执行期间,并且从数据库中检索订阅者。

然而,第二个查询不起作用,即使它subscriber_id是订阅者的外键id

如果我用另一个没有过滤器的查询替换第二个查询,它可以工作。但是后来我看到了这个问题,subscriber_id返回的不是整数,而是 UUID:

raise Exception(Subscription.query.first().subscriber_id)
        subscriptions = Subscription.query.filter(
            Subscription.subscriber_id == subscriber_id
        ).all()
    
>       raise Exception(Subscription.query.first().subscriber_id)
E       Exception: 59ebfdd6-1cbc-4748-94e1-955ef55c380c

是否有我在这里没有考虑到的 SQLAlchemy 的特殊行为?可能是表/字段的命名约定?

4

1 回答 1

1

与 SQLite 一样美妙的是,它有两个特性使其与大多数其他 SQL 实现完全“不同”:

  1. SQLite 不严格执行列类型,它只识别列"affinities"。因此,可以将列声明为INT,将字符串(如 UUID 的字符串表示形式)插入其中,SQLite 不一定会引发错误。

  2. SQLite 接受外键约束声明,但默认忽略它们。在使用 SQLite 并期望外键“正常工作”时,这可能会导致混淆。

这两种行为都对这个问题起作用。将 (UUID) 字符串插入到原本是整数的列中时出现了编码错误,并且没有强制执行外键约束导致该错误被忽视。

道德:使用 SQLite 并欣赏它所能提供的东西,但也要注意它的特殊“个性”(就像任何其他 SQL 方言一样)。

于 2020-12-23T01:16:01.553 回答