You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django中将CharField改为ForeignKey执行迁移时遇TypeError的解决求助

Django中将CharField改为ForeignKey执行迁移时遇TypeError的解决求助

大家好,我最近在Django项目里遇到了个迁移相关的麻烦,想请各位大佬帮忙支招:

最开始我的Order模型里,discount_code字段是个普通的CharField:

class Order(models.Model):
    # ... 其他字段
    discount_code = models.CharField()

后来开发过程中,我们决定把单纯的文本折扣码改成一个独立的DiscountCode模型,用来存储折扣码、折扣百分比、起止日期等更多信息,所以需要把Order里的discount_code改成ForeignKey:

class Order(models.Model):
    # ... 其他字段
    discount_code = models.ForeignKey(to=DiscountCode, on_delete=models.PROTECT, null=True, blank=True)

问题来了,这期间已经生成了几百条订单,其中一些已经填了折扣码。直接跑迁移的话肯定失败,毕竟CharField和ForeignKey的类型完全不兼容。

于是我尝试自定义迁移文件来处理数据迁移,先创建DiscountCode模型,再把现有订单里的折扣码转换成对应的DiscountCode实例,最后修改Order的字段类型。但运行python manage.py migrate时还是报错了:

TypeError: Tried to update field orders.Order.discount_code with a model instance, <DiscountCode: DiscountCode object (85)>. Use a value compatible with CharField.

下面是我写的迁移文件代码:

# Generated by Django 3.2 on 2022-09-20 05:13
from django.db import migrations, models
import django.db.models.deletion
from datetime import date

def create_discount_objects(apps, schema_editor):
    Order = apps.get_model('orders', 'Order')
    DiscountCode = apps.get_model('orders', 'DiscountCode')

    # Get a list of unique discount codes from the existing orders
    discount_codes = Order.objects.exclude(discount_code=None).order_by('discount_code').values_list('discount_code', flat=True).distinct('discount_code')

    # Create new Discount objects for each discount code
    discount_objects = []
    for code in discount_codes:
        if code is not None:
            discount_objects.append(DiscountCode(code=code, percentage=10.0, start_date=date(2023,4,20), end_date=date(2023,4,20)))
    DiscountCode.objects.bulk_create(discount_objects)

    # Update the existing orders to link them to the corresponding Discount objects
    for order in Order.objects.all():
        if order.discount_code is not None:
            discount = DiscountCode.objects.get(code=order.discount_code)
            order.discount_code = discount
            order.save()

class Migration(migrations.Migration):
    dependencies = [
        ('orders', '0012_alter_requiredpart_part_quantity'),
    ]

    operations = [
        migrations.CreateModel(
            name='DiscountCode',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('code', models.CharField(max_length=255, unique=True)),
                ('percentage', models.FloatField()),
                ('status', models.CharField(choices=[('active', 'Active'), ('expired', 'Expired'), ('inactive', 'Inactive')], default='active', max_length=10)),
                ('start_date', models.DateField()),
                ('end_date', models.DateField()),
                ('notes', models.TextField(blank=True, null=True)),
            ],
        ),
        migrations.RunPython(create_discount_objects),
        migrations.AlterField(
            model_name='order',
            name='discount_code',
            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='orders.discountcode'),
        ),
    ]

我之前也找过类似的问题,但都没解决,现在实在没办法了,有没有大佬能帮我看看哪里出问题了?

备注:内容来源于stack exchange,提问作者icesoup

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.22 15:09:32