1 回答

TA貢獻1805條經驗 獲得超9個贊
您的問題是關于數據遷移嗎?
如果是這樣,您應該閱讀鏈接的文檔。
在我看來,您的第一個提案確實是最好的。
這是如何做的。
第 1 步:對模型進行更改
您更改模型以匹配您的目標:
# models.py
from django.db import models
class Office(models.Model):
? ? name = models.CharField(max_length=1000)
class User(models.Model):
? ? email = models.EmailField()
class Profile(models.Model):
? ? user = models.OneToOneField(User, on_delete=models.CASCADE)
? ? offices = models.ManyToManyField(Office)
運行makemigrations:
(.venv) ~/c/s/m/mysite> ./manage.py makemigrations?
Migrations for 'so':
? so/migrations/0002_auto_20200825_1311.py
? ? - Remove field offices from user
? ? - Add field offices to profile
第 2 步:編輯遷移文件以遷移現有數據
打開上一步創建的文件。它看起來像:
# Generated by Django 3.1 on 2020-08-25 13:11
from django.db import migrations, models
class Migration(migrations.Migration):
? ? dependencies = [
? ? ? ? ('so', '0001_initial'),
? ? ]
? ? operations = [
? ? ? ? migrations.RemoveField(
? ? ? ? ? ? model_name='user',
? ? ? ? ? ? name='offices',
? ? ? ? ),
? ? ? ? migrations.AddField(
? ? ? ? ? ? model_name='profile',
? ? ? ? ? ? name='offices',
? ? ? ? ? ? field=models.ManyToManyField(to='so.Office'),
? ? ? ? ),
? ? ]
你需要在這里做兩件事:
您可以看到,對于 Django 生成的命令,它將首先刪除舊的 FK,然后添加新的。你應該改變它,所以它是相反的。
然后你將不得不編寫一些 python 代碼,遷移將在正確的時間執行
正確的時間是在創建新 FK 之后和舊 FK 被刪除之前,這樣您就可以訪問這兩個 FK 來遷移數據:
# Generated by Django 3.1 on 2020-08-25 13:11
from django.db import migrations, models
def migrate_office_to_profile(apps, schema_editor):
? ? User = apps.get_model('so', 'User')
? ? for user in User.objects.all():
? ? ? ? for office in user.office_set:
? ? ? ? ? ? user.profile.add(office)
def migrate_office_to_user(apps, schema_editor):
? ? Profile = apps.get_model('so', 'Profile')
? ? for profile in Profile.objects.all():
? ? ? ? profile.user.add(profile.offices)
? ? ? ? for office in profile.office_set:
? ? ? ? ? ? profile.user.add(office)
class Migration(migrations.Migration):
? ? dependencies = [
? ? ? ? ('so', '0001_initial'),
? ? ]
? ? operations = [
? ? ? ? migrations.AddField(
? ? ? ? ? ? model_name='profile',
? ? ? ? ? ? name='offices',
? ? ? ? ? ? field=models.ManyToManyField(to='so.Office'),
? ? ? ? ),
? ? ? ? # This is where your python code will be called
? ? ? ? migrations.RunPython(
? ? ? ? ? ? # This is called in the forward migration
? ? ? ? ? ? migrate_office_to_profile,
? ? ? ? ? ? # This is called in the backward migration
? ? ? ? ? ? reverse_code=migrate_office_to_user
? ? ? ? ),
? ? ? ? migrations.RemoveField(
? ? ? ? ? ? model_name='user',
? ? ? ? ? ? name='offices',
? ? ? ? ),
? ? ]
我還沒有在真實數據上測試過這個。這是你的部分。
第 3 步:運行和調試您的遷移
復制您的數據庫,運行遷移并查看它是如何工作的:
(.venv) ~/c/s/m/mysite> ./manage.py migrate
Operations to perform:
? Apply all migrations: admin, auth, contenttypes, sessions, so
Running migrations:
? Applying so.0002_auto_20200825_1311... OK
在處理數據遷移時,您應該始終編寫和調試反向遷移:
(.venv) ~/c/s/m/mysite> ./manage.py migrate so 0001
Operations to perform:
? Target specific migration: 0001_initial, from so
Running migrations:
? Rendering model states... DONE
? Unapplying so.0002_auto_20200825_1311... OK
請記住,遷移文件被添加到版本控制和軟件的一部分。
===編輯===
闡明反向或向后遷移的概念。
您的 Django 遷移通常只以一種方式運行:增加遷移數量。
但是對于您在開發過程中可能應用的所有測試和仔細思考,您不能總是考慮生產數據。代碼很“簡單”,因為它在生產中與在您的開發服務器上是一樣的。但生產數據通常不同。
在部署期間 Django 遷移可能會失敗。例如,因為您正在添加一個您認為只能為真的顯式唯一約束。但是不知何故,對于生產數據,遷移會引發完整性錯誤。
然后,您將陷入半完成的遷移和沒有遷移就無法運行的新代碼。如果您花時間確保您的遷移可以前后運行而不會丟失數據,您可以安全地撤消遷移并恢復到以前的代碼并返回以找出問題所在,而不必修復它當場。
對于模型結構,前向和后向遷移由 Django 自動處理,但是對于數據遷移,您必須編寫給migrations.RunPython.
添加回答
舉報