데이터베이스에서 django 객체를 다시로드하십시오.


160

데이터베이스에서 장고 객체의 상태를 새로 고칠 수 있습니까? 나는 대략 다음과 같은 행동을 의미합니다.

new_self = self.__class__.objects.get(pk=self.pk)
for each field of the record:
    setattr(self, field, getattr(new_self, field))

업데이트 : http://code.djangoproject.com/ticket/901 추적기에서 재개 열 / wontfix 전쟁을 발견했습니다 . 여전히 관리자가 왜 이것을 좋아하지 않는지 이해하지 못합니다.


일반적인 SQL 컨텍스트에서는 이치에 맞지 않습니다. 데이터베이스 객체는 트랜잭션이 완료되고를 수행 한 후에 만 변경할 수 있습니다 commmit. 그런 다음에는 다음 SQL 트랜잭션이 커밋 될 때까지 기다려야합니다. 왜 그런가요? 다음 거래를 얼마나 기다려야합니까?
S.Lott

이것은 불필요한 기능처럼 보입니다. 데이터베이스에서 객체를 다시 조회하는 것이 이미 가능합니다.
Stephan


2
장고 모델 객체는 프록시이므로 적합하지 않습니다. 동일한 테이블 행을 두 객체로 가져 오면-x1 = X.objects.get (id = 1); x2 = X.objects.get (id = 1), 동일한 것으로 테스트되지만 다른 객체이며 상태가 공유되지 않습니다. 둘 다 독립적으로 변경하여 저장할 수 있습니다. 마지막으로 저장된 것이 데이터베이스의 행 상태를 결정합니다. 따라서 간단한 할당 (x1 = X.objects.get (id = 1))으로 다시로드하는 것이 좋습니다. 재로드 방법을 사용하면 많은 사람들이 x1.f = '새로운 가치'라고 잘못 추론 할 수 있습니다. (x1.f == x2.f)는 True입니다.
Paul Whipp

답변:


259

Django 1.8부터 새로 고침 객체가 내장되어 있습니다. 문서에 연결 .

def test_update_result(self):
    obj = MyModel.objects.create(val=1)
    MyModel.objects.filter(pk=obj.pk).update(val=F('val') + 1)
    # At this point obj.val is still 1, but the value in the database
    # was updated to 2. The object's updated value needs to be reloaded
    # from the database.
    obj.refresh_from_db()
    self.assertEqual(obj.val, 2)

@ fcracker79 네, 1.8에서만 구현되었습니다. Django의 이전 버전의 경우 다른 답변 중 하나를 사용하는 것이 가장 좋습니다.
Tim Fletcher

1
문서에 언급 된 "지연되지 않은 모든 필드가 업데이트 됨"이 무엇을 의미하는지 잘 모르십니까?
Yunti

1
@Yunti 필드 를 연기 하거나 필드 의 하위 집합 만 명시 적으로 요청 하면 결과 개체가 부분적으로 만 채워집니다. refresh_from_db이미 채워진 필드 만 업데이트합니다.
301_Moved_Permanently

문서에서 세부 정보를 찾을 수 없지만를 DoesNotExist호출 할 때 기본 개체가 삭제되면 예외가 올바르게 발생합니다 refresh_from_db. 참고로
Tim Tisdall

28

다음 과 같이 데이터베이스에서 객체다시로드하는 것이 상대적으로 쉽다는 것을 알았습니다 .

x = X.objects.get(id=x.id)

19
예,하지만 ... 그 후에는이 객체에 대한 모든 참조를 업데이트해야합니다. 매우 편리하고 오류가 발생하기 쉽지 않습니다.
grep

2
Celery가 django 외부의 db에서 내 객체를 업데이트 할 때 이것이 필요하다는 것을 알았습니다 .django는 객체의 변경 사항을 알지 못했기 때문에 객체의 캐시를 유지했습니다.
Bob Spryn

3
django.db.models.loading에서 가져 오기 import get_model; 인스턴스 = get_model (instance) .objects.get (pk = instance.pk)
Erik

1
@grep은이 사용 사례에 대한 테스트를 작성하는 데 2 ​​시간이 걸렸습니다. 1 : 모델 초기화; 2 : 양식을 통해 모델을 업데이트합니다. 3 : 새 값이 업데이트되었는지 테스트합니다 .... 예, 오류가 발생하기 쉽습니다.
vlad-ardelean

3
나는 refresh_from_db이 모든 문제를 해결 한다고 생각 합니다.
Flimm

16

@grep의 의견과 관련하여 할 수 없어야합니다.

# Put this on your base model (or monkey patch it onto django's Model if that's your thing)
def reload(self):
    new_self = self.__class__.objects.get(pk=self.pk)
    # You may want to clear out the old dict first or perform a selective merge
    self.__dict__.update(new_self.__dict__)

# Use it like this
bar.foo = foo
assert bar.foo.pk is None
foo.save()
foo.reload()
assert bar.foo is foo and bar.foo.pk is not None

솔루션 주셔서 감사합니다. SO 만 여러 개의 투표를 허용 한 경우!
user590028

11
장고는 이제 refresh_from_db방법을 제공 합니다.
Flimm

9

@Flimm이 지적했듯이 이것은 정말 멋진 솔루션입니다.

foo.refresh_from_db()

데이터베이스의 모든 데이터가 개체로 다시로드됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.