Python 使模型的第一个实例在SQLAlchemy中具有唯一的字段

Python 使模型的第一个实例在SQLAlchemy中具有唯一的字段,python,sqlalchemy,Python,Sqlalchemy,我有一个Flask+SQLAlchemy应用程序,带有用户模型。我想强制执行这个业务逻辑:在应用程序中创建的第一个用户应该是管理员(即有字段is_admin=True),但默认情况下,所有其他用户都不应该是管理员 该模型看起来像这样(简化): 类用户(db.Model): __tablename_=“用户” 用户标识=列(整数,主键=真) username=Column(unicodext,unique=True,nullable=False) email=Column(unicodext,un

我有一个Flask+SQLAlchemy应用程序,带有
用户
模型。我想强制执行这个业务逻辑:在应用程序中创建的第一个
用户
应该是管理员(即有
字段is_admin=True
),但默认情况下,所有其他用户都不应该是管理员

该模型看起来像这样(简化):

类用户(db.Model):
__tablename_=“用户”
用户标识=列(整数,主键=真)
username=Column(unicodext,unique=True,nullable=False)
email=Column(unicodext,unique=True,nullable=False)
password=Column(unicodext,nullable=True)
is_admin=Column(Boolean(),默认值=False)
我希望这个测试用例能够成功:

first=User(username=“foo”,email=”foo@foo.com,password=“foobarbaz123”)
第二个=用户(username=“bar”,email=”bar@bar.com,password=“foobarbaz123”)
db.session.add_all([第一,第二])
db.session.commit()
assert first.is_admin
assert not second.is_admin

我尝试了几种方法:

  • 将此业务逻辑放在API路由本身中。这有一个主要的缺点,即它没有集成在模型层中,因此很容易绕过,并且您必须在多个地方维护此功能
  • 将此逻辑放入模型构造函数中,例如。
    def\uuuu初始化(自):
    user\u count=db.session.query(user.count)()
    如果用户计数=0:
    self.is_admin=True
    
    这是行不通的,因为我们不能假设我们可以随时访问数据库会话。例如,在构建测试数据时,它将涉及在数据处于不稳定状态时命中数据库
  • 将此逻辑放入事件中,例如。
    @event.listens\u for(用户'after\u insert')
    def在插入后接收(映射器、连接、目标):
    user\u count=db.session.query(user.count)()
    如果用户计数=0:
    target.is_admin=True
    
    但是,这并没有通过测试用例,因为它似乎是异步更新模型的

如何实现这种业务逻辑?

我可以问一下“为什么”您要以这种方式实现它吗?尤其是在你自己发现了它之后,用这种方式做有很多缺点或障碍。如果第一个用户从数据库中删除,会发生什么?另一个应该被提升为管理员吗?哪一个?我不太明白。我有一些需要实现的逻辑,但不知道如何实现。我没有试图以任何特定的方式实现它,方法就是我要问的。嗨@Migwell。我不认为对你的问题有“最佳”的解决方案,但我很想知道你是怎么决定的,为什么。谢谢。我认为唯一(更)防弹的方法是在数据库级别上有一个
AFTER INSERT
触发器,如果这是数据库中的第一条(唯一)记录,它会将
is_admin
设置为
TRUE