Как обновить мои объекты БД без какого-либо порядка? - PullRequest
1 голос
/ 01 октября 2019

Изображение ситуации, у меня есть приложение для личного календаря. Внутри есть модель, которая содержит дни, и только для моего приложения может быть вещь, которая может длиться 48 часов. Чтобы все было в порядке, мои дни не могут перекрывать друг друга - в БД есть ограничение на исключение.

Так что моя проблема в том, что когда я пытаюсь обновить свой календарь до нового часового пояса, мои дни перекрывают друг друга. Например, первый день начинается с 01:00 до 23:00 15 марта, второй день - с 00:03 до 23:30. 16 марта, когда мы переключаем часовой пояс на + -3 часа, происходит сбой:

    def do_execute(self, cursor, statement, parameters, context=None):
>       cursor.execute(statement, parameters)
E       sqlalchemy.exc.IntegrityError: (psycopg2.errors.ExclusionViolation) conflicting key value violates exclusion constraint "days_timerange_user_id_excl"
E       DETAIL:  Key (timerange, user_id)=(["2014-03-15 22:45:00+00","2014-03-16 11:50:00+00"), 739) conflicts with existing key (timerange, user_id)=(["2014-03-16 04:00:00+00","2014-03-16 10:00:00+00"), 739).
E        [SQL: 'UPDATE days SET timerange=%(timerange)s WHERE days.id = %(days_id)s'] [parameters: {'timerange': MutableDateTimeTZRange(datetime.datetime(2014, 3, 15, 12, 45, tzinfo=tzfile('/usr/share/zoneinfo/Pacific/Tahiti')), datetime.datetime(2014, 3, 16, 1, 50, tzinfo=tzfile('/usr/share/zoneinfo/Pacific/Tahiti')), '[)'), 'days_id': 858}] (Background on this error at: http://sqlalche.me/e/gkpj)

Мойфункция, которая делает это:

# Days
for i in user.days[::direction]:
   i.timerange = change_tz_timerange(i.timerange, user.timezone, timezone)
   self.request.dbsession.flush()

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

в change_tz_timerange вы можете увидеть:

def change_tz_timerange(timerange, old_tz, new_tz):
    return DateTimeTZRange(
                replace_tz(timerange.lower, old_tz, new_tz),
                replace_tz(timerange.upper, old_tz, new_tz),
                '[)'
            )

и replace_tz:

def replace_tz(dt, old_timezone, new_timezone):
    old_tz = pytz.timezone(old_timezone)
    dt = dt.astimezone(old_tz)
    dt = dt.replace(tzinfo=None)
    return arrow.get(dt, new_timezone).datetime

Есть ли способ обновить их все за один раз? или «удалить» их в процессе обновления? Спасибо.

1 Ответ

1 голос
/ 01 октября 2019

Решением может быть простое изменение ограничения, которое будет отложено. Затем он проверяется не как часть инструкции, а непосредственно перед окончанием транзакции.

ALTER TABLE days
   ALTER CONSTRAINT days_timerange_user_id_excl
      DEFERRABLE INITIALLY DEFERRED;

Затем к моменту проверки ограничения таблица снова станет согласованной.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...