flask-sqlachemy: нельзя заставить родителя слушать и обновлять изменения для ребенка - PullRequest
0 голосов
/ 06 ноября 2018

У меня есть тест, который я пытаюсь пройти:

@pytest.fixture(scope='function')
@pytest.mark.usefixtures('db')
def new_scan_service(db):
    user = User.create(username='Princess Leia', email='dontatme@me.com')
    date = datetime.strptime('Jun 1 2005  1:33PM', '%b %d %Y %I:%M%p')
    experiment1 = Experiment.create(date=date, scanner='GE', num_scans=2, user_id=user.id)
    experiment2 = Experiment.create(date=date, scanner='GE', num_scans=2, user_id=user.id)
    db.session.commit()
    print('I just put the user and two experiments into the database', user.num_experiments)
    s = ScanService(user.id, experiment2.id)
    return s

class TestScanUpload:

    def test_xnat_ids_correctly_generated_for_multiple_experiments_and_scans(self, new_scan_service):
        """
        Given a subject with more than one experiment, and an experiment with more than one scan
        When xnat ids are generated
        Then test that xnat_experiment_id and xnat_scan_id are as expected
        """

        with open('<file-path>', 'r') as f:
            xnat_ids = new_scan_service._generate_xnat_identifiers()
            assert xnat_ids['experiment']['xnat_id'] == '000001_MR2'

user.num_experiments должен увеличиваться на единицу каждый раз, когда я получаю новый эксперимент. Я где-то читал о переполнении стека, что это было быстрее, чем делать запрос каждый раз, когда вы хотели узнать, сколько экспериментов проводит пользователь.

Я пытаюсь использовать sqlachemy.event, чтобы прослушать создание эксперимента и обновить user.num_experiments.

Вот одна вещь, которую я попробовал. Я поместил этот код в модуль, который определяет модель эксперимента:

def update_user_exp_count(mapper, connection, target):
    db.session.begin_nested()
    user_id = target.user_id
    print("user id is ", user_id)
    user = User.get_by_id(user_id)
    user.num_experiments += 1
    print("This is my listener.  user.num experiments is", user.num_experiments)
    db.session.add(user)
    db.session.commit()

event.listen(Experiment, 'before_insert', update_user_exp_count)

Тест не пройден с ошибкой подтверждения, и вот мой стандартный вывод:

user id is  1
This is my listener.  user.num experiments is 1
user id is  1
This is my listener.  user.num experiments is 1
I just put the user and two experiments into the database. user.num_experiments is  0

Итак, мой слушатель был вызван, но объект пользователя никогда не обновлялся в таблице базы данных постоянным способом.

Я также пытался следовать примеру из этого вопроса .

Вот соответствующая часть модели User.

class User(UserMixin, SurrogatePK, Model):
    """A user of the app."""

    __tablename__ = 'users'
    username = Column(db.String(80), unique=True, nullable=False)
    email = Column(db.String(80), unique=True, nullable=False)
    num_experiments = Column(db.Integer(), default=0)
    experiments = relationship('Experiment', backref='user', lazy='dynamic')

И модели эксперимента (reference_col - это функция, определенная в колбе печенья для вставки внешних ключей):

class Experiment(SurrogatePK, Model):
    """A user's experiment, during which they are scanned."""

__tablename__ = 'experiments'
date = Column(db.Date(), nullable=False)
scanner = Column(db.String(80), nullable=True)
num_scans = Column(db.Integer(), nullable=True)
user_id = reference_col('users', nullable=True)

Я поместил этот код в модуль, который определяет модель пользователя:

  @event.listens_for(User.experiments, 'append')
    def receive_append(target, value, initiator):
        print("I was executed")
        target.num_experiments += 1

Это никогда не выполняется.

Что мне нужно сделать, чтобы родитель слушал новых детей и обновлялся, когда получал их? Буду признателен за любую помощь.

ОБНОВЛЕНИЕ: я разработал способ обойти эту проблему. Но мне все еще интересно знать, почему я не могу использовать слушателей. Вот мой обходной путь:

class ExperimentService:

    def add(self, user, date, scanner, num_scans):
        exp = Experiment.create(date=date, scanner=scanner, num_scans=num_scans, user_id=user.id)
        user.update(num_experiments=user.num_experiments + 1)
        print("here I am in the add function. user.num_experiments is ", user.num_experiments)
        return exp

.update - это один из удобных методов, предоставляемых колбой для печенья. Когда я делаю это, мой тест проходит. Итак, мои оставшиеся вопросы:

Почему, хотя update_user_exp_count выполняется, изменения не сохраняются в базе данных?

и

Почему receive_append никогда не выполняется?

...