Django로 '대량 업데이트'하는 방법은 무엇입니까?


163

장고로 테이블을 업데이트하고 싶습니다. 원시 SQL에서 이와 같은 것입니다.

update tbl_name set name = 'foo' where name = 'bar'

내 첫 번째 결과는 다음과 같습니다.-불쾌하지 않습니까?

list = ModelClass.objects.filter(name = 'bar')
for obj in list:
    obj.name = 'foo'
    obj.save()

더 우아한 방법이 있습니까?


1
배치 삽입을 찾고있을 수 있습니다. 한 번 봐 가지고 stackoverflow.com/questions/4294088/...
프라 모드

새 데이터를 삽입하고 싶지 않습니다. 기존 데이터 만 업데이트하십시오.
Thomas Schwärzl

3
아마 select_for_update의 도움으로? docs.djangoproject.com/en/dev/ref/models/querysets/…
Jure C.

ModelClass접근 방식 에 대해 불쾌하지 않은 것은 무엇입니까 ? 그 다음으로 장고에 공급 : stackoverflow.com/questions/16853649/...
치로 틸리郝海东冠状病六四事件法轮功

답변:


256

최신 정보:

Django 2.2 버전에는 이제 bulk_update가 있습니다.

이전 답변 :

다음 장고 설명서 섹션을 참조하십시오

여러 객체를 한 번에 업데이트

요컨대 다음을 사용할 수 있어야합니다.

ModelClass.objects.filter(name='bar').update(name="foo")

F객체를 사용 하여 행 증가와 같은 작업을 수행 할 수도 있습니다 .

from django.db.models import F
Entry.objects.all().update(n_pingbacks=F('n_pingbacks') + 1)

설명서를 참조하십시오 .

그러나 다음 사항에 유의하십시오.

  • 이것은 ModelClass.save메소드를 사용하지 않습니다 (따라서 내부에 논리가 있으면 트리거되지 않습니다).
  • 장고 신호가 방출되지 않습니다.
  • .update()슬라이스 된 QuerySet에 대해 수행 할 수 없으며 원래 QuerySet에 있어야하므로 .filter()and .exclude()메소드 에 의존해야 합니다.

27
사용하지 않는 결과로 있음을 유의하십시오 save(), DateTimeField와 필드 auto_now=True( "수정"열) 업데이트되지 않습니다.
Arthur

3
그러나 ModelClass.objects.filter(name = 'bar').update(name="foo")대량의 업데이트 목적을 달성하지 못합니다. 다른 ID에 대해 다른 데이터가있는 경우 루프를 사용하지 않고 어떻게 할 수 있습니까?
Shashank

@ shihon 나는 당신이 옳은지 확실하지 않지만 대답에 예를 추가했습니다.
jb.

@Shashank 아직 사건에 대한 해결책을 찾았습니까? 나는 또한 같은 시나리오가 있습니다.
Sourav Prem

F 객체는 .update 메소드에서 다른 모델을 참조하는 데 사용할 수 없습니다 Entry.objects.all().update(title=F('blog__title')). 예를 들어 사용할 수 없습니다 . 문서에는 이것에 대한 작은 언급이 있습니다. 당신이 당신의 항목을 업데이트하는 다른 모델로부터 데이터를 가져하려는 경우, 당신은 루프를 실행해야합니다
sean.hudson

31

GitHubdjango-bulk-update 에서 here 사용을 고려 하십시오 .

설치: pip install django-bulk-update

구현 : (프로젝트 ReadMe 파일에서 직접 가져온 코드)

from bulk_update.helper import bulk_update

random_names = ['Walter', 'The Dude', 'Donny', 'Jesus']
people = Person.objects.all()

for person in people:
    r = random.randrange(4)
    person.name = random_names[r]

bulk_update(people)  # updates all columns using the default db

업데이트 : Marc는 의견에서 지적했듯이 한 번에 수천 행을 업데이트하는 데 적합하지 않습니다. 더 작은 배치 10 ~ 100에 적합하지만. 적합한 배치 크기는 CPU 및 쿼리 복잡성에 따라 다릅니다. 이 도구는 덤프 트럭보다 휠 배로 우와 비슷합니다.


16
django-bulk-update를 시도했지만 개인적으로 사용하지 않는 것이 좋습니다. 내부적으로하는 것은 다음과 같은 단일 SQL 문을 작성하는 것입니다. UPDATE "table"SET "field"= CASE "id"WHEN % s THEN % s WHEN % s THEN % s [...] WHERE id in ( % s, % s, [...]) ;. 이것은 대량 행 업데이터가 필요하지 않은 경우 몇 행에 대해 괜찮습니다.하지만 10,000으로 쿼리가 너무 복잡하여 postgres가 디스크에 쓰는 시간을 절약하는 것보다 CPU를 100 % 쿼리로 이해하는 데 더 많은 시간을 소비합니다 .
Marc Garcia

1
@MarcGarcia 좋은 지적. 많은 개발자들이 영향을 몰라도 외부 라이브러리를 사용하는 것을 발견했습니다
Dejell

3
@MarcGarcia 나는 대량 업데이트가 가치가 없으며 수천 번의 업데이트가 필요할 때만 실제로 필요하다는 것에 동의하지 않습니다. 언급 한 이유로 10,000 행을 한 번에 수행하는 것은 좋지 않지만 한 번에 50 행을 업데이트하는 데 50 행을 업데이트하는 것이 50 개의 개별 업데이트 요청으로 db를 누르는 것보다 훨씬 효율적입니다.
nu everest

3
내가 찾은 가장 좋은 해결책은 a) 단일 트랜잭션을 사용하여 성능을 향상시키는 @ transaction.atomic 데코레이터를 사용하거나 b) 임시 테이블에 대량 삽입을 한 다음 임시 테이블에서 원래 테이블로 UPDATE하는 것입니다.
Marc Garcia

1
나는 이것이 오래된 스레드라는 것을 알고 있지만 실제로 CASE / WHERE가 유일한 방법은 아닙니다. PostgreSQL의 경우 다른 접근 방식이 있지만 DB 고유입니다 (예 : stackoverflow.com/a/18799497) 그러나 이것이 ANSI SQL에서 가능한지 확실하지 않습니다
Ilian Iliev

21

Django 2.2 버전에는 이제 bulk_update방법이 있습니다 ( 릴리스 노트 ).

https://docs.djangoproject.com/en/stable/ref/models/querysets/#bulk-update

예:

# get a pk: record dictionary of existing records
updates = YourModel.objects.filter(...).in_bulk()
....
# do something with the updates dict
....
if hasattr(YourModel.objects, 'bulk_update') and updates:
    # Use the new method
    YourModel.objects.bulk_update(updates.values(), [list the fields to update], batch_size=100)
else:
    # The old & slow way
    with transaction.atomic():
        for obj in updates.values():
            obj.save(update_fields=[list the fields to update])


8

rows 컬렉션에 동일한 값설정하려면 update () 메서드를 쿼리 용어와 함께 사용하여 하나의 쿼리에서 모든 행을 업데이트 할 수 있습니다.

some_list = ModelClass.objects.filter(some condition).values('id')
ModelClass.objects.filter(pk__in=some_list).update(foo=bar)

일부 조건에 따라 다른 값으로 행 모음업데이트 하려는 경우 에 따라 업데이트를 일괄 처리 할 수 ​​있습니다. 열을 X 값 중 하나로 설정하려는 1000 개의 행이 있고 사전에 배치를 준비한 다음 X 업데이트 쿼리 (각각 위의 첫 번째 예의 형식을 가짐) + 초기 SELECT 만 실행할 수 있다고 가정 해 봅시다. -질문.

모든 행에 고유 한 값필요한 경우 업데이트 당 하나의 쿼리를 피할 수있는 방법이 없습니다. 후자의 경우 성능이 필요한 경우 CQRS / 이벤트 소싱과 같은 다른 아키텍처를 살펴볼 수 있습니다.


1

IT는 테이블에서 업데이트 된 개체 수를 반환합니다.

update_counts = ModelClass.objects.filter(name='bar').update(name="foo")

이 링크를 참조하여 대량 업데이트 및 작성에 대한 자세한 정보를 얻을 수 있습니다. 대량 업데이트 및 생성

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