I have the following models (I left out def __unicode__(...)
for clarity):
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 view method for using a MinorResident object to create an OtherPerson object, like:
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
This all works great, but I still have a record in the minoresident table pointing to the person record with person_ptr_id. I also have a pointer record in the otherperson table with the same person_ptr_id pointing to the same person, and displaying all of the data as it was before the switch, but with an OtherPerson object instead of MinorResident object. So, I want to delete the MinorResident object, without deleting the parent class Person object. 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 like to not have a new record in the Person table if I can help it, since it really isn't a new person, just a person whose an adult now. Maybe I can I do something like this? 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-keeping-parent, but I was hoping for an improved answer.
On 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 collection:
from django.db.models import deletion
collector = deletion.Collector(using=minor._state.db)
collector.add([minor])
collector.delete()
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 row.
Option #2
Use a 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 should probably change your data model and use the same table for both adults and minors. The properties you are storing in the MinorResident
model do not belong there, they belong on the relationship between the MinorResident
and the entity it is moving in/out from/to.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With