Foo.objects.get(pk="foo")
<Foo: test>
У базу даних я хочу додати ще один об'єкт, який є копією об'єкта вгорі.
Припустимо, у мого столу є один ряд. Я хочу вставити об'єкт першого рядка в інший рядок з іншим первинним ключем. Як я можу це зробити?
Foo.objects.get(pk="foo")
<Foo: test>
У базу даних я хочу додати ще один об'єкт, який є копією об'єкта вгорі.
Припустимо, у мого столу є один ряд. Я хочу вставити об'єкт першого рядка в інший рядок з іншим первинним ключем. Як я можу це зробити?
Відповіді:
Просто змініть основний ключ вашого об'єкта та запустіть save ().
obj = Foo.objects.get(pk=<some_existing_pk>)
obj.pk = None
obj.save()
Якщо ви хочете автоматично згенерувати ключ, встановіть новий ключ на "Нічого".
Більше про ОНОВЛЕННЯ / ВСТАВКА тут .
Офіційні документи щодо копіювання моделей примірників: https://docs.djangoproject.com/en/2.2/topics/db/queries/#copying-model-in вещества
obj.pk
і інше, obj.id
щоб зробити цю роботу в Джанго 1.4
Документація 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 до версії 1.4. Однак це можливо ще до 1,4 року.
Можлива функціональність у майбутньому: Згадані зміни в документах були внесені в цей квиток . У темі коментаря до квитка також було обговорено питання щодо додавання вбудованої copy
функції для модельних класів, але, наскільки я знаю, вони ще не вирішили вирішити цю проблему. Тож цей "ручний" спосіб копіювання, мабуть, доведеться робити зараз.
Будьте обережні тут. Це може бути надзвичайно дорого, якщо ви знаходитесь в певному циклі і ви шукаєте об'єкти по одному. Якщо ви не хочете дзвінка в базу даних, просто зробіть:
from copy import deepcopy
new_instance = deepcopy(object_you_want_copied)
new_instance.id = None
new_instance.save()
Це робить те саме, що і деякі інші відповіді, але він не робить виклик бази даних для отримання об'єкта. Це також корисно, якщо ви хочете зробити копію об'єкта, який ще не існує в базі даних.
Використовуйте наведений нижче код:
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)
model_to_dict
бере exclude
параметр, що означає, що вам не потрібно окремого pop
:model_to_dict(instance, exclude=['id'])
Там клон фрагмент тут , який ви можете додати до вашої моделі , яка робить це:
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)
if
тепер це має бути if fld.name != old._meta.pk.name
, тобто, name
власність _meta.pk
примірника.
Як це зробити, було додано до офіційних документів Django в Django1.4
https://docs.djangoproject.com/en/1.10/topics/db/queries/#copying-model-in вещества
Офіційна відповідь схожа з відповіддю miah, але документи вказують на певні труднощі з успадкуванням та пов’язаними об'єктами, тому, ймовірно, ви повинні переконатися, що ви прочитали документи.
stable
замість номера версії в URL-адресі, наприклад, така: docs.djangoproject.com/en/stable/topics/db/queries/…
Я зіштовхнувся з парою готчей із прийнятою відповіддю. Ось моє рішення.
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
Примітка: тут використовуються рішення, які офіційно не дозволені в документах Django, і вони можуть перестати працювати в майбутніх версіях. Я перевірив це в 1.9.13.
Перше вдосконалення полягає в тому, що воно дозволяє продовжувати використовувати початковий екземпляр, використовуючи copy.copy
. Навіть якщо ви не збираєтесь повторно використовувати екземпляр, це може бути безпечніше зробити цей крок, якщо екземпляр, який ви клонуєте, був переданий як аргумент функції. Якщо ні, абонент несподівано матиме інший примірник, коли функція повернеться.
copy.copy
здається, створюється мілка копія екземпляра моделі Django потрібним чином. Це одна з речей, яку я не знайшов задокументованою, але вона працює шляхом маринування та відсікання, тому, ймовірно, це добре підтримується.
По-друге, затверджена відповідь залишить усі попередньо встановлені результати, додані до нового екземпляра. Ці результати не повинні пов'язуватися з новим екземпляром, якщо ви явно не скопіюєте зв'язки на багато. Якщо ви перейдете заздалегідь встановленими відносинами, ви отримаєте результати, які не відповідають базі даних. Порушення робочого коду при додаванні попереднього вибору може бути неприємним сюрпризом.
Видалення _prefetched_objects_cache
- це швидкий і брудний спосіб зняти всі попередні вибори. Подальший доступ до багатьох працює так, ніби ніколи не було попереднього вибору. Використання недокументованого властивості, яке починається з підкреслення, ймовірно, вимагає проблем із сумісністю, але воно працює на даний момент.
_[model_name]_cache
, якому, як тільки видалили, я зміг призначити новий ідентифікатор для цієї пов'язаної моделі, а потім зателефонувати save()
. Ще можуть бути побічні ефекти, яких я ще не визначив.
Для клонування моделі з декількома рівнями спадкування, тобто> = 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)
Будь ласка , зверніться питання тут .
Спробуйте це
original_object = Foo.objects.get(pk="foo")
v = vars(original_object)
v.pop("pk")
new_object = Foo(**v)
new_object.save()