[python] Django 모델 인스턴스 객체를 어떻게 복제하여 데이터베이스에 저장합니까?

Foo.objects.get(pk="foo")
<Foo: test>

데이터베이스에서 위의 객체의 사본 인 다른 객체를 추가하고 싶습니다.

내 테이블에 하나의 행이 있다고 가정하십시오. 다른 기본 키를 사용하여 첫 번째 행 객체를 다른 행에 삽입하고 싶습니다. 어떻게해야합니까?



답변

객체의 기본 키를 변경하고 save ()를 실행하십시오.

obj = Foo.objects.get(pk=<some_existing_pk>)
obj.pk = None
obj.save()

자동 생성 키를 원하면 새 키를 없음으로 설정하십시오.

UPDATE / INSERT에 대한 자세한 내용은 여기를 참조하십시오 .

모델 인스턴스 복사에 대한 공식 문서 : https://docs.djangoproject.com/en/2.2/topics/db/queries/#copying-model-instances


답변

데이터베이스 쿼리에 대한 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()만들고 두 번째 는 사본을 만듭니다.

문서를 계속 읽으면 두 가지 더 복잡한 경우를 처리하는 방법에 대한 예도 있습니다. -많은 관계.


miah의 답변에 대한 참고 사항 : pk를 설정하는 None것은 miah의 답변에 언급되어 있지만 앞면과 가운데에는 나와 있지 않습니다. 그래서 제 대답은 주로 장고 권장 방법으로 그 방법을 강조하는 것입니다.

역사적 참고 사항 : 이것은 장고 문서에서 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)


답변

복제 조각이있다 여기 이 수행 모델에 추가 할 수있는 :

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)


답변

이 작업을 수행하는 방법은 Django1.4의 공식 Django 문서에 추가되었습니다

https://docs.djangoproject.com/en/1.10/topics/db/queries/#copying-model-instances

공식적인 대답은 miah의 대답과 비슷하지만 문서는 상속 및 관련 개체에 약간의 어려움이 있음을 나타내므로 문서를 읽으십시오.


답변

나는 받아 들인 대답으로 몇 가지 문제에 봉착했습니다. 여기 내 해결책이 있습니다.

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는 모든 프리 페치를 제거하는 빠르고 더러운 방법입니다. 후속 다 대다 액세스는 프리 페치가없는 것처럼 작동합니다. 밑줄로 시작하는 문서화되지 않은 속성을 사용하는 것은 호환성 문제를 요구할 수도 있지만 현재로서는 효과가 있습니다.