Foo.objects.get(pk="foo")
<Foo: test>
In der Datenbank möchte ich ein anderes Objekt hinzufügen, bei dem es sich um eine Kopie des obigen Objekts handelt.
Angenommen, meine Tabelle hat eine Zeile. Ich möchte das erste Zeilenobjekt in eine andere Zeile mit einem anderen Primärschlüssel einfügen. Wie kann ich das machen?
Ändern Sie einfach den Primärschlüssel Ihres Objekts und führen Sie save () aus.
obj = Foo.objects.get(pk=<some_existing_pk>)
obj.pk = None
obj.save()
Wenn Sie einen automatisch generierten Schlüssel wünschen, setzen Sie den neuen Schlüssel auf Keine.
Mehr zu UPDATE/INSERT hier .
Die Django-Dokumentation für Datenbankabfragen enthält einen Abschnitt zum Kopieren von Modellinstanzen . Angenommen, Ihre Primärschlüssel werden automatisch generiert, Sie erhalten das Objekt, das Sie kopieren möchten, setzen den Primärschlüssel auf None
und speichern das Objekt erneut:
blog = Blog(name='My blog', tagline='Blogging is easy')
blog.save() # blog.pk == 1
blog.pk = None
blog.save() # blog.pk == 2
In diesem Snippet erstellt das erste save()
das ursprüngliche Objekt und das zweite save()
erstellt die Kopie.
Wenn Sie weiter in der Dokumentation lesen, gibt es auch Beispiele, wie mit zwei komplexeren Fällen umgegangen werden soll: (1) Kopieren eines Objekts, das eine Instanz einer Modellunterklasse ist, und (2) Kopieren verwandter Objekte, einschließlich der Objekte in Many-to -Viele Beziehungen.
Anmerkung zu miahs Antwort: Die Einstellung von pk auf None
wird in miahs Antwort erwähnt, obwohl sie nicht vorne und mittig dargestellt wird. Meine Antwort dient also hauptsächlich dazu, diese Methode als von Django empfohlene Methode hervorzuheben.
Historischer Hinweis: Dies wurde in den Django-Dokumenten erst in Version 1.4 erläutert. Dies ist jedoch seit 1.4 möglich.
Mögliche zukünftige Funktionalität: Die vorgenannte Dokumentänderung wurde in dieses Ticket vorgenommen. Im Kommentarthread des Tickets wurde auch über das Hinzufügen einer eingebauten copy
-Funktion für Modellklassen diskutiert, aber soweit ich weiß, haben sie beschlossen, dieses Problem noch nicht zu lösen. Diese "manuelle" Art des Kopierens wird also wahrscheinlich erst einmal erledigt sein müssen.
Sei hier vorsichtig. Dies kann extrem teuer sein, wenn Sie sich in einer Schleife befinden und Objekte einzeln abrufen. Wenn Sie den Aufruf der Datenbank nicht wünschen, machen Sie einfach Folgendes:
from copy import deepcopy
new_instance = deepcopy(object_you_want_copied)
new_instance.id = None
new_instance.save()
Es macht dasselbe wie einige dieser anderen Antworten, es wird jedoch nicht die Datenbank aufgerufen, um ein Objekt abzurufen. Dies ist auch nützlich, wenn Sie eine Kopie eines Objekts erstellen möchten, das noch nicht in der Datenbank vorhanden ist.
Es gibt ein Klon-Snippet here , das Sie zu Ihrem Modell hinzufügen können, das dies tut:
def clone(self):
new_kwargs = dict([(fld.name, getattr(old, fld.name)) for fld in old._meta.fields if fld.name != old._meta.pk]);
return self.__class__.objects.create(**new_kwargs)
Wie Sie dies tun, wurde den offiziellen Django-Dokumenten in Django1.4 hinzugefügt
https://docs.djangoproject.com/de/1.10/topics/db/queries/#copying-model-instances
Die offizielle Antwort ist ähnlich wie die von miah, aber die Dokumente weisen auf einige Schwierigkeiten bei der Vererbung und verwandten Objekten hin. Daher sollten Sie wahrscheinlich sicherstellen, dass Sie die Dokumente lesen.
Verwenden Sie den folgenden Code:
from Django.forms import model_to_dict
instance = Some.objects.get(slug='something')
kwargs = model_to_dict(instance, exclude=['id'])
new_instance = Some.objects.create(**kwargs)
wenn pk auf None eingestellt ist, ist besser, sinse Django kann einen pk für Sie richtig erstellen
object_copy = MyObject.objects.get(pk=...)
object_copy.pk = None
object_copy.save()
Ich bin auf ein paar Gotchas mit der akzeptierten Antwort gestoßen. Hier ist meine Lösung.
import copy
def clone(instance):
cloned = copy.copy(instance) # don't alter original instance
cloned.pk = None
try:
delattr(cloned, '_prefetched_objects_cache')
except AttributeError:
pass
return cloned
Hinweis: Hierbei werden Lösungen verwendet, die in den Django-Dokumenten nicht offiziell genehmigt sind, und funktionieren möglicherweise in zukünftigen Versionen nicht mehr. Ich habe das in 1.9.13 getestet.
Die erste Verbesserung besteht darin, dass Sie die ursprüngliche Instanz weiterhin verwenden können, indem Sie copy.copy
verwenden. Selbst wenn Sie die Instanz nicht wiederverwenden möchten, kann es sicherer sein, diesen Schritt auszuführen, wenn die zu kopierende Instanz als Argument an eine Funktion übergeben wurde. Wenn nicht, hat der Aufrufer unerwartet eine andere Instanz, wenn die Funktion zurückkehrt.
copy.copy
scheint in der gewünschten Weise eine flache Kopie einer Django-Modellinstanz zu erzeugen. Dies ist eines der Dinge, die ich nicht dokumentiert fand, aber es funktioniert durch Beizen und Abnehmen, daher ist es wahrscheinlich gut unterstützt.
Zweitens hinterlässt die genehmigte Antwort alle vorabgerufenen Ergebnisse der neuen Instanz. Diese Ergebnisse sollten nicht mit der neuen Instanz verknüpft werden, es sei denn, Sie kopieren die Zu-Viele-Beziehungen explizit. Wenn Sie die vorabgerufenen Beziehungen durchlaufen, erhalten Sie Ergebnisse, die nicht mit der Datenbank übereinstimmen. Das Brechen von Arbeitscode beim Hinzufügen eines Prefetch kann eine böse Überraschung sein.
Durch das Löschen von _prefetched_objects_cache
können Sie schnell alle Vorabrufe entfernen. In der Folge funktionieren viele Zugriffe so, als ob es nie einen Prefetch gab. Die Verwendung einer undokumentierten Eigenschaft, die mit einem Unterstrich beginnt, erfordert möglicherweise Kompatibilitätsprobleme, ist jedoch vorerst funktionsfähig.
Versuche dies
original_object = Foo.objects.get(pk="foo")
v = vars(original_object)
v.pop("pk")
new_object = Foo(**v)
new_object.save()
Dies ist eine weitere Möglichkeit, die Modellinstanz zu klonen:
d = Foo.objects.filter(pk=1).values().first()
d.update({'id': None})
duplicate = Foo.objects.create(**d)
So klonen Sie ein Modell mit mehreren Vererbungsstufen, d. H.> = 2 oder ModelC (unten)
class ModelA(models.Model):
info1 = models.CharField(max_length=64)
class ModelB(ModelA):
info2 = models.CharField(max_length=64)
class ModelC(ModelB):
info3 = models.CharField(max_length=64)
Bitte beziehen Sie sich auf die Frage hier .