6

ok i think this is very basic, but since I am new to Django I don't know how to handle this.

I need to copy an instance of a django-model. As explained here, there is a problem with copying ManyToMany relations. But the attachment "django-model-copying.diff" has that function I guess. So I don't know - does my Django already have that function? I don't know how to call it. Help would be appreciated.

Julien Vavasseur
  • 3,854
  • 1
  • 20
  • 29
Peter
  • 141
  • 1
  • 2
  • 5
  • "I need to copy a whole django-model"? Do you mean clone an instance of the model -- i.e., clone a row in a database. This is -- generally -- a terrible idea. Why would you be cloning database rows? The whole point of the relational model of data is to make cloning a row needless. What are you doing? – S.Lott Sep 30 '10 at 19:46
  • yeah, your right - i need to copy an instance of a model.. I want to copy an instance with all its attributes and relations to other models.. You know, i thought about redundancy and stuff - but for my problem - it's the best way to just copy it. – Peter Sep 30 '10 at 19:57
  • @Peter: "but for my problem - it's the best way to just copy it". Sorry, but it isn't. It can't be. You have "relationships" in the database that make this completely needless. Perhaps you need to fix your data model before you go too far down this road. – S.Lott Sep 30 '10 at 20:02
  • Thanks for your quick response S.Lott! Ok, i'll try to explain.. So we have 2 models: User and Book. A User has a book called "Titanic" with some content. Now, another user wants a relation to that book too. But, the second user wants exactly the same book, but it should be called "Ship is going under".. I would copy the book, and rename it. - I know, i could also put the content of the book in another model - but my model is a little bit more complex. Not much is copied and im sure i need it this way.. Soo, can you help me use the function i mentiond in the title? thanks in advance – Peter Sep 30 '10 at 20:11
  • that's not an instance copy of a model, it's a new row with different data – KevinDTimm Sep 30 '10 at 20:16
  • @Peter: Please don't write long comments. Please **update** your question to contain all the information. "Not much is copied and im sure i need it this way". This is always false. Please provide **enough** information that we can correct your **real** problem. And provide this in the question. Not a comment. – S.Lott Oct 01 '10 at 01:39
  • possible duplicate of [How do I clone a Django model instance object and save it to the database?](http://stackoverflow.com/questions/4733609/how-do-i-clone-a-django-model-instance-object-and-save-it-to-the-database) – Anurag Uniyal Sep 08 '11 at 17:56

4 Answers4

5

The docs include directions on how to do this - including how to handle many to many relationships.

Lutz Prechelt
  • 36,608
  • 11
  • 63
  • 88
Aidan Ewen
  • 13,049
  • 8
  • 63
  • 88
4

You can just do the following:

m = MyModel.objects.get(pk=1)
m.id = None
m.save()

That way new instance will be created with new id of course in case of any unique properties it will trigger errors during validation.

NOTE: As for the function you've mentioned - it is not yet added to the trunk, the status is design decision needed, but if you know what you're doing you can manually apply the diff to your django instance - it's called patching btw. Here are some details about how to do it: http://ariejan.net/2007/07/03/how-to-create-and-apply-a-patch-with-subversion/.

bx2
  • 6,356
  • 5
  • 36
  • 40
  • I guess you could add `__copy__()`/`__deepcopy__()` functions to your model and then save the m2m values. Or maybe using `pickle`.. I'll try to solve this one out - quite interesting ;) – bx2 Sep 30 '10 at 21:00
  • 1
    Problem is that you have to copy 'through' table also, to point the new model on one end while pointing to the other end of the relation.. – bx2 Sep 30 '10 at 21:12
  • As Peter and bx2 already mentionned, this doesn't address the main problem which is m2m relationships. – bruno desthuilliers Oct 01 '10 at 07:55
  • 1
    Also doesn't work with Django 1.2+ - you need to set `m.pk = None` as well -- and doesn't fix m2m problem. – rcoup Nov 29 '11 at 20:34
1

I'll try to answer your actual problem, because what you are asking for in the question is a problem with your proposed solution, which as many have pointed out is not really ideal.

In the comments you mention this:

i'll try to explain.. So we have 2 models: User and Book. A User has a book called "Titanic" with some content. Now, another user wants a relation to that book too. But, the second user wants exactly the same book, but it should be called "Ship is going under".. I would copy the book, and rename it. - I know, i could also put the content of the book in another model - but my model is a little bit more complex.

Looks like you have three things to track:

  1. Users
  2. Their Books
  3. Some custom notes that users have about their "owned" book.

For each Book, store its common information, for example:

class Author(models.Model):
    name = models.CharField(max_length=50)
    email = models.EmailField()

    def __unicode__(self):
        return unicode(self.name)

class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.ManyToMany(Author)
    isbn = models.CharField(max_length=13)
    # and so on

    def __unicode__(self):
        return unicode(self.title)

Now, you need to store Book -> User relation, such as one user can have many books, two users may own the same book, with their own meta information attached.

class BookClub(models.Model):
     username = models.ForeignKey(User)
     book = models.ForeignKey(Book)
     comments = models.TextField()

If you structure your models like that, you'll be able to do queries like:

  • "How many books does each member have?"
  • "What is the most popular book?"
  • "What is the least popular book?"
  • "What is the most popular author?"
Burhan Khalid
  • 169,990
  • 18
  • 245
  • 284
0

It's worth noting that as of django 1.8 you may have UUIDFields. If you copy a model instance and then save it the unique constraint will fail on this column, in which case you have to do something like:

import uuid
m = MyModel.objects.get(pk=1)
m.pk = None
m.uuid = uuid.uuid4() //generate new uuid
m.save()
Escher
  • 5,418
  • 12
  • 54
  • 101