如何在 Django 1.7 中重置迁移

How to reset migrations in Django 1.7

(我知道有一个标题和这个一样,但是问题不一样)。

我设法让我的开发机器迁移和生产迁移不同步。

我有一个使用 South 的 Django 应用程序。我有自己的工作流程,运行良好(这可能不是正确的做事方式,但我没有遇到任何问题)。

基本上我有一个脚本可以将生产数据库转储复制到我的开发机器上。它还复制了迁移文件。这样两者就同步了,我可以像往常一样 运行 向南指挥。

现在我已经升级到1.7,开始使用迁移了。当我使用以前的工作流程(复制数据库转储和从生产环境迁移文件)时,它没有检测到我的开发机器上的更改。

我已经通读了迁移文档,我发现正确的使用方法是

  1. 运行 "make migrations" 和 "migrate" 在我的开发机器上。
  2. 运行 "migrate" 在我的开发机器上实际进行数据库更改
  3. 复制修改过来,包括迁移文件。
  4. 运行 "migrate" 在生产机器上。 (没有 "makemigrations" 步骤)

总之。现在一团糟。我想 "reset" 我的迁移并从头开始,从现在开始正确地做事。

我需要做什么?

  1. 删除迁移的内容table(在两台机器上)?
  2. 删除迁移文件夹的内容? (包括 init.py 文件)。
  3. 根据新的文档开始迁移。

我错过了什么吗? 从生产环境(数据库和迁移文件)复制所有内容之后没有检测到我的开发机器上的任何更改是有原因的

运行

python manage.py migrate your_app zero

这将从 your_app

中删除所有表

如果你愿意,既然你说你想重新开始,你可以删除你的迁移文件夹,或者重命名文件夹,创建一个新的迁移文件夹,然后 运行

python manage.py makemigrations your_app
python manage.py migrate your_app

就像南方一样,你可以随时来回...

# Go to the first migration
python manage.py migrate your_app 0001

# Go to the third migration
python manage.py migrate your_app 0003

因此,假设您的第 4 次迁移一团糟...您始终可以迁移到第 3 次,删除第 4 次迁移文件并重新执行。

注:

这是您的模型应该在不同应用中的原因之一。假设您有 2 个模型:用户和注释。创建 2 个应用程序是一个很好的做法:用户和笔记,以便迁移彼此独立。

尽量不要为所有模型使用一个应用程序

我会在两种环境中执行以下操作(只要代码相同)

  1. 删除您的迁移文件夹
  2. 从 django_migrations 应用程序 = <your app name> 中删除。您也可以截断此 table.
  3. python manage.py makemigrations
  4. python manage.py migrate --fake

在此之后,您的所有更改都应该能够跨环境检测到。

对 harshil 的回答稍作改动:

$ manage.py migrate --fake <appname> zero
$ rm -rf migrations
$ manage.py makemigrations <appname>
$ manage.py migrate --fake <appname>

这将...

  • 假装回滚所有迁移而不触及应用中的实际表
  • 删除应用的现有迁移脚本
  • 为应用创建新的初始迁移
  • 伪造到应用程序初始迁移的迁移

所以这个解决方案今天对我有用。

  1. 删除名为“django_migrations”的 django 迁移 table (无需删除整个数据库 - 只需迁移 table。)

  2. 已删除所有应用程序中的所有迁移文件(例如 0002_auto.py 等),保留 __init__.py 文件。您可以使用来自 Ahmed Bouchefra 的代码:

    找到。 -path "/migrations/.py" -not -name "init.py" -delete

    找到。 -路径“/migrations/.pyc”-delete

(此查找和删除代码仅适用于 linux。对于 Windows,您必须手动删除文件。)

  1. 现在运行以下命令:

    python manage.py makemigrations
    
    python manage.py migrate --fake
    

django 将创建一个新的迁移 table 并将初始迁移伪造到 table 中,而不会触及您现有的数据。享受吧。

如果您想完全重置数据库和架构,请像这样将代码放入任何应用程序中

app/management/commands/resetdb.py

import os
import glob
import shutil
from django.conf import settings
from django.core.management.base import BaseCommand, CommandError
from django.db import connection


class Command(BaseCommand):
    help = 'Resets the database'

    def handle(self, *args, **options):
        dbname = settings.DATABASES["default"]["NAME"]
        with connection.cursor() as cursor:
            cursor.execute("DROP DATABASE %s" % dbname)
            cursor.execute("CREATE DATABASE %s" % dbname)

        base = str(settings.BASE_DIR)
        migrations = glob.glob(os.path.join(base, "*", "migrations"))

        for migration in migrations:
            shutil.rmtree(migration)

        apps = [migration.split("\")[-2] for migration in migrations]
        for app in apps:
            os.system("python manage.py makemigrations %s" % app)
        os.system("python manage.py migrate")

现在使用重置它:

python manage.py resetdb

这将

  • 删除数据库
  • 删除迁移文件夹
  • 进行迁移
  • 迁移新的数据库

我遇到了与此类似的问题,但是在使用 python manage.py showmigrations 测试其中一些相同的解决方案时,我发现我遇到了同样的错误。

最终我发现了这个,它帮助我意识到我把事情搞得太复杂了,基本上定义了两个用户模型。

要重置所有 迁移并重新开始,您可以运行以下操作:

1。重置所有迁移

python manage.py migrate <app_name> zero

ℹ️ If this is causing you issues you can add the --fake flag to the end of the command.

2。创建迁移

python manage.py makemigrations <app_name>

ℹ️ Only do this step if you deleted or altered the migrations files

3。迁移

python manage.py migrate <app_name>

⚠️ if you added the --fake command to step # 1 you will need to add --fake-initial to the migrate command so python manage.py migrate <app_name> --fake-initial

这对我有用

第一步:
删除所有应用程序中的所有“迁移”文件夹

第二步:
创建一个全新的应用程序。
python manage.py justTestApp.
将新应用的新“migrations”文件夹复制到所有应用

第 3 步:
删除“db.sqlite3”文件。
删除“justTestApp”文件夹

第四步:
python manage.py makemigrations
python manage.py migrate

在项目中重置不需要的迁移后,您仍然会遇到测试数据库(由 pytest 创建的数据库)中存在这些不需要的迁移的问题。

您可以通过将 --create-db 添加到您的测试命令来重置 测试数据库

py.test path/to-tests.py --create-db

如@brunofitas 所述,回到之前的迁移对我的情况有所帮助。此后,我删除了从那个点到最后一个 运行 makemigrationsmigrated 的迁移,然后我就完成了。

如果你想要一个完全干净的开始,你会想放弃数据库。这意味着然后重新创建它,添加权限,re-generate 所有迁移,re-run 它们并创建一个超级用户。

好消息是,您可以轻松地将所有这些变成 single/few 行命令。

全新迁移文件

如果删除整个文件夹,则必须 运行 makemigrations 命令提及所有应用名称。如果您经常这样做,那就很麻烦了。要让 Django 查看需要迁移的应用程序,您需要保留 migrations 文件夹和其中的 __init__.py

这是一个 bash 命令:

find . -path "*migrations*" -not -regex ".*__init__.py" -a -not -regex ".*migrations" | xargs rm -rf

然后通常(这应该为所有之前有迁移的应用程序创建迁移):

python manage.py makemigrations

重置数据库

对于SQLite只需删除数据库文件。

对于 PostgreSQL 运行 控制台中的这个:

psql -c "drop database <db_name>;"
psql -c "create database <db_name>;"
psql -c "grant all on database <db_name> to <db_user>;"

最后 re-run 迁移

python manage.py migrate

超级用户

您显然会缺少超级用户,因此您可能还想这样做:

python manage.py createsuperuser

No-input 这样做的方法是将 python 代码输送到 shell:

echo "from django.contrib.auth import get_user_model; User = get_user_model(); User.objects.create_superuser('admin', 'badmin@myproject.com', 'pa$$w0rd')" | python manage.py shell

大体说一下这些很常见的动作 - 帮自己一个忙,写一点bash。在与 Django 一起工作的这些年里,它为我节省了很多很多时间。因为比单行命令更好的是拥有一个完整的实用程序文件来存储更多这些方便的功能。然后你可以 运行 像这样:

django --reset_migrations
db --reset <my_db>
django --migrate

如果您发现自己在重复相同的几个动作,甚至可以将其汇总到一行中。将此添加到您的bash个人资料

reset_django() {
    find . -path "*migrations*" -not -regex ".*__init__.py" -a -not -regex ".*migrations" | xargs rm -rf
    python manage.py makemigrations
    psql -c "drop database <db_name>;"
    psql -c "create database <db_name>;"
    psql -c "grant all on database <db_name> to <db_user>;"
    python manage.py migrate
    echo "from django.contrib.auth import get_user_model; User = get_user_model(); User.objects.create_superuser('admin', 'badmin@myproject.com', 'pa$$w0rd')" | python manage.py shell
}

我的 Django lite 实用程序以获取灵感:

#!/bin/bash


django() {

    project_name=$(basename $PWD)
    project_path="$PWD"
    manage_path="${project_path}/${project_name}/manage.py"

    if [ ! -f $manage_path ] ; then  # No project/manage.py
        echo "Error: Could not locate Django manage.py file."
        return -1
    fi

    if [ $# -eq 0 ] ; then
        echo "Django project detected."
    fi

    while [ ! $# -eq 0 ]
        do
            case "" in

                --help | -h)
                        echo "Django shortcut, unknown commands are forwarded to manage.py"
                        echo "  -c, --check         Run Django manage.py check."
                        echo "  --req           Install requirements."
                        echo "  -r, --run           Run server."
                        echo "  -s, --shell         Run Django shell plus."
                        echo "  -sd, --shell            Run Django shell plus. Debug DB (print sql)"
                        echo ""
                    ;;

                --check | -c)
                        python $manage_path check
                    ;;

                --shell | -s)
                        python $manage_path shell_plus --bpython
                    ;;

                --shell | -sd)
                        python $manage_path shell_plus --bpython --print-sql
                    ;;

                --run | -r)
                        python $manage_path runserver
                    ;;

                --req)
                        pip install -r $project_path/requirements.txt
                    ;;

                --mig | -m)
                        python $manage_path makemigrations
                        python $manage_path migrate
                    ;;

                --reset_migrations)
                        find . -path "*migrations*" -not -regex ".*__init__.py" -a -not -regex ".*migrations" | xargs rm -rf
                        python $manage_path makemigrations
                        ;;

                *)
                    python $manage_path "$@"
                    ;;

            esac
            shift
        done

}