All notes
Migrations

Intro

Migrations are Django’s way of propagating changes you make to your models (adding a field, deleting a model, etc.) into your database schema.

You should think of migrations as a version control system for your database schema.

makemigrations is responsible for packaging up your model changes into individual migration files - analogous to commits - and migrate is responsible for applying those to your database.

The migration files for each app live in a “migrations” directory inside of that app, and are designed to be committed to, and distributed as part of, its codebase.

You should be making them once on your development machine and then running the same migrations on your colleagues’ machines, your staging machines, and eventually your production machines.

Commands

segmentfault.



migrate
    applying migrations, as well as unapplying and listing their status.
makemigrations
    creating new migrations based on the changes you have made to your models.
sqlmigrate
    displays the SQL statements for a migration.
showmigrations
    lists a project’s migrations.

# Dump and load data
python manage.py dumpdata [appname] > appname_data.json
python manage.py loaddata appname_data.json
# Dump auth.User data
python manage.py dumpdata auth.User --indent 4 > users.json

# To delete migrations, remove all files in "migrations" directory except for "__init__.py":
find . -path "*migrations*" -name "*.py" -not -path "*__init__*" -exec rm {} \;

python manage.py squashmigrations schools 0002

在使用SQLite3数据库时, 因为SQLite3 不支持删除列操作,只有有限地 ALTER TABLE 支持,所以修改数据库列的操作被新建表然后select into newtable 代替,所以会存在更多问题。

Workflow

After adding a field or removing a model:


python manage.py makemigrations
# Or use a different name by --name:
python manage.py makemigrations --name changed_my_model 

python manage.py migrate

Once the migration is applied, commit the migration and the models change to your version control system as a single commit - that way, when other developers (or your production servers) check out the code, they’ll get both the changes to your models and the accompanying migration at the same time.

FAQ

Error: django migrate cannot serialize bound method

ValueError: Cannot serialize: <bound method ShortUUID.uuid of <shortuuid.main.ShortUUID object at 0x00000222D7EB5EB8>>

SO: migration cannot serialize a class method.

As explained in Django's migrations docs, Django can serialize function and method references, (in Python 3) unbound methods used from within the class body, and a bunch of other stuff, but it can't serialize everything.

In this case, because you've made get_default a @classmethod, Car.get_default is a bound method (i.e., it takes an implicit reference to Car as its first parameter), rather than a plain function or method reference, and Django doesn't know what to do with that.

Try making get_default a @staticmethod instead, or make a free function (top-level function) that calls Car.get_default.

wcfSolution: defind a free function and use this function for default:


def populateUuid():
  return shortuuid.uuid

# Create your models here.
class BaseModel(models.Model):
  uuid = ShortUUIDField(unique=True, default=populateUuid, editable=False, db_index=True, blank=False)
  class Meta:
    abstract = True

Add initial data

djangoProject: RunPython.

Write your own migration file, with migrations.RunPython:



# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models

def forwards_func(apps, schema_editor):
    # We get the model from the versioned app registry;
    # if we directly import it, it'll be the wrong version
    Country = apps.get_model("myapp", "Country")
    db_alias = schema_editor.connection.alias
    Country.objects.using(db_alias).bulk_create([
        Country(name="USA", code="us"),
        Country(name="France", code="fr"),
    ])

def reverse_func(apps, schema_editor):
    Country = apps.get_model("myapp", "Country")
    db_alias = schema_editor.connection.alias
    Country.objects.using(db_alias).filter(name="USA", code="us").delete()
    Country.objects.using(db_alias).filter(name="France", code="fr").delete()

class Migration(migrations.Migration):

    dependencies = []

    operations = [
        migrations.RunPython(forwards_func, reverse_func),
    ]

django squashmigrations invalid syntax with runpython

google groups: django squashmigrations invalid syntax with runpython<.

It was because python cannot import from modules that starts with numbers. Also, the idea was that we shouldn't use the migration files as modules to import code from, that's why the file name stayed as it was. Users should manually move their RunPython methods manually and resolve those invalid references to migration files.

wcfNote: don't prefix numbers to your RunPython migration files.