![](/img/trans.png)
[英]Django change Model's field type from CharField to JSONField
[英]Django change database field from integer to CharField
我有一個帶有填充(Postgres)數據庫的 Django 應用程序,該數據庫有一個整數字段,我需要將其更改為 CharField。 我需要開始在該字段中存儲帶有前導零的數據。 如果我運行 migrate (Django 1.8.4),我會收到以下錯誤:
psycopg2.ProgrammingError: operator does not exist: character varying >= integer
HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts.
我嘗試搜索谷歌,但並沒有真正找到太多幫助。 我真的不知道我應該在這里做什么。 任何人都可以幫忙嗎?
您需要生成架構遷移。 您如何做到這一點取決於您使用的 Django 版本(1.7 版和更新版本具有內置遷移;舊版本的 Django 將使用south
)。
注意:如果此數據是生產數據,則您需要非常小心地處理。 確保您有一個已知良好的數據副本,如果事情變得棘手,您可以重新安裝。 在非生產環境中測試您的遷移。 是。 小心!
至於字段上的轉換(從 IntegerField 到 CharField)和字段值上的轉換(以前導零開頭) - Django 無法為您執行此操作,您必須手動編寫。 執行此操作的正確方法是使用django.db.migrations.RunPython
遷移命令( 請參閱此處)。
我的建議是生成多個遷移; 創建一個新的 IntegerField, my_new_column
,然后通過 RunPython 寫入這個新列。 然后,運行第二次遷移,刪除原始 CharField my_old_column
並將my_new_column
重命名為my_old_column
。
最初,我認為會有一個簡單的解決方案,讓 Django 或 Postgres 自動進行轉換,但它似乎不能那樣工作。 我認為其他人提出的一些建議可能有效,但我想出了一個我自己的簡單解決方案。 這是在生產數據庫上完成的,所以我必須小心。 我最終將字符字段添加到模型中並進行了遷移。 然后我在 python shell 中運行一個小腳本,復制整數字段中的數據,進行我需要的轉換,然后將其寫入生產數據庫中同一記錄中的新字段。
例如:
members = Members.objects.all()
for mem in members:
mem.memNumStr = str(mem.memNum)
... more data processing here
mem.save()
所以現在,我在表中的 str 字段和 int 字段中復制了數據。 然后,我可以修改訪問該字段的視圖並在生產數據庫上對其進行測試,而不會破壞舊代碼。 完成后,我可以刪除舊的 int 字段。 有點涉及,但最終非常簡單。
從 django 2.x 你只需要改變字段類型
IntegerField to CharField
並且 django 將自動為您更改字段和遷移數據。
我認為完整的代碼示例會有所幫助。 我遵循了 ken-koster 在上面的評論中概述的方法。 我最終進行了兩次遷移(0091 和 0092)。 似乎可以將兩次遷移壓縮為一次遷移,但我並沒有走那么遠。 (也許 Django 會自動執行此操作,但可以使用此處的框架,以防字符串值比簡單的 int 到字符串轉換更復雜。我還包含了一個反向轉換示例。)
第一次遷移(0091):
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('myapp', '0090_auto_20200622_1452'),
]
operations = [
# store original values in tmp fields
migrations.RenameField(model_name='member',
old_name='mem_num',
new_name='mem_num_tmp'),
# add back fields as string fields
migrations.AddField(
model_name='member',
name='mem_num',
field=models.CharField(default='0', max_length=64, verbose_name='Number of members'),
),
]
第二次遷移(0092):
from django.db import migrations
def copyvals(apps, schema_editor):
Member = apps.get_model("myapp", "Member")
members = Member.objects.all()
for member in members:
member.rotate_xy = str(member.mem_num_tmp)
member.save()
def copyreverse(apps, schema_editor):
Member = apps.get_model("myapp", "Member")
members = Member.objects.all()
for member in members:
try:
member.mem_num_tmp = int(member.mem_num)
member.save()
except Exception:
print("Reverse migration for member %s failed." % member.name)
print(member.mem_num)
class Migration(migrations.Migration):
dependencies = [
('myapp', '0091_custom_migration'),
]
operations = [
# convert integers to strings
migrations.RunPython(copyvals, reverse_code=copyreverse),
# remove the tmp field
migrations.RemoveField(
model_name='member',
name='mem_num_tmp',
),
]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.