cqcum6er
cqcum6er

Reputation: 57

Change attribute field type in SQLite3

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.

Upvotes: 0

Views: 71

Answers (1)

Endre Both
Endre Both

Reputation: 5730

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).

Upvotes: 1

Related Questions