Heroku postgres postgis - выпуски django завершаются с ошибкой: отношение «spatial_ref_sys» не существует

1 августа 2022 г. компания Heroku изменила управление схемой расширения PostgreSQL. (https://devcenter.heroku.com/changelog-items/2446)

С тех пор каждое развертывание нашего существующего приложения django 4.0 в Heroku терпит неудачу на этапе выпуска, сборка завершается успешно.

Кто-нибудь сталкивался с такой же проблемой? Есть ли обходной путь для отправки новой версии в Heroku, кроме переустановки расширения postgis?

Если я правильно понимаю изменения, Heroku добавил схему под названием «heroku_ext» для вновь созданных расширений. Поскольку расширение уже существует в нашем случае, оно не должно быть затронуто.

All currently installed extensions will continue to work as intended.

Следуя полным журналам выпуска через git push:

git push staging develop:master
Gesamt 0 (Delta 0), Wiederverwendet 0 (Delta 0), Pack wiederverwendet 0
remote: Compressing source files... done.
remote: Building source:
remote: 
remote: -----> Building on the Heroku-20 stack
remote: -----> Using buildpacks:
remote:        1. https://github.com/heroku/heroku-geo-buildpack.git
remote:        2. heroku/python
remote: -----> Geo Packages (GDAL/GEOS/PROJ) app detected
remote: -----> Installing GDAL-2.4.0
remote: -----> Installing GEOS-3.7.2
remote: -----> Installing PROJ-5.2.0
remote: -----> Python app detected
remote: -----> Using Python version specified in runtime.txt
remote: -----> No change in requirements detected, installing from cache
remote: -----> Using cached install of python-3.9.13
remote: -----> Installing pip 22.1.2, setuptools 60.10.0 and wheel 0.37.1
remote: -----> Installing SQLite3
remote: -----> Installing requirements with pip
remote: -----> Skipping Django collectstatic since the env var DISABLE_COLLECTSTATIC is set.
remote: -----> Discovering process types
remote:        Procfile declares types -> release, web, worker
remote: 
remote: -----> Compressing...
remote:        Done: 156.1M
remote: -----> Launching...
remote:  !     Release command declared: this new release will not be available until the command succeeds.
remote:        Released v123
remote:        https://myherokuapp.herokuapp.com/ deployed to Heroku
remote: 
remote: This app is using the Heroku-20 stack, however a newer stack is available.
remote: To upgrade to Heroku-22, see:
remote: https://devcenter.heroku.com/articles/upgrading-to-the-latest-stack
remote: 
remote: Verifying deploy... done.
remote: Running release command...
remote: 
remote: Traceback (most recent call last):
remote:   File "/app/.heroku/python/lib/python3.9/site-packages/django/db/backends/utils.py", line 87, in _execute
remote:     return self.cursor.execute(sql)
remote: psycopg2.errors.UndefinedTable: relation "spatial_ref_sys" does not exist
remote: 
remote: 
remote: The above exception was the direct cause of the following exception:
remote: 
remote: Traceback (most recent call last):
remote:   File "/app/manage.py", line 22, in <module>
remote:     main()
remote:   File "/app/manage.py", line 18, in main
remote:     execute_from_command_line(sys.argv)
remote:   File "/app/.heroku/python/lib/python3.9/site-packages/django/core/management/__init__.py", line 446, in execute_from_command_line
remote:     utility.execute()
remote:   File "/app/.heroku/python/lib/python3.9/site-packages/django/core/management/__init__.py", line 440, in execute
remote:     self.fetch_command(subcommand).run_from_argv(self.argv)
remote:   File "/app/.heroku/python/lib/python3.9/site-packages/django/core/management/base.py", line 414, in run_from_argv
remote:     self.execute(*args, **cmd_options)
remote:   File "/app/.heroku/python/lib/python3.9/site-packages/django/core/management/base.py", line 460, in execute
remote:     output = self.handle(*args, **options)
remote:   File "/app/.heroku/python/lib/python3.9/site-packages/django/core/management/base.py", line 98, in wrapped
remote:     res = handle_func(*args, **kwargs)
remote:   File "/app/.heroku/python/lib/python3.9/site-packages/django/core/management/commands/migrate.py", line 106, in handle
remote:     connection.prepare_database()
remote:   File "/app/.heroku/python/lib/python3.9/site-packages/django/contrib/gis/db/backends/postgis/base.py", line 26, in prepare_database
remote:     cursor.execute("CREATE EXTENSION IF NOT EXISTS postgis")
remote:   File "/app/.heroku/python/lib/python3.9/site-packages/sentry_sdk/integrations/django/__init__.py", line 544, in execute
remote:     return real_execute(self, sql, params)
remote:   File "/app/.heroku/python/lib/python3.9/site-packages/django/db/backends/utils.py", line 67, in execute
remote:     return self._execute_with_wrappers(
remote:   File "/app/.heroku/python/lib/python3.9/site-packages/django/db/backends/utils.py", line 80, in _execute_with_wrappers
remote:     return executor(sql, params, many, context)
remote:   File "/app/.heroku/python/lib/python3.9/site-packages/django/db/backends/utils.py", line 89, in _execute
remote:     return self.cursor.execute(sql, params)
remote:   File "/app/.heroku/python/lib/python3.9/site-packages/django/db/utils.py", line 91, in __exit__
remote:     raise dj_exc_value.with_traceback(traceback) from exc_value
remote:   File "/app/.heroku/python/lib/python3.9/site-packages/django/db/backends/utils.py", line 87, in _execute
remote:     return self.cursor.execute(sql)
remote: django.db.utils.ProgrammingError: relation "spatial_ref_sys" does not exist
remote: 
remote: Sentry is attempting to send 2 pending error messages
remote: Waiting up to 2 seconds
remote: Press Ctrl-C to quit
remote: Waiting for release.... failed.
To https://git.heroku.com/myherokuapp

🤔 А знаете ли вы, что...
В Python можно легко работать с базами данных, такими как SQLite и MySQL.


28
1 848
8

Ответы:

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

System check identified no issues (5 silenced).
Traceback (most recent call last):
File "/app/.heroku/python/lib/python3.10/site-packages/django/db/backends/utils.py", line 87, in _execute
return self.cursor.execute(sql)
psycopg2.errors.UndefinedTable: relation "spatial_ref_sys" does not exist
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/app/manage.py", line 40, in
main()
File "/app/manage.py", line 36, in main
execute_from_command_line(sys.argv)
File "/app/.heroku/python/lib/python3.10/site-packages/django/core/management/init.py", line 446, in execute_from_command_line
utility.execute()
File "/app/.heroku/python/lib/python3.10/site-packages/django/core/management/init.py", line 440, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/app/.heroku/python/lib/python3.10/site-packages/django/core/management/base.py", line 414, in run_from_argv
self.execute(*args, **cmd_options)
File "/app/.heroku/python/lib/python3.10/site-packages/django/core/management/base.py", line 460, in execute
output = self.handle(*args, **options)
File "/app/.heroku/python/lib/python3.10/site-packages/django/core/management/base.py", line 98, in wrapped
res = handle_func(*args, **kwargs)
File "/app/.heroku/python/lib/python3.10/site-packages/django/core/management/commands/migrate.py", line 106, in handle
connection.prepare_database()
File "/app/.heroku/python/lib/python3.10/site-packages/psqlextra/backend/base.py", line 32, in prepare_database
super().prepare_database()
File "/app/.heroku/python/lib/python3.10/site-packages/django/contrib/gis/db/backends/postgis/base.py", line 26, in prepare_database
cursor.execute("CREATE EXTENSION IF NOT EXISTS postgis")
File "/app/.heroku/python/lib/python3.10/site-packages/sentry_sdk/integrations/django/init.py", line 544, in execute
return real_execute(self, sql, params)
File "/app/.heroku/python/lib/python3.10/site-packages/django/db/backends/utils.py", line 67, in execute
return self._execute_with_wrappers(
File "/app/.heroku/python/lib/python3.10/site-packages/django/db/backends/utils.py", line 80, in _execute_with_wrappers
return executor(sql, params, many, context)
File "/app/.heroku/python/lib/python3.10/site-packages/django_read_only/init.py", line 74, in blocker
return execute(sql, params, many, context)
File "/app/.heroku/python/lib/python3.10/site-packages/django/db/backends/utils.py", line 84, in _execute
with self.db.wrap_database_errors:
File "/app/.heroku/python/lib/python3.10/site-packages/django/db/utils.py", line 91, in exit
raise dj_exc_value.with_traceback(traceback) from exc_value
File "/app/.heroku/python/lib/python3.10/site-packages/django/db/backends/utils.py", line 87, in _execute
return self.cursor.execute(sql)
django.db.utils.ProgrammingError: relation "spatial_ref_sys" does not exist
Sentry is attempting to send 2 pending error messages
Waiting up to 2 seconds
Press Ctrl-C to quit

У нас также была ошибка перед этой, в которой говорилось pgaudit stack is not empty, что требовало от меня ручного перевода наших баз данных в режим обслуживания, чтобы их ротировать. https://devcenter.heroku.com/articles/data-maintenance-cli-commands#heroku-data-maintenances-schedule Эта статья помогла мне обойти первую проблему, но теперь я нахожусь в той же лодке с ошибкой space_ref_sys.


Моя команда тоже столкнулась с этим. Не могли дождаться, пока Heroku исправят, поэтому мы сделали небольшую хирургическую операцию. Не для всех применимо, но так как мы мало используем PostGIS, это не так уж и плохо.

Это был мой контрольный список для каждой затронутой базы данных:

  • резервное копирование базы данных
  • включить режим обслуживания
  • создайте новые примитивные столбцы float во всех таблицах, которые использовали типы geography для хранения необработанных данных широты / долготы
  • записать значения из полей geography в новые столбцы
  • удалить расширение postgis: DROP EXTENSION postgis CASCADE;
  • воссоздать расширение: CREATE EXTENSION IF NOT EXISTS postgis;
  • воссоздайте наши поля geography и заполните их из новых столбцов
  • удалить новые временные столбцы
  • воссоздать соответствующие индексы

Все идет нормально.


Мы также столкнулись с этой проблемой при попытке использовать heroku pg:backups:restore и heroku pg:copy — существующие снимки резервных копий нельзя восстановить, если они содержат установленные расширения.


Вот обходной путь, который я придумал для наших обзорных приложений, использующих резервную копию базы данных, через pg:backups:restore (может потребоваться включить техническое обслуживание, если вы манипулируете производственной базой данных):

  1. Скопируйте локально базу данных приложения для проверки (та, которая была недавно восстановлена ​​с помощью pg:backups:restore, чтобы получить все данные): heroku pg:pull [Database URL] localdb -a [app-name]

  2. Настройте конфигурацию базы данных приложения на использование localdb, затем подключитесь к psql и выполните: ALTER EXTENSION "hstore" SET SCHEMA heroku_ext;. Запустите эту команду для всех ваших существующих расширений.

Чтобы просмотреть все доступные расширения, которые вы вытащили, запустите \dx. Вам не нужно ничего менять plpgsql он встроен в PostgreSQL

Это будет работать, потому что локально у вас есть все привилегии.

  1. отправьте эту версию обратно в приложение для проверки: heroku pg:push mylocaldb [Database URL] -a [app-name] ==> Для этого ваша база данных должна быть пустой. Вы можете попробовать эту операцию на свежем приложении обзора с пустыми данными. таким образом, он может стать вашей новой базой для всех обзорных приложений.

  2. Убедитесь, что все работает как положено (данные правильно восстановлены). Затем вы можете создать новый дамп базы данных с помощью pg:backups:capture и использовать его в качестве новой резервной копии базы данных для всех ваших новых приложений для проверки.

Источник: https://devcenter.heroku.com/articles/managing-heroku-postgres-using-cli

Мне также пришлось сделать это, потому что, например, УДАЛЕНИЕ расширения hstore и его повторное включение не было подходящим вариантом для нашего случая.


Решено

Я работал над этим, перезаписывая движок postgis/base.py, я добавил следующее в свое приложение под db/base.py

from django.contrib.gis.db.backends.postgis.base import (
     DatabaseWrapper as PostGISDatabaseWrapper,
)

class DatabaseWrapper(PostGISDatabaseWrapper):
    def prepare_database(self):
        # This is the overwrite - we don't want to call the
        # super() because of a faulty extension creation
     pass

Тогда в моих настройках я просто указал DATABASES["engine"] = "app.db"

Это не поможет с резервными копиями, но, по крайней мере, я могу снова выпустить.


Мы использовали этот обходной путь, предоставленный @chedli https://stackoverflow.com/a/73219273/840568.

Но в нашем случае postgis выдавал ошибку о том, что не разрешено перемещать схемы при попытке обходного пути ALTER EXTENSION postgis SET SCHEMA heroku_ext, поэтому нам пришлось выполнить этот дополнительный шаг.

UPDATE pg_extension
  SET extrelocatable = true
    WHERE extname = 'postgis';

ALTER EXTENSION "postgis" SET SCHEMA "heroku_ext";

UPDATE pg_extension
  SET extrelocatable = false
    WHERE extname = 'postgis';

Команда Heroku наконец-то решила проблему :)


Интересные вопросы для изучения