Django: How to delete an object of a child class without deleting the object of the parent class?

I have the following models (for clarity, I left 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) 

I have the following presentation method for using the MinorResident object to create the OtherPerson object, for example:

 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 

All of this works fine, but I still have an entry in the minorizer table indicating a person entry with person_ptr_id. I also have a pointer entry in the otherperson table with the same person_ptr_id pointing to the same person and displaying all the data as it was before the switch, but with the OtherPerson object instead of the MinorResident object. So, I want to delete the MinorResident object without deleting the Person object of the parent class. I suppose I can do something like:

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

But I would not want to have a new entry in the Person table, if I can help her, because this is really not a new person, but just a person, an adult now. Maybe I can do something like that? Or is there a better way to handle model transmutation?

 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 

I looked at SO # 3711191: django-deleting-object-keep-parent , but I was hoping for an improved response.

+4
source share
2 answers

Option 1

Explicitly specify your parent_link fields and use an unmanaged model.

 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 

Now you can call UnmanagedMinorResident.delete() without deleting the parent line.

Option number 2

Use raw SQL query

 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) 

But you probably should change your data model and use the same table for adults and minors. The properties that you save in the MinorResident model MinorResident not belong there, they relate to the relationship between MinorResident and the object in which it moves to / from /.

+4
source

In Django 1.10.4+, you can use the keep_parents option:

 minor.delete(keep_parents=True) 

Else I suggest you use deletion.Collector with manual assembly:

 from django.db.models import deletion collector = deletion.Collector(using=minor._state.db) collector.add([minor]) collector.delete() 
+5
source

Source: https://habr.com/ru/post/1398316/


All Articles