Изменить тип поля атрибута в SQLite3

#django #python-2.7 #django-models #sqlite

#django #python-2.7 #django-модели #sqlite

Вопрос:

Я пытаюсь изменить тип поля одного из атрибутов с 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.

Ответ №1:

all_ks.objects.get_or_create() возвращает All_ks объект, который вы присваиваете десятичному полю LastPrice_v1 . Очевидно, что Django жалуется. Почему бы вам не назначить те же ks ‘s LastPrice ?

 ks.LastPrice_v1 = float(ks.LastPrice)
  

Тем не менее, возня с ручной миграцией кажется большой проблемой для того, чего вы хотите достичь (если вы не очень хорошо знакомы с кодом миграции). Если вы этого не сделаете, вам обычно лучше

  • создание нового поля в коде
  • миграция
  • заполнение нового поля
  • переименование старого поля
  • переименование нового поля в исходное имя
  • удаление старого поля
  • повторная миграция

Все шаги являются обычными операциями Django, с бонусом, что вы можете вернуться к самому последнему шагу (приятно иметь, когда все может принять неожиданный оборот, как вы только что испытали).

Комментарии:

1. Хорошо, теперь это работает для значений, которые можно преобразовать в float, но почему-то строковым значениям не было присвоено значение null. Я изменил часть else на ks. LastPrice_v1 = Нет

2. NVM я получаю исключение ValueError для работы с попыткой … за исключением. Также я думал, что заполнение нового поля работает только при выполнении пустых миграций с помощью RunPython в операциях журнала миграций?

3. try/except ValueError это правильный путь, да. Боюсь, я не смогу помочь с кодом миграции; если вы не занимаетесь реструктуризацией баз данных на регулярной основе, я считаю, что проще и безопаснее выполнять любые изменения, как описано выше.