Django PostgreSQL: Step-by-Step Configuration with Psycopg2

django postgresql pscycopg2 python banner

Configuring a Django PostgreSQL project is a straight-forward process that involves updating the settings.py file and adding one additional library (psycopg2). Depending on which IDE, OS, and Python version used there are several possible errors that can arise. We’ll address those here as well.

Django comes configured to work with a local SQLite database by default, which is great for early-stage app development. Unfortunately, it’s not great for production use or even some more stringent development tasks like concurrent I/O. Below are the steps needed to configure a new Django project for use with a PostgreSQL database.

Django PostgreSQL Setup

Django uses some third-party libraries by default but does not install the required libraries to support postgres. Here’s a look at the packages installed after a clean install of Django on a new virtual environment:

asgiref==3.3.1
Django==3.1.4
pytz==2020.4
sqlparse==0.4.1

Django is designed to use a project-folder sqlite database by default that is configured in the project/project/settings.py and to use the django.db.backends.sqlite3 adapter as such:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}

This tells Django to use a database named BASE_DIR/db.sqlite3 as the project’s database. To use a postgres database, the following steps must happen:

  1. Specify the correct Django adapter + credentials for Postgres
  2. Install necessary 3rd party library for Postgres
  3. Specify credentials to new/existing postgres database

These steps are simple enough but can benefit from some elaboration.

Step 1: Specify Postgres Adapter + Credentials

To make Django work with Postgres, an adapter other than the default sqlite adapter must be specified. I like working with the psycopg2 Postgres adaptor and have shown how to specify that adapter below:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': "db_name",
        'USER': "db_username",
        'PASSWORD': "db_password",
        'HOST': "db_host",
        'PORT': "db_port",  # 5432 by default
    }
}

In older versions of Django, the adapter was named django.db.backends.postgresql_psycopg2. This was changed from release 1.9 forwards and summarized in the official release notes as such:

The PostgreSQL backend django.db.backends.postgresql_psycopg2 is also available as django.db.backends.postgresql. The old name will continue to be available for backward compatibility.

Obviously, you need to have access to a Postgres database to make this work well. You should replace the values in the above code with the database to which your project will connect.  Common values for HOST and PORT are localhost and 5432 respectively, which 5432 being the default Postgres port, as described in the official PostgreSQL documentation.

Step 2: Install Necessary Postgres Adaptor

While Django ships with an “adapter” for Postgres, it still needs a 3rd party library for support. If you simply add the code above and run python manage.py makemigrations you’ll get a stacktrace with the following exception:

django.core.exceptions.ImproperlyConfigured: Error loading psycopg2 module: No module named 'psycopg2'

Django’s django.db.backends.postgresql adaptor bridges Django’s own ORM models to Postgres, but doesn’t actually provide the adaptors needed for actual Postgres usage. Rather than re-inventing the wheel, the Django Project has elected to use the psycopg2 library—arguably the most popular python adapter for Postgres.

To make the Django adaptor work, the psycopg2 library needs to be installed with this command: pip install psycopg2. Running the pip freeze command should now produce the following output:

asgiref==3.3.1
Django==3.1.4
psycopg2==2.8.6
pytz==2020.4
sqlparse==0.4.1

Common Issues with psycopg2

Depending on what platform, Python version, or IDE used; psycopg2 has some known-issues when it comes to installation. The most common is a DLL error that will prevent Django from creating the required migrations:

ImproperlyConfigured Exception

django.core.exceptions.ImproperlyConfigured: Error loading psycopg2 module: DLL load failed while importing _psycopg: The specified module could not be found.

This error indicates that a core DLL file is missing from the psycopg2 installation. It’s important to recognize that psychopg2 is a third-party library and, as such, may not always be compatible with the latest Python version. In some cases, reverting to a previous version of Python may be necessary.

Option 1: Use pyscopg2-binary

Note: This package comes with its own version of some core libraries that may, under certain conditions, cause conflicts with other libraries. See the developer’s notes for more info.

Option 2: Manual Copy from System Install

Some IDEs, at least PyCharm in my experience, may have trouble installing psycopg2. In such cases, a possible workaround is to install psycopg2 to the main system install of python, then copy those files manually into your project’s virtual environment’s site-packages directory. On a Windows machine, the steps are as follows:

  1. Using the Windows terminal: pip install psycopg2
  2. Copy Program Files/PythonXX/site-packages/psycopg2 to your virtual environments’ site-packages directory.

If installed without elevated privileges, the psycopg2 library may install to the local User’s Python installation. If this is the case (you won’t find the psycopg2 package in the directory above) look in the following directory:

.
└── C:/
    └── Users/
        └── pc/
            └── AppData/
                └── Roaming/
                    └── Python/
                        └── Python38/
                            └── site-packages/
                                └── psycopg2

Migrate Changes

Assuming psycopg2 was configured correctly, your project should be adequately configured for basic Postgres usage now. Assuming your project doesn’t require any changes to models or other areas to work with Postgres, running the makemigrations and migrate commands should give you the confirmation of success you need. Below is what the output should look like—for a blank Django project having just configured Postgres:

(venv) C:\path\to\your-project>python manage.py makemigrations
No changes detected

(venv) C:\path\to\your-project>python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying sessions.0001_initial... OK

These are all the core Django models being migrated to the Postgres database.

Discussion

Django is an incredible framework for building multi-purpose web applications ranging from hobbyist projects to enterprise-caliber endeavors. As we’ve seen here, Django can be configured to work with PostgreSQL relatively easily. There may be some quirks depending on your OS or IDE but I’ve still to see anything that would prevent the setup outlined here from being troubleshot.

Zαck West
Full-Stack Software Engineer with 10+ years of experience. Expertise in developing distributed systems, implementing object-oriented models with a focus on semantic clarity, driving development with TDD, enhancing interfaces through thoughtful visual design, and developing deep learning agents.