DATABASE: Migrate from SQLite3 to PostgreSQL
Objectives
Two databases were setup on server, sqlite
is for development, PostgreSQL
is for production. It is probably a stupid idea in the first place: because of an environment variable error, sqlite
was still being used in production and user has been uploading data (files and pictures) for a while. I now need to change the database to PostgreSQL
on the server without losing the data.
Server: Ubuntu 18.04
- Goal: To migrate/transfer SQLite3 data to PostgreSQL
- To dos:
- research how to backup sqlite databases
- find and install necessary tools
- backup database waiting to be transferred remotely
- Tools:
django-archive
==0.1.6 easy to use and setup, for backing up database as well as media files-
[`django-dbbackup`](https://pypi.org/project/django-dbbackup/)==3.2.0couldn’t setup backup folder path correctly somehow
-
[pgloader](https://pgloader.readthedocs.io/en/latest/intro.html)Actually didn’t get you use it
Process
After a whole day of running round the circles and walking into deadends, I finally figured out. At times, I felt I was so close to the solution of the problem yet an error throw me off the edge… But I finally solved it after 2 days of work. It’s actually quite easy.
1: DUMP
Make sure in settings.py
, your database is still pointing to db.sqlite3
if you use default django database.
(venv)$ python manage.py dumpdata > datadump.json
You will have a datadump.json
file in your project directory
2. NEW DATABASE SETTING
point your database to your new database to be created
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'db_name',
'USER': 'db_user',
'PASSWORD': os.environ.get('DB_PASSWD'),
'HOST': 'localhost',
'PORT': '',
}
}
3. CREATE NEW DATABASE WITH ‘UTF-8’ ENCODING
Some of the data is written in Russian (Cyrillic), wrong encoding of the database can be disastrous! Apparently, you can only set the encoding of a database when you create it. It can not be altered afterwards.
Here’s how to create a database support all language input ==>
$ sudo -u postgres psql
postgres=# CREATE DATABASE new_db_name WITH ENCODING='UTF8' LC_CTYPE='ru_RU.UTF-8' LC_COLLATE='ru_RU.UTF-8' OWNER=postgres TEMPLATE=template0;
# note:
# 1. I need Russian locale encoding: 'ru_RU.UTF-8';
# 2. you have to specify 'template0' if your template0 and template1 encoding is not 'UTF8'
postgres=# GRANT ALL PRIVILEGES ON DATABASE myproject TO myprojectuser;
# don not forget to grant access before exiting the psql shell
# you can use \l to check existing databases
postgres=# \l
postgres=# \q
check out CREATE DATABASE for more
4. MIGRATE DATA
We need to create the tables in the new database:
(venv)$ python manage.py migrate --run-syncdb
5. EXCLUDE CONTENTTYPES
Before loading dumped data, we need to exclude contenttype data, for avoiding integrity errors:
(venv)$ python manage.py shell
>>> from django.contrib.contenttypes.models import ContentType
>>> ContentType.objects.all().delete()
>>> quit()
Thanks for this post by coderasha
6. LOADDATA
And finally:
(venv)$ python manage.py loaddata datadump.json
Installed 541 object(s) from 1 fixture(s)
However:
TROUBLESHOOTING:
You will likely to run into many problems and errors on the way, but don’t worry, read them and analyze them, google and stackoverflow, here’s a few:
-
UnicodeEncodeError: ‘latin-1’ codec can’t encode characters in position 0-2: ordinal not in range(256)
This happened when I tried to
loaddata
(step 6). Step 3 is the fix. -
character with byte sequence 0xd0 0x90 in encoding “UTF8” has no equivalent in encoding “LATIN1”
This is caused by the system LANGUAGE setting. The system can not recognize/find the cyrillic charactors in “LATIN1” encoding/’library’. If you need to support other languages, use ‘utf-8’ EVERYWHERE!!!
QUICK FIX LANG = UTF-8 IN UBUNTU
The system default (LANG=en_US) didn’t support cyrillic at all, so try the command below and logout login again:# if you want to generate say Russian cyrillic language locale in UTF-8 $ sudo locale-gen "ru_RU.UTF-8" # also try this to permanently change all of your locale to en_US.UTF-8 $ sudo update-locale LANG="en_US.UTF-8" LANGUAGE="en_US.UTF-8" $ locale # run locale see if everything equals to 'en_US.UTF-8'
##### Thanks for this post by perlgeek
-
users.models.DoesNotExist: Problem installing fixture ‘…’ matching query does not exist
SOME TABLE MISSING
These tables are likely be the ones whoes creation depends on others. In my case, a profile table wounldn’t be initiated unless a User instance is created. Hence, I created a superuser before I ran Step 6 above. Problem solved.
Many many other failed attempts
Although these attempts didn’t become the solution to this problem, they were the lessons I missed:
1. Installation of pgloader:
pgloader: By default, apt
found the latest version of pgloader
is v3.4.1
# on Ubuntu server, install PGLoader
$ sudo apt-get update -y
$ sudo apt-get install -y pgloader
$ sudo -u postgres pgloader db.sqlite3 postgresql:///db_name
This will prompt an error because of a bug of some sort in the outdated version. After researching for a while, I found out that pgloader needed to be updated:
2. Update PostgreSQL packages list for Ubuntu: check this article: PostgreSQL packages for Debian and Ubuntu:
I couldn’t update pgloader
from 3.4 to 3.6 so I tried the method in the article to update the installation listk, then:
# uninstall current old version of pgloader:
$ sudo apt-get purge --auto-remove pgloader
# install the new one:
$ sudo apt update
$ sudo apt install pgloader
# Normal the above code can get you the latest version of the package
Now the pgloader
is v3.5, although not v3.6 but it’s enough to do the following ==>
3. Now you will be able to migrate the SQLite database to the PostgreSQL:
$ sudo -u postgres pgloader db.sqlite3 postgresql:///db_name
KABOOM!
KILLED
# the website now is not accessable, error: "ProgrammingError at / permission denied for relation..."
# because the public tables haven't grant access to the project user, type:
$ sudo -u postgres psql db_name
db_name=> GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO myprojectuser;
Now the website can be accessed normally, however ==>
4. Restoring the database with the correct encoding ‘UTF-8’
For details of the problem you can checkout the post, here’s the solution:
- if you want to keep the existing database, dump the data before renaming it:
$ sudo -u postgres pg_dump dbname > dbname.bak
$ sudo -u postgres psql
postgres=> ALTER DATABASE db_name RENAME TO temp_name
Reference articles:
- pgloader official doc: Migrating an SQLite database to PostgreSQL