在Django中第二次保存模型时出错

在Django中第二次保存模型时出错,django,Django,我有以下模型结构: class Parent(models.Model): fieldA = models.TextField() fieldB = models.TextField() class Child(Parent): fieldC = models.CharField() 我在以下代码片段中注意到一些意外行为: child = Child(fieldA = 'Text fieldA', fieldB = 'Text fieldB', fieldC =

我有以下模型结构:

class Parent(models.Model):
     fieldA = models.TextField()
     fieldB = models.TextField()

class Child(Parent):
     fieldC = models.CharField()
我在以下代码片段中注意到一些意外行为:

child = Child(fieldA = 'Text fieldA', fieldB = 'Text fieldB', fieldC = 'Text fieldC')
child.full_clean()
child.save()

self.assertEqual(Child.objects.count(), 1)
child.delete()
self.assertEqual(Child.objects.count(), 0)

child.full_clean()
child.save()
不了解为什么要添加第二个
child.save()
,会传递断言,但当我想用第二个错误保存它时,它会用
ValueError
失败:

ValueError:禁止保存()以防止由于未保存而导致数据丢失 相关对象“父对象”

同时,我没有看到以下代码中存在任何此类错误:

parent = Parent(fieldA = 'Text fieldA', fieldB = 'Text fieldB')
parent.full_clean()
parent.save()

self.assertEqual(Parent.objects.count(), 1)
parent.delete()
self.assertEqual(Parent.objects.count(), 0)

parent.full_clean()
parent.save()

为什么会这样?有人能告诉我应该如何修复第一个代码段吗?

发生的事情是,您正在利用一种称为“多表继承”的功能

这意味着,它不是表示一个包含三个字段的表的
Child
,而是只有两个字段:
fieldC
和一个外键(
OneToOneField
),指向
Parent
中的记录

删除
子行
时,会同时删除
子行
父行
。当您再次尝试保存
Child
的实例时,
parent\u ptr
OneToOneField
的值仍然包含旧的
parent
行的ID,该行指向不再存在的内容

您可能希望改用抽象基类:


在这里,
Parent
Child
之间没有链接:
Child
表示的表有三个字段,而
Parent
表示的表有两个字段。

发生的事情是,您正在利用一种称为“多表继承”的功能

这意味着,它不是表示一个包含三个字段的表的
Child
,而是只有两个字段:
fieldC
和一个外键(
OneToOneField
),指向
Parent
中的记录

删除
子行
时,会同时删除
子行
父行
。当您再次尝试保存
Child
的实例时,
parent\u ptr
OneToOneField
的值仍然包含旧的
parent
行的ID,该行指向不再存在的内容

您可能希望改用抽象基类:


这里,
Parent
Child
之间没有链接:
Child
表示的表有三个字段,
Parent
表示的表有两个字段。

非常感谢您的澄清。是的,抽象类在这里很好,但是因为我需要有
Parent
类型的对象和它们自己的表,所以我不能在这里使用它。@sebap123在我列出的示例中,
Parent
Child
都有它们自己的表。抽象模型没有自己的表;这几乎就像一张桌子的模板。哦,是的,你说得对。我不知道我怎么会错过。使用这种方法与我正在使用的常规继承有什么区别(除了解决我的问题之外)?一个选项比另一个好吗?在网上我只能找到关于表格创建的信息,这是唯一的区别。@sebap123通常我会推荐抽象模型作为正确答案。除非您特别需要模型继承,否则请坚持使用抽象模型。很少有人希望为多个模型共享一个表;它只对非常特定的用例有用。如果您有其中一个用例,您就会知道它;)非常感谢您的澄清。是的,抽象类在这里很好,但是因为我需要有
Parent
类型的对象和它们自己的表,所以我不能在这里使用它。@sebap123在我列出的示例中,
Parent
Child
都有它们自己的表。抽象模型没有自己的表;这几乎就像一张桌子的模板。哦,是的,你说得对。我不知道我怎么会错过。使用这种方法与我正在使用的常规继承有什么区别(除了解决我的问题之外)?一个选项比另一个好吗?在网上我只能找到关于表格创建的信息,这是唯一的区别。@sebap123通常我会推荐抽象模型作为正确答案。除非您特别需要模型继承,否则请坚持使用抽象模型。很少有人希望为多个模型共享一个表;它只对非常特定的用例有用。如果您有其中一个用例,您就会知道它;)
class Base(models.Model):
     fieldA = models.TextField()
     fieldB = models.TextField()
     class Meta:
        abstract = True


class Parent(Base):
    pass

class Child(Base):
     fieldC = models.CharField()