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

[BUG] __duplicate_m2m_fields doesn't work for other db with 'through' attribute

Open accedx opened this issue 2 years ago • 0 comments

Is there an existing issue for this?

  • [X] I have searched the existing issues

Does this issue exist in the latest version?

  • [X] I'm using the latest release

Describe the bug?

Hello, if model field has 'through' attribute, that code doesn't use source model instance db id

https://github.com/tj-django/django-clone/blob/a401427bddc3d4be267400ce030ea08b66f92f4d/model_clone/mixin.py#L664C24-L664C24

I suggest add 'using' to 'through.objects' objs = through.objects.using(self._state.db).filter(**{field_name: self.pk})

Or remove this 'if', and leave only code into 'else' branch. 'Else' branch work perfectly for 'through' if is exists.

    for field in fields:
        if hasattr(field, "field"):
            # ManyToManyRel
            field_name = field.field.m2m_reverse_field_name()
            through = field.through
            source = getattr(self, field.get_accessor_name())
            destination = getattr(duplicate, field.get_accessor_name())
        else:
            through = field.remote_field.through
            field_name = field.m2m_field_name()
            source = getattr(self, field.attname)
            destination = getattr(duplicate, field.attname)

        items_clone = []
        for item in source.all():
            if hasattr(item, "make_clone"):
                try:
                    item_clone = item.make_clone(
                        using=using,
                    )
                except IntegrityError:
                    item_clone = item.make_clone(
                        sub_clone=True,
                        using=using,
                    )
            else:
                item_clone = CloneMixin._create_copy_of_instance(
                    item,
                    force=True,
                    sub_clone=True,
                    using=using,
                )
                item_clone.save(using=using)
                items_clone.append(item_clone)

            destination.set(items_clone)

    return duplicate

To Reproduce

class Product(Model, CloneMixin):
    pass

class Catalog(Model, CloneMixin):
    products = ManyToManyField(Product, through='CatalogThrough')

class CatalogThrough(Model):
    catalog = ForeignKey(Catalog)
    product = ForeignKey(Product)

Catalog.objects.using('db-id-1').get(pk=1).make_clone(using=DEFAULT_DB_ALIAS)

What OS are you seeing the problem on?

No response

Expected behavior?

Copy products from 'db-id-1'

Relevant log output

No response

Anything else?

No response

Code of Conduct

  • [X] I agree to follow this project's Code of Conduct

accedx avatar Jul 24 '23 18:07 accedx