Django:如何在不删除父类对象的情况下删除子类对象?

时间:2012-02-24 23:54:14

标签: django django-models django-views

我有以下模型(为了清楚起见,我遗漏了def __unicode__(...)):

class Person(models.Model):
    first_name = models.CharField(max_length=64, null=True, blank=True)
    middle_name = models.CharField(max_length=32, null=True, blank=True)
    last_name = models.CharField(max_length=64, null=True, blank=True)

class MinorResident(Person):
    move_in_date = models.DateField(null=True)
    move_out_date = models.DateField(null=True)
    natural_child = models.NullBooleanField()

class OtherPerson(Person):
    associate_all_homes = models.BooleanField(default=False)

我有以下使用MinorResident对象创建OtherPerson对象的视图方法,如:

def MinorToAdult(request, minor):
    p = Person.objects.get(id=minor.person_ptr_id)
    o = OtherPerson(p.id)
    o.__dict__.update(p.__dict__)
    o.save()
    return True

这一切都很有效,但我仍然在minoresident表中有一条记录,指向person_ptr_id的人员记录。我在otherperson表中也有一个指针记录,同一个person_ptr_id指向同一个人,并显示切换之前的所有数据,但是使用了OtherPerson对象而不是MinorResident对象。所以,我想删除MinorResident对象,而不删除父类Person对象。我想我可以做类似的事情:

p = Person.objects.get(id=minor.person_ptr_id)
o = OtherPerson()
o.__dict__.update(p.__dict__)
o.save()
minor.delete()
return True

但是如果我能帮助它,我想在Person表中没有新的记录,因为它真的不是一个新人,只是一个现在成年人。也许我可以这样做吗?或者有更好的方法来处理模型嬗变吗?

p = Person.objects.get(id=minor.person_ptr_id)
o = OtherPerson(p.id)
o.__dict__.update(p.__dict__)
o.save()
minor.person_ptr_id = None
minor.delete()
return True

我看了SO #3711191: django-deleting-object-keeping-parent,但我希望得到更好的答案。

2 个答案:

答案 0 :(得分:6)

在Django 1.10.4+上,您可以使用keep_parents选项:

minor.delete(keep_parents=True)

否则我建议您使用deletion.Collector进行手动收集:

from django.db.models import deletion

collector = deletion.Collector(using=minor._state.db)
collector.add([minor])
collector.delete()

答案 1 :(得分:4)

选项1

明确指定您的parent_link字段并使用非托管模型。

class MinorResident(Person):
    person = models.OneToOneField(
        Person,
        parent_link = True,
        primary_key = True,
        db_column = 'person_id'
    )
    move_in_date = models.DateField(null=True)
    move_out_date = models.DateField(null=True)
    natural_child = models.NullBooleanField()


class UnmanagedMinorResident(models.Model):
    person = models.OneToOneField(
        Person,
        primary_key = True,
        db_column = 'person_id'
    )
    move_in_date = models.DateField(null=True)
    move_out_date = models.DateField(null=True)
    natural_child = models.NullBooleanField()

    class Meta:
        managed = False
        db_table = MinorResident._meta.db_table

现在您可以在不删除父行的情况下调用UnmanagedMinorResident.delete()

选项#2

使用原始SQL查询

from django.db import connection

minor = # MinorResident object
c = connection.cursor()
table = MinorResident._meta.db_table
column = MinorResident._meta.pk.column
# In this specific case it is safe to not escape.
sql = "DELETE FROM {0} WHERE {1}={2}".format(table, column, minor.pk)
c.execute(sql)

但您应该更改数据模型并为成人和未成年人使用相同的表格。您存储在MinorResident模型中的属性不属于那里,它们属于MinorResident与其移入/移出的实体之间的关系。