Django模型查询报错:缺失inventory_instance_id列求助
问题分析与解决:Django模型关联迁移导致查询失败
问题现象
查询Character.objects.all()时触发错误:
OperationalError: no such column: oblivionalchemy_character.inventory_instance_id
模型代码
当前oblivionalchemy.models中的定义:
class InventoryInstance(models.Model): character_name = models.ForeignKey('oblivionalchemy.Character', on_delete=models.CASCADE, null=True, related_name="character") items = models.JSONField(default=dict)
class Character(models.Model): user = models.ForeignKey('discordbot.DiscordUser', on_delete=models.CASCADE, null=True, related_name="characters") name = models.CharField(max_length=40) strength = models.IntegerField(default=10) endurance = models.IntegerField(default=10) agility = models.IntegerField(default=10) speed = models.IntegerField(default=10) willpower = models.IntegerField(default=10) intelligence = models.IntegerField(default=10) personality = models.IntegerField(default=10) luck = models.IntegerField(default=10) alchemy = models.IntegerField(default=10) survival = models.IntegerField(default=10) blade = models.IntegerField(default=10) marksman = models.IntegerField(default=10) inventory_instance = models.OneToOneField('inventory.InventoryInstance', on_delete=models.CASCADE, related_name="character", null=True, blank=True)
初始迁移文件
oblivionalchemy app
class Migration(migrations.Migration): initial = True dependencies = [ ('discordbot', '0001_initial'), ('inventory', '0001_initial'), ] operations = [ migrations.CreateModel( name='Character', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(max_length=40)), ('strength', models.IntegerField(default=10)), ('endurance', models.IntegerField(default=10)), ('agility', models.IntegerField(default=10)), ('speed', models.IntegerField(default=10)), ('willpower', models.IntegerField(default=10)), ('intelligence', models.IntegerField(default=10)), ('personality', models.IntegerField(default=10)), ('luck', models.IntegerField(default=10)), ('alchemy', models.IntegerField(default=10)), ('survival', models.IntegerField(default=10)), ('blade', models.IntegerField(default=10)), ('marksman', models.IntegerField(default=10)), ('inventory_instance', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='character', to='inventory.inventoryinstance')), ('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='characters', to='discordbot.user')), ], ), ]
discordbot app
class Migration(migrations.Migration): initial = True dependencies = [ ] operations = [ migrations.CreateModel( name='User', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('discord_id', models.CharField(blank=True, max_length=100, unique=True)), ], ), ]
inventory app
class Migration(migrations.Migration): initial = True dependencies = [ ] operations = [ migrations.CreateModel( name='InventoryInstance', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('items', models.JSONField(default=dict)), ], ), migrations.CreateModel( name='InventoryItem', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(max_length=40)), ('weight', models.IntegerField(default=0)), ('hitpoints', models.IntegerField(default=100)), ('is_default', models.BooleanField(default=False)), ('effects', models.JSONField(default=inventory.models.default_effects_for_item)), ], ), ]
问题原因
- 模型关联冲突:
InventoryInstance定义了指向Character的ForeignKey,同时Character又定义了指向InventoryInstance的OneToOneField,且两者的related_name均为character,导致字段映射逻辑混乱。 - 模型归属不一致:
InventoryInstance代码位于oblivionalchemy.models,但inventoryapp的初始迁移却创建了该模型,导致Django无法正确匹配模型与数据库表的关联。 - 迁移执行异常:初始迁移中虽定义了
inventory_instance字段,但可能因之前的迁移操作失败,数据库中未实际创建该字段;同时先存在Character记录再添加关联,迁移未正确处理存量数据。
解决步骤
1. 修正模型关联逻辑
按照DiscordUser → Character → InventoryInstance的创建流程,清理重复关联,统一模型归属:
# 若InventoryInstance属于inventory app,移至inventory/models.py # inventory/models.py class InventoryInstance(models.Model): items = models.JSONField(default=dict) # oblivionalchemy/models.py class Character(models.Model): user = models.ForeignKey('discordbot.DiscordUser', on_delete=models.CASCADE, null=True, related_name="characters") # 保留原有属性 inventory_instance = models.OneToOneField('inventory.InventoryInstance', on_delete=models.CASCADE, related_name="character", null=True, blank=True)
2. 修复迁移与数据库不一致
- 备份数据库,避免数据丢失。
- 若迁移已应用但字段缺失,创建空迁移手动补全字段:
编辑生成的迁移文件:python manage.py makemigrations --empty oblivionalchemy
执行迁移:from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ ('oblivionalchemy', '0001_initial'), # 替换为当前最新迁移编号 ] operations = [ migrations.AddField( model_name='character', name='inventory_instance', field=models.OneToOneField(blank=True, null=True, on_delete=models.CASCADE, related_name='character', to='inventory.inventoryinstance'), ), ]python manage.py migrate - 若迁移彻底混乱,可重置迁移(需备份数据):
- 删除各app下
migrations文件夹内除__init__.py外的所有文件。 - 清空数据库中
django_migrations表。 - 重新生成并执行迁移:
python manage.py makemigrations python manage.py migrate
- 删除各app下
3. 同步存量数据
- 关联无
DiscordUser的Character记录:from discordbot.models import DiscordUser from oblivionalchemy.models import Character orphan_chars = Character.objects.filter(user__isnull=True) for char in orphan_chars: # 根据业务逻辑创建或关联DiscordUser,示例为创建临时用户 user, _ = DiscordUser.objects.get_or_create(discord_id=f'temp_{char.id}') char.user = user char.save() - 为存量
Character创建对应InventoryInstance:from inventory.models import InventoryInstance from oblivionalchemy.models import Character for char in Character.objects.all(): if not char.inventory_instance: inv = InventoryInstance.objects.create(items={}) char.inventory_instance = inv char.save()
内容的提问来源于stack exchange,提问作者Syllogism
相关产品推荐
相关产品推荐

