#python #sqlalchemy
#python #sqlalchemy
Вопрос:
У меня есть приложение Flask SQLAlchemy с User
моделью. Я хочу применить эту бизнес-логику: первым User
созданным в приложении должен быть администратор (т.Е. Поле is_admin=True
), но все остальные пользователи по умолчанию не должны быть администраторами.
Модель выглядит примерно так (упрощенно):
class User(db.Model):
__tablename__ = "users"
user_id = Column(Integer, primary_key=True)
username = Column(UnicodeText, unique=True, nullable=False)
email = Column(UnicodeText, unique=True, nullable=False)
password = Column(UnicodeText, nullable=True)
is_admin = Column(Boolean(), default=False)
И я хочу, чтобы этот тестовый пример был успешным:
first = User(username="foo", email="foo@foo.com", password="foobarbaz123")
second = User(username="bar", email="bar@bar.com", password="foobarbaz123")
db.session.add_all([first, second])
db.session.commit()
assert first.is_admin
assert not second.is_admin
Я попробовал несколько подходов:
- Поместите эту бизнес-логику в сам маршрут API. У этого есть основной недостаток, заключающийся в том, что он не интегрирован в уровень модели, поэтому его легко обойти, и вам нужно поддерживать эту функциональность в нескольких местах.
- Поместите эту логику в конструктор модели, например
def __init__(self): user_count = db.session.query(User).count() if user_count == 0: self.is_admin = True
Это не работает, потому что мы не можем предположить, что у нас всегда есть доступ к сеансу базы данных. Например, при построении тестовых данных потребуется обращение к базе данных, когда данные находятся в нестабильном состоянии.
- Поместите эту логику в
after_insert
событие, например@event.listens_for(User, 'after_insert') def receive_after_insert(mapper, connection, target): user_count = db.session.query(User).count() if user_count == 0: target.is_admin = True
Однако это не проходит тестовый пример, потому что, похоже, он обновляет модель асинхронно.
Как можно реализовать эту бизнес-логику?
Комментарии:
1. могу я спросить «почему» вы пытаетесь реализовать это таким образом? Особенно после того, как вы сами нашли его, есть так много недостатков или препятствий для того, чтобы сделать это таким образом . И что должно произойти, если этот первый пользователь будет удален из базы данных? Должен ли другой быть назначен администратором? Какой из них?
2. Я не совсем понимаю. У меня есть некоторая логика, которую мне нужно реализовать, но я не знаю, как ее реализовать. Я не пытаюсь реализовать это каким-либо конкретным способом, метод — это то, о чем я спрашиваю.
3. Привет @Migwell. Я не думаю, что существует «лучшее» решение для вашего вопроса, но было бы очень любопытно узнать, как вы решили это сделать и почему. Спасибо.
4. Единственный (более) надежный способ, которым, на мой взгляд, это можно сделать, — это установить
AFTER INSERT
триггер на уровне базы данных, который установилis_admin
быTRUE
значение, если это первая (единственная) запись в базе данных.