django-polymorphic icon indicating copy to clipboard operation
django-polymorphic copied to clipboard

Copying Polymorphic objects for ModelC not working

Open pipanchik opened this issue 5 years ago • 2 comments

From example:

from django.db import models
from polymorphic.models import PolymorphicModel

class ModelA(PolymorphicModel):
    field1 = models.CharField(max_length=10)

class ModelB(ModelA):
    field2 = models.CharField(max_length=10)

class ModelC(ModelB):
    field3 = models.CharField(max_length=10)

I set in object .id and the .pk of the object to None before saving:

>>> o = ModelB.objects.first()
>>> o.field1 = 'new val' # leave field2 unchanged
>>> o.pk = None
>>> o.id = None
>>> o.save()

It works. But this method does not work if i coping ModelC (because modela_ptr not set to None).

What should I do?

pipanchik avatar Nov 07 '19 12:11 pipanchik

Had the same issue, here is a little workaround for all in need.

fields_to_copy = ["name"]
Model = get_model(to_be_copied._meta.label.split(".")[0], to_be_copied._meta.label.split(".")[1])
copied = Model()
for attr in to_be_copied.__dict__:
    if attr in fields_to_copy:
        copied.__dict__[attr] = to_be_copied.__dict__[attr]
copied.save()

dice89 avatar Jul 22 '20 12:07 dice89

Here's another solution that will resolve things by unsetting the OneToOneField pointers. There might be a cleverer way to determine which fields are in our own inheritance tree, but this works.

self.pk = self.id = None

# However if we have three levels of inheritance, we also need
# to clear the pointers, else we'll end up with an UPDATE rather
# than an INSERT still.
for field in self._meta.get_fields(include_parents=True):
    if not isinstance(field, models.OneToOneField):
        continue

    # Test this is a pointer to something in our own inheritance
    # tree
    if not isinstance(self, field.related_model):
        continue

    setattr(self, field.attname, None)

danni avatar Jan 03 '23 22:01 danni