使用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
相关产品推荐
相关产品推荐

