手動遷移

有時,Django 生成的遷移是不夠的。當你想要進行資料遷移時尤其如此。

例如,讓我們有這樣的模型:

class Article(models.Model):
    title = models.CharField(max_length=70)

此模型已有現有資料,現在你要新增 SlugField

class Article(models.Model):
    title = models.CharField(max_length=70)
    slug = models.SlugField(max_length=70)

你建立了遷移以新增欄位,但現在你想根據他們的 title 為所有現有文章設定 slug。

當然,你可以在終端中執行以下操作:

$ django-admin shell
>>> from my_app.models import Article
>>> from django.utils.text import slugify
>>> for article in Article.objects.all():
...     article.slug = slugify(article.title)
...     article.save()
...
>>>

但是你必須在所有的環境中(例如你的辦公室桌面,你的膝上型電腦……)這樣做,你的所有同事也必須這樣做,你必須在分期和推動時考慮它。生活。

為了一勞永逸,我們將在遷移中實現。首先建立一個空遷移:

$ django-admin makemigrations --empty app_name

這將建立一個空的遷移檔案。開啟它,它包含一個基礎骨架。假設你之前的遷移被命名為 0023_article_slug,這個名字叫 0024_auto_20160719_1734。以下是我們將在遷移檔案中編寫的內容:

# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-07-19 15:34
from __future__ import unicode_literals

from django.db import migrations
from django.utils.text import slugify

def gen_slug(apps, schema_editor):
    # We can't import the Article model directly as it may be a newer
    # version than this migration expects. We use the historical version.
    Article = apps.get_model('app_name', 'Article')
    for row in Article.objects.all():
        row.slug = slugify(row.name)
        row.save()

class Migration(migrations.Migration):

    dependencies = [
        ('hosting', '0023_article_slug'),
    ]

    operations = [
        migrations.RunPython(gen_slug, reverse_code=migrations.RunPython.noop),
        # We set `reverse_code` to `noop` because we cannot revert the migration
        # to get it back in the previous state.
        # If `reverse_code` is not given, the migration will not be reversible,
        # which is not the behaviour we expect here.
    ]