django - 无法分配外键

Posted

技术标签:

【中文标题】django - 无法分配外键【英文标题】:django - can't assign a foreign key 【发布时间】:2015-08-30 04:59:40 【问题描述】:

由于未知原因,我无法将Item_rarity 表的外键实例分配给Detailed_item 表。 Django 抛出错误:

无法分配“u'Basic'”:“Detailed_item.rarity”必须是“Item_rarity”实例。

...但是在Item_rarity 字典中存在“基本”记录 - 我可以从管理面板中选择它并手动创建Detailed_item 记录。

我已经定义了模型:

class Detailed_item(models.Model):
    item_id = models.IntegerField(primary_key=True)
    name = models.CharField(max_length=50)
    level = models.IntegerField()
    icon = models.CharField(max_length=150)
    rarity = models.ForeignKey('Item_rarity')
    general_type = models.ForeignKey('Item_type')
    detailed_type = models.ForeignKey('Item_detailed_type')

class Item_rarity(models.Model):
    name = models.CharField(max_length=15, primary_key=True)

class Item_type(models.Model):
    name = models.CharField(max_length=15, primary_key=True)

class Item_detailed_type(models.Model):
    name = models.CharField(max_length=20, primary_key=True)

在视图中,我尝试以这种方式填充它(插入多个项目):

...
   items = get_all_items()  #get dict of items
        for element in items:
            tmp_det_type = ''
            for key, val in element.iteritems():
            #get 'detailed type' from inner dict
                if key == "type":
                    tmp_det_type = val

            item = Detailed_item(
                item_id=element['id'],
                name=element['name'],
                level=element['level'],
                icon=element['icon'],
                rarity=element['rarity'],  #error
                general_type=element['type'],
                detailed_type=tmp_det_type,
                )

            item.save()

...

我什至尝试硬编码“基本”字符串,但它也不起作用。

* 已解决 * 接下来的两个条目,即Item_typeItem_detailed_type 也是无效的。 正确代码:

from app.models import Detailed_item, Item_rarity, Item_type, Item_detailed_type
...
   items = get_all_items()  #get dict of items
        for element in items:
            tmp_det_type = ''
            for key, val in element.iteritems():
            #get 'detailed type' from inner dict
                if key == "type":
                    tmp_det_type = val

                #create objects with string values
                obj_rarity = Item_rarity(name=element['rarity'])
                obj_item_type = Item_type(name=element['type'])
                obj_item_detailed_type = Item_detailed_type(name=tmp_det_type)

                item = Detailed_item(
                    item_id=element['id'],
                    name=element['name'],
                    level=element['level'],
                    icon=element['icon'],
                    rarity=obj_rarity,
                    general_type=obj_item_type,
                    detailed_type=obj_item_detailed_type,
                    )


            item.save()

...

【问题讨论】:

期待一个对象实例,element['rarity'] 的值是多少? 这是一个字符串“Basic”,可以在stdio上毫无问题地打印。 啊,那么模型需要一个值为Basic的稀有实例 【参考方案1】:

在存储Detailed_item 对象时应传递Item_rarity 实例,因为Item_rarity 是Detailed_item 中的外键相关对象。

您可能传递了Basic 字符串而不是<Basic Object> 本身。

使用 ORM 在 django 中创建对象时,任何与 foreign_key 相关的对象都应提供实例本身,而不是对象的 id(pk),而从数据库中获取数据时,您可以使用任一实例或实例的 id(pk)。

class ParentModel(models.Model):
    model_field = models.CharField(max_length=16)

class MyModel(models.Model):
    some_field = models.ForeignKey('ParentModel')

parent_model = ParentModel.objects.create(model_field='some_data')

my_model = MyModel.objects.create(some_field=parent_model)
                                             ^^^^^^^^^^^^

这里注意传递的是parent_model对象本身而不是id

在取回数据时,

parent_model = ParentModel.objects.get(model_field='some_data')

my_model = MyModel.objects.get(some_field=parent_model)

or

my_model = MyModel.objects.get(some_field=parent_model.id)

在获取数据的情况下两者都可以工作。

【讨论】:

可以写成更短的形式,例如:my_model = parentModel(model_field='some data') 但两者有什么区别? 带有 .objects.create(...) 的版本创建一个对象并立即将其插入数据库,而较短的版本需要使用 parentModel.save() 保存它。在循环中尝试 Item_rarity.objects.create(...) 给了我一个完整性错误(试图复制 PK)。【参考方案2】:

如果将kwarg更改为rarity_name,则不必在创建时提供相关对象:

item = Detailed_item(
            item_id=element['id'],
            name=element['name'],
            level=element['level'],
            icon=element['icon'],
            rarity_name=element['rarity'],  # no error
            general_type=element['type'],
            detailed_type=tmp_det_type,
            )

我只用常规 id 字段(自动 pk)对此进行了测试,但它 应该可以很好地使用您的主键。

例如

class SimpleModel(Model):
    value = TextField(blank=True)

class ComplexModel(Model):
    simple = ForeingKey(SimpleModel)
    title = TextField(unique=True)

ComplexModel.objects.create(title='test', simple_id=1)

【讨论】:

以上是关于django - 无法分配外键的主要内容,如果未能解决你的问题,请参考以下文章

django 我无法用 2 个外键保存表单

外键 id 无法加载到 Django 模板的下拉列表中

Django:在运行单元测试之前创建测试表时“无法添加外键约束”

Django - sqlclear 无法删除具有 AbstractUser 外键约束的数据库

我无法让这个外键表值显示在 django 模板中

Django:1215,“无法在只有一个字段的模型上添加外键约束”