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

使用django-money执行数据迁移时遇'MoneyField无_currency_field属性'错误

问题分析与解决方案

问题原因

在Django数据迁移中,通过app.get_model()获取的是迁移专用的模型代理类,而非项目中定义的实际模型类。djmoney的MoneyField底层会自动生成对应的货币字段(比如gst_amount_currency),但迁移代理模型并没有完整初始化MoneyField的关联属性(如_currency_field),导致实例化模型对象时触发字段赋值逻辑出错。

解决方案

方案1:批量更新(推荐,性能最优)

无需实例化模型对象,直接通过QuerySet的update方法批量设置值,绕过字段的属性赋值逻辑:

from djmoney.money import Money
from django.db import migrations

def migrate_invoices(app, _):
    Invoice = app.get_model("users", "Invoice")
    # 直接批量更新,无需遍历实例
    Invoice.objects.update(gst_amount=Money(10, 'AUD'))

class Migration(migrations.Migration):
    operations = [
        migrations.RunPython(migrate_invoices, migrations.RunPython.noop)
    ]

方案2:直接操作底层数据库字段

如果需要逐个处理实例(比如有复杂业务逻辑),可以直接操作MoneyField生成的两个底层字段(金额字段+货币字段),避免触发MoneyField的属性设置逻辑:

from django.db import migrations

def migrate_invoices(app, _):
    Invoice = app.get_model("users", "Invoice")
    for invoice in Invoice.objects.all().iterator():  # 用iterator减少内存占用
        # 直接操作底层字段,绕过MoneyField的__set__方法
        invoice.gst_amount = 10
        invoice.gst_amount_currency = 'AUD'
        invoice.save(update_fields=['gst_amount', 'gst_amount_currency'])

class Migration(migrations.Migration):
    operations = [
        migrations.RunPython(migrate_invoices, migrations.RunPython.noop)
    ]

方案3:原生SQL更新

如果上述方法仍有问题,可以直接执行原生SQL语句更新数据:

from django.db import migrations

def migrate_invoices(app, _):
    db_alias = app.connection.alias
    with app.connection.cursor() as cursor:
        cursor.execute(
            "UPDATE users_invoice SET gst_amount = %s, gst_amount_currency = %s",
            [10, 'AUD']
        )

class Migration(migrations.Migration):
    operations = [
        migrations.RunPython(migrate_invoices, migrations.RunPython.noop)
    ]

内容的提问来源于stack exchange,提问作者richflow

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 15:45:55