簡體   English   中英

Django 將數據庫字段從整數更改為 CharField

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM