"django.db.utils.NutSupportedError: extension 'postgis' not available" error being thrown despite having postgis installed in Python virtualenv
I am attempting to migrate model changes I have made to my codebase to a PostgreSQL server (PostgreSQL 18.1 on x86_64-linux, compiled by gcc-11.4.0, 64-bit), but every time I do this error is thrown. Specifically, the migrate sequence throws the error when reading the file /home/[username]/[project]/[project_directory]/newenv/lib/python3.10/site-packages/django/db/backends/utils.py on return self.cursor.execute(sql). (Note: the system environment is Linux DESKTOP-7C9U6H4 6.6.87.2-microsoft-standard-WSL2).
The function called looks like this:
def _execute(self, sql, params, *ignored_wrapper_args):
# Raise a warning during app initialization (stored_app_configs is only
# ever set during testing).
if not apps.ready and not apps.stored_app_configs:
warnings.warn(self.APPS_NOT_READY_WARNING_MSG, category=RuntimeWarning)
self.db.validate_no_broken_transaction()
with self.db.wrap_database_errors:
if params is None:
# params default might be backend specific.
return self.cursor.execute(sql)
else:
return self.cursor.execute(sql, params)
In my project settings my Databases dictionary looks like the following:
DATABASES = {
'default': {
'ENGINE': 'django.contrib.gis.db.backends.postgis',
'NAME': '[name]',
'USER': '[user]',
'PASSWORD': '',
'HOST': '127.0.0.1', # localhost
'PORT': '5432',
}
}
When I try to enter the command CREATE extension postgis; on the database side (the server is located at /usr/local/pgsql/data), I get the following error thrown: ERROR: extension "postgis" is not available. Hint: The extension must first be installed on the system where PostgreSQL is running.
I am unclear why the extension is not available because I have already run (in my project's local virtualenv)
sudo apt install postgis
sudo apt install postgresql-18
sudo apt install ca-certificates gnupg
curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/apt.postgresql.org.gpg >/dev/null
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
When I run apt search postgis, these items appear for postgresql-18
postgresql-18-postgis-3/jammy-pgdg-testing,jammy-pgdg,now 3.6.1+dfsg-1.pgdg22.04+1 amd64 [installed,automatic]
Geographic objects support for PostgreSQL 18
postgresql-18-postgis-3-dbgsym/jammy-pgdg-testing,jammy-pgdg 3.6.1+dfsg-1.pgdg22.04+1 amd64
debug symbols for postgresql-18-postgis-3
postgresql-18-postgis-3-scripts/jammy-pgdg-testing,jammy-pgdg,now 3.6.1+dfsg-1.pgdg22.04+1 all [installed,automatic]
Geographic objects support for PostgreSQL 18 -- SQL scripts
It is neither Django nor Python issue. Especially venv has nothing to do with it. Using apt in venv or not installs packages globally in your OS. This issue is solely between your Postgres and Postigs system-wide installations.
I did reproduce your setup using your Postgres and Postgis installation commands (in reverse order and with required sudo apt update after repo update) in Ubuntu 24.04.03. In my setup Postgis extension can be created with CREATE EXTENSION postgis;.
What might be wrong in your setup
You can check whether packages are installed or not, using apt list --installed. In my working setup I get:
$ apt list --installed postgis postgresql-18
postgis/noble-pgdg,now 3.6.1+dfsg-1.pgdg24.04+1 amd64 [installed]
postgresql-18/noble-pgdg,now 18.1-1.pgdg24.04+2 amd64 [installed]
As all apt installations are system-wide, if you are installing more than one Postgres servers in one OS you might end up running and connecting to wrong one.
For example if you install packages in following order
$ sudo apt install postgresql-17
$ sudo apt install postgresql-18
$ sudo apt install postgis
and then not configure anything, you will probably get a conflict. Reasoning from my tests it looks like the first Postgres you installed is ran by default. But apt doesn't know whichever you are running, so Postgis will be installed for Postgresql 18, the latest one. Default systemd postgres service will still serve Postgres 17.
You can check if you are on correct Postgres version by running
SELECT version();
while connected to db, or
$ pg_lsclusters
in shell.
If you serve wrong one, which I find highly probable, to create a new one you can use
$ pg_createcluster 18 pg18
Note that this command will list new (configurable) port that you will have to use in your app configuration.
Note: I am aware this answer contains assumptions that might be not correct. After OP gives more insights on their setup I will edit.