Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python 2 -> 3 Django migration causes field parameter type change

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.

like image 890
Brad Solomon Avatar asked Aug 28 '18 12:08

Brad Solomon


People also ask

How does Django migration work?

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.

What is the difference between Makemigrations and migrate in Django?

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.

What does fake migration do in Django?

--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.


1 Answers

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"
like image 66
Brad Solomon Avatar answered Oct 01 '22 01:10

Brad Solomon