Django 1.8.2.dev20150513143415 documentation

迁移

New in Django 1.7.

迁移是Django用于同步你的发生改变的模型(添加一个字段,删除一个模型,等等。) 到你的数据库。 它的设计是很智能的, 但是你还是需要了解什么时候进行迁移, 什么时候去启动它们, 以及可能遇到的指令问题。

简短历史

在 1.7版本之前, Django 只支持添加新模型到数据库;无法通过syncdb命令来修改或移除已存在的模型 (已被migrate代替)。

第三方工具,最著名的是South, 为这些额外的功能提供支持,但是它还是被认为是很重要的部分并且加入到django的核心里面。

命令集

有一些你用于进行迁移的命令集和数据库架构的django操作

  • migrate,负责应用迁移,以及取消应用并列出其状态。
  • makemigrations, 负责基于你的模型修改创建一个新的迁移
  • sqlmigrate, 展示迁移的sql语句

值得注意的是,迁移是建立和运行在每一个app的基础上。 特别的,确实存在 没有用迁移的app (它们被称为“非迁移”apps) -相比利用遗留的保存行为,它们只是在这个基础上添加一个新的模型.

你可以想象 migrations相当一个你的数据库的一个版本控制系统。makemigrations 命令负责保存你的模型变化到一个迁移文件 - 和 commits很类似 - 同时 migrate负责将改变提交到数据库。

每个app 的迁移文件会保存到每个相应app的“migrations”文件夹里面,并且准备如何去执行它, 作为一个分布式代码库。 每当在你的开发机器或是你同事的机器并且最终在你的生产机器上运行同样的迁移,你应当再创建这些文件。

Note

通过修改 MIGRATION_MODULES 设置,可以覆盖那些每个app 都包含  migrations 的 package 

同样的方式,同样的数据集,将产生一致的结果, 那意味着你在开发和筹划中在按照同样的原理运行的情况下得到的结果和线上是一致的

Django 将迁移你对模型和字段做出的任何改变 - 甚至包括那些对数据库没有影响的操作, -在历史记录存放所有改变是正确重建field的唯一方式,你可能会在以后的数据迁移中使用到这些选项 (比如,在你定制了校验器的时候)。

后台支持

Django附带的所有后端都支持迁移,以及任何第三方后端,如果他们已被编程支持模式更改(通过SchemaEditor类完成)。

但是,一些数据库比其他数据库在模式迁移方面更有能力;下面是一些警告.

PostgreSQL

PostgreSQL is the most capable of all the databases here in terms of schema support; the only caveat is that adding columns with default values will cause a full rewrite of the table, for a time proportional to its size.

For this reason, it’s recommended you always create new columns with null=True, as this way they will be added immediately.

MySQL

MySQL缺少对模式更改操作的事务的支持,这意味着如果迁移无法应用,则必须手动取消批准更改才能再次尝试(不可能回滚到更早的点)。

此外,MySQL将为每个模式操作完全重写表,通常需要与表中的行数成正比的时间来添加或删除列。在较慢的硬件上,这可能比每分钟每百万行更糟 - 向表中添加几列只有几百万行可能会锁定您的网站超过十分钟。

最后,MySQL对列,表和索引的名称长度有相当小的限制,以及索引涵盖的所有列的组合大小的限制。这意味着在其他后端可能的索引将无法在MySQL下创建。

SQLite

SQLite has very little built-in schema alteration support, and so Django attempts to emulate it by:

  • 使用新模式创建新表
  • Copying the data across
  • 删除旧表
  • Renaming the new table to match the original name

This process generally works well, but it can be slow and occasionally buggy. It is not recommended that you run and migrate SQLite in a production environment unless you are very aware of the risks and its limitations; the support Django ships with is designed to allow developers to use SQLite on their local machines to develop less complex Django projects without the need for a full database.

工作流程

迁移工作很简单。 修改你的模型 -比如添加字段和移除一个模型 - 然后运行 makemigrations:

$ python manage.py makemigrations
Migrations for 'books':
  0003_auto.py:
    - Alter field author on book

你的原型会扫描和比较你当前迁移文件里面的版本,同时新的迁移文件会被创建. 请务必查阅输出,看看makemigrations 是如何理解你做出的更改 - 迁移不是完全准确的, 对于一些复杂的更改,它可能不会检测到你所期望的东西。

一旦你有了新的迁移文件, 你应该把它们提交到你的数据库以确保它们像预期的那样工作:

$ python manage.py migrate
Operations to perform:
  Synchronize unmigrated apps: sessions, admin, messages, auth, staticfiles, contenttypes
  Apply all migrations: books
Synchronizing apps without migrations:
  Creating tables...
  Installing custom SQL...
  Installing indexes...
Installed 0 object(s) from 0 fixture(s)
Running migrations:
  Applying books.0003_auto... OK

命令分两步运行,首先,它会同步未迁移的应用(与旧的syncdb命令所做的操作相同),然后对未应用的更改进行迁移。

一旦迁移应用后,在版本控制系统中将迁移与模型的改变作为同一次提交-那样的话,其他开发者(或者你的生产服务器)检查代码时,他们将同时看到模型的改变及伴随的迁移。

New in Django 1.8.

如果要给migration(s)起一个有意义的名称而不是用自动生成的,则可以使用--name选项:

$ python manage.py makemigrations --name changed_my_model your_app_label

版本控制

Because migrations are stored in version control, you’ll occasionally come across situations where you and another developer have both committed a migration to the same app at the same time, resulting in two migrations with the same number.

Don’t worry - the numbers are just there for developers’ reference, Django just cares that each migration has a different name. 迁移指定文件中依赖的其他迁移(包括在同一应用中的早期迁移),因此可以检测同一应用的两次不规则的新迁移。

When this happens, Django will prompt you and give you some options. 如果它认为它足够安全,它会为你自动线性化两个迁移。If not, you’ll have to go in and modify the migrations yourself - don’t worry, this isn’t difficult, and is explained more in Migration files below.

依赖关系

While migrations are per-app, the tables and relationships implied by your models are too complex to be created for just one app at a time. 当您进行迁移时,需要其他东西来运行——例如,您可以在books应用添加一个ForeignKey到您的authors应用——由此产生的迁移将包含对authors的迁移的依赖

This means that when you run the migrations, the authors migration runs first and creates the table the ForeignKey references, and then the migration that makes the ForeignKey column runs afterwards and creates the constraint. If this didn’t happen, the migration would try to create the ForeignKey column without the table it’s referencing existing and your database would throw an error.

This dependency behavior affects most migration operations where you restrict to a single app. Restricting to a single app (either in makemigrations or migrate) is a best-efforts promise, and not a guarantee; any other apps that need to be used to get dependencies correct will be.

Be aware, however, that unmigrated apps cannot depend on migrated apps, by the very nature of not having migrations. This means that it is not generally possible to have an unmigrated app have a ForeignKey or ManyToManyField to a migrated app; some cases may work, but it will eventually fail.

Warning

Even if things appear to work with unmigrated apps depending on migrated apps, Django may not generate all the necessary foreign key constraints!

This is particularly apparent if you use swappable models (e.g. AUTH_USER_MODEL), as every app that uses swappable models will need to have migrations if you’re unlucky. As time goes on, more and more third-party apps will get migrations, but in the meantime you can either give them migrations yourself (using MIGRATION_MODULES to store those modules outside of the app’s own module if you wish), or keep the app with your user model unmigrated.

迁移文件

Migrations are stored as an on-disk format, referred to here as “migration files”. These files are actually just normal Python files with an agreed-upon object layout, written in a declarative style.

A basic migration file looks like this:

from django.db import migrations, models

class Migration(migrations.Migration):

    dependencies = [("migrations", "0001_initial")]

    operations = [
        migrations.DeleteModel("Tribble"),
        migrations.AddField("Author", "rating", models.IntegerField(default=0)),
    ]

What Django looks for when it loads a migration file (as a Python module) is a subclass of django.db.migrations.Migration called Migration. It then inspects this object for four attributes, only two of which are used most of the time:

  • dependencies, a list of migrations this one depends on.
  • operations, a list of Operation classes that define what this migration does.

operations 是关键,它们是一个陈述性说明的集合,能告诉Django需要产生什么样的schema 更改。Django scans them and builds an in-memory representation of all of the schema changes to all apps, and uses this to generate the SQL which makes the schema changes.

That in-memory structure is also used to work out what the differences are between your models and the current state of your migrations; Django运行所有的更改,按顺序,在内存中的模型集,以找出你的模型在你上次运行makemigrations的状态。It then uses these models to compare against the ones in your models.py files to work out what you have changed.

You should rarely, if ever, need to edit migration files by hand, but it’s entirely possible to write them manually if you need to. Some of the more complex operations are not autodetectable and are only available via a hand-written migration, so don’t be scared about editing them if you have to.

自定义字段

您无法修改已迁移的自定义字段中的位置参数的数量,而不抛出TypeErrorThe old migration will call the modified __init__ method with the old signature. 如果你需要新的参数,请创建一个关键字参数并加入像 assert 'argument_name' in kwargs 这样的语句到构造器中。

Model managers

New in Django 1.8.

您可以选择将管理器序列化为迁移,并使它们在RunPython操作中可用。这是通过在管理器类上定义use_in_migrations属性来实现的:

class MyManager(models.Manager):
    use_in_migrations = True

class MyModel(models.Model):
    objects = MyManager()

如果您使用from_queryset()函数动态生成管理器类,则需要从生成的类继承以使其可导入:

class MyManager(MyBaseManager.from_queryset(CustomQuerySet)):
    use_in_migrations = True

class MyModel(models.Model):
    objects = MyManager()

请参阅迁移中有关历史模型的注意事项,了解其中的影响。

Adding migrations to apps

Adding migrations to new apps is straightforward - they come preconfigured to accept migrations, and so just run makemigrations once you’ve made some changes.

If your app already has models and database tables, and doesn’t have migrations yet (for example, you created it against a previous Django version), you’ll need to convert it to use migrations; this is a simple process:

$ python manage.py makemigrations your_app_label

This will make a new initial migration for your app. Now, run python manage.py migrate --fake-initial, and Django will detect that you have an initial migration and that the tables it wants to create already exist, and will mark the migration as already applied. (Without the --fake-initial flag, the migrate command would error out because the tables it wants to create already exist.)

Note that this only works given two things:

  • You have not changed your models since you made their tables. For migrations to work, you must make the initial migration first and then make changes, as Django compares changes against migration files, not the database.
  • You have not manually edited your database - Django won’t be able to detect that your database doesn’t match your models, you’ll just get errors when migrations try to modify those tables.

Historical models

When you run migrations, Django is working from historical versions of your models stored in the migration files. If you write Python code using the RunPython operation, or if you have allow_migrate methods on your database routers, you will be exposed to these versions of your models.

Because it’s impossible to serialize arbitrary Python code, these historical models will not have any custom methods that you have defined. They will, however, have the same fields, relationships, managers (limited to those with use_in_migrations = True) and Meta options (also versioned, so they may be different from your current ones).

Warning

This means that you will NOT have custom save() methods called on objects when you access them in migrations, and you will NOT have any custom constructors or instance methods. Plan appropriately!

References to functions in field options such as upload_to and limit_choices_to and model manager declarations with managers having use_in_migrations = True are serialized in migrations, so the functions and classes will need to be kept around for as long as there is a migration referencing them. Any custom model fields will also need to be kept, since these are imported directly by migrations.

In addition, the base classes of the model are just stored as pointers, so you must always keep base classes around for as long as there is a migration that contains a reference to them. On the plus side, methods and managers from these base classes inherit normally, so if you absolutely need access to these you can opt to move them into a superclass.

Considerations when removing model fields

New in Django 1.8.

Similar to the “references to historical functions” considerations described in the previous section, removing custom model fields from your project or third-party app will cause a problem if they are referenced in old migrations.

To help with this situation, Django provides some model field attributes to assist with model field deprecation using the system checks framework.

Add the system_check_deprecated_details attribute to your model field similar to the following:

class IPAddressField(Field):
    system_check_deprecated_details = {
        'msg': (
            'IPAddressField has been deprecated. Support for it (except '
            'in historical migrations) will be removed in Django 1.9.'
        ),
        'hint': 'Use GenericIPAddressField instead.',  # optional
        'id': 'fields.W900',  # pick a unique ID for your field.
    }

After a deprecation period of your choosing (two major releases for fields in Django itself), change the system_check_deprecated_details attribute to system_check_removed_details and update the dictionary similar to:

class IPAddressField(Field):
    system_check_removed_details = {
        'msg': (
            'IPAddressField has been removed except for support in '
            'historical migrations.'
        ),
        'hint': 'Use GenericIPAddressField instead.',
        'id': 'fields.E900',  # pick a unique ID for your field.
    }

You should keep the field’s methods that are required for it to operate in database migrations such as __init__(), deconstruct(), and get_internal_type(). Keep this stub field for as long as any migrations which reference the field exist. For example, after squashing migrations and removing the old ones, you should be able to remove the field completely.

数据迁移

As well as changing the database schema, you can also use migrations to change the data in the database itself, in conjunction with the schema if you want.

Migrations that alter data are usually called “data migrations”; they’re best written as separate migrations, sitting alongside your schema migrations.

Django can’t automatically generate data migrations for you, as it does with schema migrations, but it’s not very hard to write them. Migration files in Django are made up of Operations, and the main operation you use for data migrations is RunPython.

首先,创建一个你可以工作的空的迁移文件,(Django会把文件放在正确的地方,建议一个名字,并为你添加依赖关系):

python manage.py makemigrations --empty yourappname

接下来, 我们打开刚刚生成的迁移文件; 你应该可以看到类似以下的内容:

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

class Migration(migrations.Migration):

    dependencies = [
        ('yourappname', '0001_initial'),
    ]

    operations = [
    ]

Now, all you need to do is create a new function and have RunPython use it. RunPython expects a callable as its argument which takes two arguments - the first is an app registry that has the historical versions of all your models loaded into it to match where in your history the migration sits, and the second is a SchemaEditor, which you can use to manually effect database schema changes (but beware, doing this can confuse the migration autodetector!)

Let’s write a simple migration that populates our new name field with the combined values of first_name and last_name (we’ve come to our senses and realized that not everyone has first and last names). All we need to do is use the historical model and iterate over the rows:

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

def combine_names(apps, schema_editor):
    # We can't import the Person model directly as it may be a newer
    # version than this migration expects. We use the historical version.
    Person = apps.get_model("yourappname", "Person")
    for person in Person.objects.all():
        person.name = "%s %s" % (person.first_name, person.last_name)
        person.save()

class Migration(migrations.Migration):

    dependencies = [
        ('yourappname', '0001_initial'),
    ]

    operations = [
        migrations.RunPython(combine_names),
    ]

Once that’s done, we can just run python manage.py migrate as normal and the data migration will run in place alongside other migrations.

You can pass a second callable to RunPython to run whatever logic you want executed when migrating backwards. If this callable is omitted, migrating backwards will raise an exception.

通过其他应用访问模型

When writing a RunPython function that uses models from apps other than the one in which the migration is located, the migration’s dependencies attribute should include the latest migration of each app that is involved, otherwise you may get an error similar to: LookupError: No installed app with label 'myappname' when you try to retrieve the model in the RunPython function using apps.get_model().

In the following example, we have a migration in app1 which needs to use models in app2. We aren’t concerned with the details of move_m1 other than the fact it will need to access models from both apps. Therefore we’ve added a dependency that specifies the last migration of app2:

class Migration(migrations.Migration):

    dependencies = [
        ('app1', '0001_initial'),
        # added dependency to enable using models from app2 in move_m1
        ('app2', '0004_foobar'),
    ]

    operations = [
        migrations.RunPython(move_m1),
    ]

更多高级迁移

如果你对更高级的迁移操作感兴趣, 或者想写自定义迁移文件, see the migration operations reference and the “how-to” on writing migrations.

Squashing migrations

You are encouraged to make migrations freely and not worry about how many you have; the migration code is optimized to deal with hundreds at a time without much slowdown. 然而,最终你会想从几百个迁移回到几个,这需要挤压。

Squashing is the act of reducing an existing set of many migrations down to one (or sometimes a few) migrations which still represent the same changes.

Django does this by taking all of your existing migrations, extracting their Operations and putting them all in sequence, and then running an optimizer over them to try and reduce the length of the list - for example, it knows that CreateModel and DeleteModel cancel each other out, and it knows that AddField can be rolled into CreateModel.

Once the operation sequence has been reduced as much as possible - the amount possible depends on how closely intertwined your models are and if you have any RunSQL or RunPython operations (which can’t be optimized through) - Django will then write it back out into a new set of initial migration files.

These files are marked to say they replace the previously-squashed migrations, so they can coexist with the old migration files, and Django will intelligently switch between them depending where you are in the history. If you’re still part-way through the set of migrations that you squashed, it will keep using them until it hits the end and then switch to the squashed history, while new installs will just use the new squashed migration and skip all the old ones.

This enables you to squash and not mess up systems currently in production that aren’t fully up-to-date yet. The recommended process is to squash, keeping the old files, commit and release, wait until all systems are upgraded with the new release (or if you’re a third-party project, just ensure your users upgrade releases in order without skipping any), and then remove the old files, commit and do a second release.

支持所有这一切的命令是squashmigrations - 只要将app标签和你想要压缩的迁移名称传递给它,它就会工作:

$ ./manage.py squashmigrations myapp 0004
Will squash the following migrations:
 - 0001_initial
 - 0002_some_change
 - 0003_another_change
 - 0004_undo_something
Do you wish to proceed? [yN] y
Optimizing...
  Optimized from 12 operations to 7 operations.
Created new squashed migration /home/andrew/Programs/DjangoTest/test/migrations/0001_squashed_0004_undo_somthing.py
  You should commit this migration but leave the old ones in place;
  the new migration will be used for new installs. Once you are sure
  all instances of the codebase have applied the migrations you squashed,
  you can delete them.

Note that model interdependencies in Django can get very complex, and squashing may result in migrations that do not run; either mis-optimized (in which case you can try again with --no-optimize, though you should also report an issue), or with a CircularDependencyError, in which case you can manually resolve it.

To manually resolve a CircularDependencyError, break out one of the ForeignKeys in the circular dependency loop into a separate migration, and move the dependency on the other app with it. If you’re unsure, see how makemigrations deals with the problem when asked to create brand new migrations from your models. In a future release of Django, squashmigrations will be updated to attempt to resolve these errors itself.

Once you’ve squashed your migration, you should then commit it alongside the migrations it replaces and distribute this change to all running instances of your application, making sure that they run migrate to store the change in their database.

After this has been done, you must then transition the squashed migration to a normal initial migration, by:

  • Deleting all the migration files it replaces
  • Removing the replaces argument in the Migration class of the squashed migration (this is how Django tells that it is a squashed migration)

Note

Once you’ve squashed a migration, you should not then re-squash that squashed migration until you have fully transitioned it to a normal migration.

序列化值

Migrations are just Python files containing the old definitions of your models - thus, to write them, Django must take the current state of your models and serialize them out into a file.

虽然Django可以序列化大多数东西,但有一些,我们不能序列化为有效的Python表示 - 对于如何将值转换回代码没有Python标准(repr()仅适用于基本值,并且不指定导入路径)。

Django can serialize the following:

  • int, long, float, bool, str, unicode, bytes, None
  • list, set, tuple, dict
  • datetime.date, datetime.time, and datetime.datetime instances (include those that are timezone-aware)
  • decimal.Decimal instances
  • Any Django field
  • Any function or method reference (e.g. datetime.datetime.today) (must be in module’s top-level scope)
  • Any class reference (must be in module’s top-level scope)
  • Anything with a custom deconstruct() method (see below)
Changed in Django 1.7.1:

Support for serializing timezone-aware datetimes was added.

Django can serialize the following on Python 3 only:

  • Unbound methods used from within the class body (see below)

Django cannot serialize:

  • Nested classes
  • Arbitrary class instances (e.g. MyClass(4.3, 5.7))
  • Lambdas

由于__qualname__仅在Python 3中引入,Django只能在Python 3上序列化以下模式(在类体中使用的未绑定方法),但将在Python 2上无法序列化对它的引用:

class MyModel(models.Model):

    def upload_to(self):
        return "something dynamic"

    my_file = models.FileField(upload_to=upload_to)

If you are using Python 2, we recommend you move your methods for upload_to and similar arguments that accept callables (e.g. default) to live in the main module body, rather than the class body.

Adding a deconstruct() method

You can let Django serialize your own custom class instances by giving the class a deconstruct() method. It takes no arguments, and should return a tuple of three things (path, args, kwargs):

  • path should be the Python path to the class, with the class name included as the last part (for example, myapp.custom_things.我的类)If your class is not available at the top level of a module it is not serializable.
  • args should be a list of positional arguments to pass to your class’ __init__ method. Everything in this list should itself be serializable.
  • kwargs should be a dict of keyword arguments to pass to your class’ __init__ method. Every value should itself be serializable.

Note

This return value is different from the deconstruct() method for custom fields which returns a tuple of four items.

Django will write out the value as an instantiation of your class with the given arguments, similar to the way it writes out references to Django fields.

To prevent a new migration from being created each time makemigrations is run, you should also add a __eq__() method to the decorated class. This function will be called by Django’s migration framework to detect changes between states.

As long as all of the arguments to your class’ constructor are themselves serializable, you can use the @deconstructible class decorator from django.utils.deconstruct to add the deconstruct() method:

from django.utils.deconstruct import deconstructible

@deconstructible
class MyCustomClass(object):

    def __init__(self, foo=1):
        self.foo = foo
        ...

    def __eq__(self, other):
        return self.foo == other.foo

The decorator adds logic to capture and preserve the arguments on their way into your constructor, and then returns those arguments exactly when deconstruct() is called.

Python 2 和 3 支持

In order to generate migrations that support both Python 2 and 3, all string literals used in your models and fields (e.g. verbose_name, related_name, etc.), must be consistently either bytestrings or text (unicode) strings in both Python 2 and 3 (rather than bytes in Python 2 and text in Python 3, the default situation for unmarked string literals.) Otherwise running makemigrations under Python 3 will generate spurious new migrations to convert all these string attributes to text.

The easiest way to achieve this is to follow the advice in Django’s Python 3 porting guide and make sure that all your modules begin with from __future__ import unicode_literals, so that all unmarked string literals are always unicode, regardless of Python version. When you add this to an app with existing migrations generated on Python 2, your next run of makemigrations on Python 3 will likely generate many changes as it converts all the bytestring attributes to text strings; this is normal and should only happen once.

多Django版本支持

If you are the maintainer of a third-party app with models, you may need to ship migrations that support multiple Django versions. In this case, you should always run makemigrations with the lowest Django version you wish to support.

The migrations system will maintain backwards-compatibility according to the same policy as the rest of Django, so migration files generated on Django X.Y should run unchanged on Django X.Y+1. The migrations system does not promise forwards-compatibility, however. New features may be added, and migration files generated with newer versions of Django may not work on older versions.

从 South 升级

如果你有使用 South创建的迁移, 使用django.db.migrations升级的过程非常简单:

  • 确认所有的安装都以South创建的迁移完全更新。
  • INSTALLED_APPS中移除 'south'
  • 删除你所有的迁移文件(编号标识的),但不能删除所在目录或 __init__.py - 也需确认删除 .pyc 文件。
  • 运行 python manage.py makemigrations. Django should see the empty migration directories and make new initial migrations in the new format.
  • Run python manage.py migrate --fake-initial. Django will see that the tables for the initial migrations already exist and mark them as applied without running them. (Django won’t check that the table schema match your models, just that the right table names exist).

That’s it! The only complication is if you have a circular dependency loop of foreign keys; in this case, makemigrations might make more than one initial migration, and you’ll need to mark them all as applied using:

python manage.py migrate --fake yourappnamehere
Changed in Django 1.8:

The --fake-initial flag was added to migrate; previously, initial migrations were always automatically fake-applied if existing tables were detected.

库/第三方应用

If you are a library or app maintainer, and wish to support both South migrations (for Django 1.6 and below) and Django migrations (for 1.7 and above) you should keep two parallel migration sets in your app, one in each format.

To aid in this, South 1.0 will automatically look for South-format migrations in a south_migrations directory first, before looking in migrations, meaning that users’ projects will transparently use the correct set as long as you put your South migrations in the south_migrations directory and your Django migrations in the migrations directory.

更多信息请参考 South 1.0 发布说明.

参考

The Migrations Operations Reference
Covers the schema operations API, special operations, and writing your own operations.
The Writing Migrations “how-to”
Explains how to structure and write database migrations for different scenarios you might encounter.