首页 > django > 在SQLite3中更改属性字段类型

在SQLite3中更改属性字段类型 (Change attribute field type in SQLite3)

问题

我试图通过执行空迁移来将CharField中的一个属性的字段类型更改为DecimalField,并通过使用以下内容填充迁移日志来填充新字段:

from __future__ import unicode_literals

from django.db import migrations
from decimal import Decimal

def populate_new_col(apps, schema_editor):  #Plug data from 'LastPrice' into 'LastPrice_v1' in the same model class 'all_ks'.
    all_ks = apps.get_model('blog', 'all_ks')
    for ks in all_ks.objects.all():
        if float(ks.LastPrice):  #Check if conversion to float type is possible...
            print ks.LastPrice
            ks.LastPrice_v1, created = all_ks.objects.get_or_create(LastPrice_v1=Decimal(float(ks.LastPrice)*1.0))
        else:  #...else insert None.
            ks.LastPrice_v1, created = all_ks.objects.get_or_create(LastPrice_v1=None)
        ks.save()

class Migration(migrations.Migration):

    dependencies = [
        ('blog', '0027_auto_20190301_1600'),
    ]

    operations = [
        migrations.RunPython(populate_new_col),
    ]

但是当我尝试迁移时,我一直收到错误:

TypeError: Tried to update field blog.All_ks.LastPrice_v1 with a model instance, <All_ks: All_ks object>. Use a value compatible with DecimalField.

有没有我错过将字符串转换为十进制?仅供参考,'LastPrice'是CharField的旧属性,'LastPrice_v1'是DecimalField的新属性。

解决方法

all_ks.objects.get_or_create()返回All_ks您分配给DecimalField 的对象LastPrice_v1。显然Django抱怨道。你为什么不指定相同ksLastPrice

ks.LastPrice_v1 = float(ks.LastPrice)

也就是说,摆弄手动迁移对你想要实现的目标来说似乎很麻烦(除非你对迁移代码非常熟悉)。如果你不是,你通常会变得更好

  • 在代码中创建新字段
  • 迁移
  • 填充新字段
  • 重命名旧字段
  • 将新字段重命名为原始名称
  • 删除旧字段
  • 再次迁移

所有步骤都是vanilla Django操作,你可以恢复到最后一步的好处(当你刚刚体验到事情可能会发生意外转变时很好)。

问题

I am trying to change the field type of one of attributes from CharField to DecimalField by doing an empty migrations and populate the new field by filling the migrations log with the following:

from __future__ import unicode_literals

from django.db import migrations
from decimal import Decimal

def populate_new_col(apps, schema_editor):  #Plug data from 'LastPrice' into 'LastPrice_v1' in the same model class 'all_ks'.
    all_ks = apps.get_model('blog', 'all_ks')
    for ks in all_ks.objects.all():
        if float(ks.LastPrice):  #Check if conversion to float type is possible...
            print ks.LastPrice
            ks.LastPrice_v1, created = all_ks.objects.get_or_create(LastPrice_v1=Decimal(float(ks.LastPrice)*1.0))
        else:  #...else insert None.
            ks.LastPrice_v1, created = all_ks.objects.get_or_create(LastPrice_v1=None)
        ks.save()

class Migration(migrations.Migration):

    dependencies = [
        ('blog', '0027_auto_20190301_1600'),
    ]

    operations = [
        migrations.RunPython(populate_new_col),
    ]

But I kept getting an error when I tried to migrate:

TypeError: Tried to update field blog.All_ks.LastPrice_v1 with a model instance, <All_ks: All_ks object>. Use a value compatible with DecimalField.

Is there something I missed converting string to Decimal? FYI, ‘LastPrice’ is the old attribute with CharField, and ‘LastPrice_v1’ is the new attribute with DecimalField.

解决方法

all_ks.objects.get_or_create() returns an All_ks object which you assign to the DecimalField LastPrice_v1. So obviously Django complains. Why don't you assign the same ks's LastPrice?

ks.LastPrice_v1 = float(ks.LastPrice)

That said, fiddling around with manual migrations seems a lot of trouble for what you want to achieve (unless you're very familiar with migration code). If you're not, you're usually better off

  • creating the new field in code
  • migrating
  • populating the new field
  • renaming the old field
  • renaming the new field to the original name
  • removing the old field
  • migrating again

All steps are vanilla Django operations, with the bonus that you can revert until the very last step (nice to have when things can take unexpected turns as you've just experienced).

相似信息