1 回答

TA貢獻(xiàn)1805條經(jīng)驗(yàn) 獲得超9個贊
您的問題是關(guān)于數(shù)據(jù)遷移嗎?
如果是這樣,您應(yīng)該閱讀鏈接的文檔。
在我看來,您的第一個提案確實(shí)是最好的。
這是如何做的。
第 1 步:對模型進(jìn)行更改
您更改模型以匹配您的目標(biāo):
# 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)
運(yùn)行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 步:編輯遷移文件以遷移現(xiàn)有數(shù)據(jù)
打開上一步創(chuàng)建的文件。它看起來像:
# 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,然后添加新的。你應(yīng)該改變它,所以它是相反的。
然后你將不得不編寫一些 python 代碼,遷移將在正確的時間執(zhí)行
正確的時間是在創(chuàng)建新 FK 之后和舊 FK 被刪除之前,這樣您就可以訪問這兩個 FK 來遷移數(shù)據(jù):
# 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',
? ? ? ? ),
? ? ]
我還沒有在真實(shí)數(shù)據(jù)上測試過這個。這是你的部分。
第 3 步:運(yùn)行和調(diào)試您的遷移
復(fù)制您的數(shù)據(jù)庫,運(yùn)行遷移并查看它是如何工作的:
(.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
在處理數(shù)據(jù)遷移時,您應(yīng)該始終編寫和調(diào)試反向遷移:
(.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 遷移通常只以一種方式運(yùn)行:增加遷移數(shù)量。
但是對于您在開發(fā)過程中可能應(yīng)用的所有測試和仔細(xì)思考,您不能總是考慮生產(chǎn)數(shù)據(jù)。代碼很“簡單”,因?yàn)樗谏a(chǎn)中與在您的開發(fā)服務(wù)器上是一樣的。但生產(chǎn)數(shù)據(jù)通常不同。
在部署期間 Django 遷移可能會失敗。例如,因?yàn)槟谔砑右粋€您認(rèn)為只能為真的顯式唯一約束。但是不知何故,對于生產(chǎn)數(shù)據(jù),遷移會引發(fā)完整性錯誤。
然后,您將陷入半完成的遷移和沒有遷移就無法運(yùn)行的新代碼。如果您花時間確保您的遷移可以前后運(yùn)行而不會丟失數(shù)據(jù),您可以安全地撤消遷移并恢復(fù)到以前的代碼并返回以找出問題所在,而不必修復(fù)它當(dāng)場。
對于模型結(jié)構(gòu),前向和后向遷移由 Django 自動處理,但是對于數(shù)據(jù)遷移,您必須編寫給migrations.RunPython.
添加回答
舉報