We are transitioning a Django project from Django 1.8 -> 2.1 and Python 2.7 -> 3.6.
In the old project version, there are Django models that looked like this, for example:
# models.py
from django.db import models
class RowStatusModel(models.Model):
active = models.BooleanField(default=True, db_column='is_active')
# ...
class Meta:
abstract = True
Notice that from __future__ import unicode_literals
is not used in this module. That means that db_column
is a Python 2 str
, corresponding to bytes
in Python 3. The initial migration, 0001_initial.py, looks like this:
# 0001_initial.py
operations = [
# ...
('row_ef', models.BooleanField(default=True, db_column=b'is_active')
# ...
]
Notice the byte-literal b'is_active
, which I suppose was done by Django in the interest of being more explicit, but am not sure.
Now after transitioning most of the codebase with 2to3 and running makemigrations
, Python 3 treats a string literal as what would be the unicode type in Python 2, and consequently generates a migration where the db_column
is a string literal, for every single model that inherits from RowStatusModel
:
# migrations/0023_auto_20180827_1955.py
migrations.AlterField(
# ...
field=models.BooleanField(default=True, db_column='is_active')
), # ...
What effect, if any, will this have on the database side when ./manage.py migrate
is ran? Is the "change" purely on the Python side, or what side effects may be created?
Database engine is django.db.backends.postgresql
.
I'm aware that we can just clone the RDS instance and revert back to that if migrate
causes immediate problems, but I am more concerned about more subtle issues being introduced that would not be caught until much later on.
Migrations are Django's way of propagating changes you make to your models (adding a field, deleting a model, etc.) into your database schema. They're designed to be mostly automatic, but you'll need to know when to make migrations, when to run them, and the common problems you might run into.
migrate, which is responsible for applying migrations, as well as unapplying and listing their status. makemigrations, which is responsible for creating new migrations based on the changes you have made to your models.
--fake-initialAllows Django to skip an app's initial migration if all database tables with the names of all models created by all CreateModel operations in that migration already exist. This option is intended for use when first running migrations against a database that preexisted the use of migrations.
I came across a Django ticket after asking this question, where the recommendation from a Django developer is to edit any legacy migrations files (such as 0001_initial) that contain (Python 3) bytes literals, removing the b
and making them string-literals in Python 3.
Editing migrations to fix this issue is safe.
From there you should presumably be able to delete the migrations modules that were made with python3 ./manage.py makemigrations
, and redo that command, which should no longer take issue with the type of that argument.
I used the following to do a mass-find-and-replace of all instances of 'db_column=b'
with 'db_column='
. Granted, you should absolutely check git diff
before making that commit.
grep -nrl "db_column=b" apps | xargs sed -i "s/db_column=b/db_column=/g"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With