1

In my project, i have 2 models:

class Product(models.Model):
    name = models.CharField(max_length=200)

class Material(models.Model):
    name = models.CharField(max_length=200)
    product = models.ForeignKey(Product)

Now, I want to make a copy of Product and keep all of the assigned materials. This is what I tried:

new_product = Product.object.get(pk='someexistingpk')
new_product.pk = None
new_product.name += ' (Copy)'
new_product.save()

Another variant I tried:

new_product = deepcopy(Product.object.get(pk='someexistingpk'))
new_product.pk = None
new_product.name += ' (Copy)'
new_product.save()

But in both cases, the resulting model_set is empty. None of the attached items are kept.

new_product.material_set.all()
<QuerySet []>

How can I resolve this? Ideally without iterating over every item in the original material_set.

S.D.
  • 2,486
  • 1
  • 16
  • 23
  • Sorry to ask, but what ya wanna do with the copy? It's kinda important. –  Jun 22 '17 at 16:35
  • and how you are going to save to database if no pk is provided?? – Exprator Jun 22 '17 at 16:36
  • 1
    @Exprator [this is a standard way](https://stackoverflow.com/questions/4733609/how-do-i-clone-a-django-model-instance-object-and-save-it-to-the-database) to clone Django model objects. OP, the Foreign Key will continue to point to the original Product, not to your copy. – Jedi Jun 22 '17 at 16:38
  • @Melvyn, it is to be used for a bill of materials for garments. Most of the time these lists of materials don't change much, but some items do. So to avoid having to re-enter everything, I'd like to copy the object. I edited the example a bit to reflect the copy's identity. – S.D. Jun 22 '17 at 16:40
  • I think it's easier to create a BillOfMaterials model that is basically a through model for the manytomany relation between product and material. It depends a bit what for. Is this to record a sale of that product? –  Jun 22 '17 at 16:54
  • Well, the above is a simplified version of the models. In reality, I'm already using a BillOfMaterial model to do this, and assign the right quantities needed for the product in question. But how do you see this being better as a many2many? Right now this is also using ForeignKeys. – S.D. Jun 22 '17 at 19:56

2 Answers2

0

Given that ForeignKeys, can not have multiple assignments, it only makes sense that they are not copied over, as that would break the original object.

So, when copying over the Product, one should also do the same for the related objects. Like this:

new_prod = deepcopy(prod)
new_prod.pk = None
new_prod.save()

for mat in prod.material_set.all():
    new_mat = deepcopy(mat)
    new_mat.pk = None
    new_mat.product = new_prod
    new_mat.save()

Now, it results in a nice Queryset with all of the material objects attached, as expected.

new_prod.material_set.all()
<QuerySet [<Material: 1.01 Katoen cats and dogs>, <Material: 1.0 Hour-cost>, <Material: 2.0 lint>, <Material: 1.0 Katoen cats and dogs>]>
S.D.
  • 2,486
  • 1
  • 16
  • 23
0

From my understanding you are trying to duplicate a model. The way I approached this problem in my project was using dynamic models and inheritance. If you use inheritance, all the fields are going to be automatically copied to the new model.

from MyApp.models import Product
class Meta:
    pass
setattr(Meta, 'app_label', 'MyApp')
attrs = {'__module__': module, 'Meta': Meta}
model = type('ProductCopy', (Product,), attrs)

So here the new model that is created is called ProductCopy and will have a table on your Django Admin page. To learn more about dynamic models you can take a look at this documentation.

cookiedough
  • 3,552
  • 2
  • 26
  • 51