Как клонировать объект экземпляра модели Django и сохранять его в базе данных?
Foo.objects.get(pk="foo")
<Foo: test>
В базе данных я хочу добавить еще один объект, который является копией объекта выше.
Предположим, что моя таблица имеет одну строку. Я хочу вставить первый объект строки в другую строку с другим первичным ключом. Как я могу это сделать?
Ответы
Ответ 1
Просто измените первичный ключ вашего объекта и запустите save().
obj = Foo.objects.get(pk=<some_existing_pk>)
obj.pk = None
obj.save()
Если вы хотите автогенерированный ключ, установите для нового ключа значение None.
Подробнее о UPDATE/INSERT здесь.
Ответ 2
Документация Django для запросов к базе данных включает раздел о копировании экземпляров модели. Предполагая, что ваши первичные ключи автогенерируются, вы получаете объект, который хотите скопировать, установите первичный ключ на None
и снова сохраните объект:
blog = Blog(name='My blog', tagline='Blogging is easy')
blog.save() # blog.pk == 1
blog.pk = None
blog.save() # blog.pk == 2
В этом фрагменте первый save()
создает исходный объект, а второй save()
создает копию.
Если вы продолжаете читать документацию, есть примеры того, как обрабатывать два более сложных случая: (1) копирование объекта, являющегося экземпляром подкласса модели, и (2) также копирование связанных объектов, включая объекты в отношения "многие ко многим".
Примечание для ответа miah: установка pk на None
упоминается в ответе miah, хотя он не представлен спереди и в центре. Поэтому мой ответ в основном помогает подчеркнуть этот метод как рекомендуемый Django способ сделать это.
Историческое примечание. Это не объяснялось в документах Django до версии 1.4. Это было возможно, так как до 1.4, однако.
Возможная будущая функциональность: вышеупомянутое изменение документов было сделано в этот билет. В потоке комментариев к билетам также обсуждалось добавление встроенной функции copy
для классов моделей, но, насколько я знаю, они решили не решать эту проблему. Таким образом, этот "ручной" способ копирования, вероятно, придется сделать сейчас.
Ответ 3
Будьте осторожны. Это может быть очень дорого, если вы в какой-то петле, и вы возвращаете объекты по одному. Если вам не нужен вызов в базу данных, просто выполните:
from copy import deepcopy
new_instance = deepcopy(object_you_want_copied)
new_instance.id = None
new_instance.save()
Он делает то же самое, что и некоторые из этих других ответов, но не вызывает вызов базы данных для извлечения объекта. Это также полезно, если вы хотите сделать копию объекта, который еще не существует в базе данных.
Ответ 4
Здесь есть фрагмент клонирования здесь, который вы можете добавить к своей модели, которая делает это:
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)
Ответ 5
Как это сделать, было добавлено в официальные документы Django в Django1.4
https://docs.djangoproject.com/en/1.10/topics/db/queries/#copying-model-instances
Официальный ответ аналогичен ответу miah, но документы указывают на некоторые трудности с наследованием и связанными с ним объектами, поэтому вы, вероятно, должны убедиться, что прочитали документы.
Ответ 6
Используйте приведенный ниже код:
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)
Ответ 7
установка pk на None лучше, sinse Django может правильно создать pk для вас
object_copy = MyObject.objects.get(pk=...)
object_copy.pk = None
object_copy.save()
Ответ 8
Чтобы клонировать модель с несколькими уровнями наследования, т.е. >= 2, или ModelC ниже
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)
Пожалуйста, обратитесь к вопросу здесь.
Ответ 9
Попробуйте это
original_object = Foo.objects.get(pk="foo")
v = vars(original_object)
v.pop("pk")
new_object = Foo(**v)
new_object.save()