django에서는 모델 객체를 업데이트 하는 방법이 여러가지가 있다.
쓸때마다 이거였지 생각은 나는데 정확하지 않아 계속 찾아보고 하는 과정이 반복되어
이번 기회에 정리하고자 한다.
django developer들에게 조금이나마 도움이 되길 바란다.
목차
Queryset.update()
"django model update"를 검색했을 때 가장 많이 나오는 방법이다.
즉시 적용(applied instantly)
obj.save() 필요 없음
update()매서드를 호출하는 순간 데이터가 변경된다.
save()보다 더 빠르다(Queryset의 특징인
laziness가 적용되지 않는다.)
외부 테이블의 필드는 수정 불가
해당 테이블의 데이터필드만 수정 가능하고 외래키로 수정은 불가하다.
>>> Entry.objects.update(blog__name="foo") # Won't work!
당연하지만 외부테이블로 filtering한 후 원래 테이블의 필드를 수정하는것은 가능하다.
>>> Entry.objects.filter(blog__id=1).update(comments_on=True) # Work!
multiple object, multiple fields 모두 가능
multiple objects update
Entry.objects.filter(pub_date__year=2010).update(comments_on=False)
publish_date가 2010년인 데이터 모두에 대해 comments_on 필드를 False로 변경해준다.
multiple objects + multiple fields update
Entry.objects.filter(pub_date__year=2010).update(
... comments_on=False, headline="This is old"
... )
publish_date가 2010년인 데이터 모두에 대해 comments_on 필드를 False로 headline필드를 "This is old"로 변경해준다.
*하나의 데이터만 업데이트 하고 싶은 경우
id 로 필터링 후 update 매서드 사용하면 유용함.
filter매서드가 리스트로 객체를 주기 때문에 뭔가 비효율적으로 보이지만
지금까지 사용한 경험으로는 이 방법이 제일 깔끔한것 같다.
return값은 변경된 데이터의 개수(updated object count)
>>> Entry.objects.filter(id=64).update(comments_on=True)
1
>>> Entry.objects.filter(slug="nonexistent-slug").update(comments_on=True)
0
>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False)
132
memory로 가져오지 않고 db에서 바로 작업(SQL level)
공식문서 설명에 따르면 update()매서드는 서버의 memory로 객체를 가져오지 않고
db내(SQL level)에서 처리를 끝낸다.(laziness X)
반면 save()매서드의 경우 서버의 memory로 들고온다.(laziness O)
단순히 값만 변경하는 경우는 update를 사용하는 것이 좋다.
e = Entry.objects.get(id=10)
e.comments_on = False
e.save()
이거보다는
Entry.objects.filter(id=10).update(comments_on=False)
이렇게 사용하는 것이 메모리를 효율적으로 사용하는 방법이다.
정리
- SQL level에서 데이터 업데이트를 한다. => 서버 메모리 사용하지 않음
- 하나의 데이터만 update할 경우 id로 필터링 후 update사용
queryset.update() >> https://docs.djangoproject.com/en/5.1/ref/models/querysets/#update
Queryset.bulk_update(objs, fields, batch_size=None)
여러객체에 대해 동시에 update하고자 할 때 사용한다.
결국 내부적으로 queryset.update()를 사용한다.
(github link : https://github.com/django/django/blob/main/django/db/models/query.py#L904)
업데이트 로직이 복잡한 경우 사용하면 좋을 듯 하다.
그런 경우가 아니면 update()매서드가 나아보인다.
사용법
첫번째 인자로 변경하고자 하는 objs리스트
두번째 인자로 변경하고자 하는 field 리스트
세번째는 batch_size로 한번에 얼마나 많은 데이터를 update할지
objs_to_update = MyModel.objects.filter(id__in=[1, 2, 3])
for obj in objs_to_update:
obj.field1 = 'New Value'
obj.field2 = 42
obj.field3 = datetime.now()
MyModel.objects.bulk_update(objs_to_update, ['field1', 'field2', 'field3'])
bulk_update를 사용하기 좋은 조건
1. update시 다른 로직을 추가할 경우 (update()의 경우엔 다른 로직을 추가하기 힘들다.)
2. 이미 모델 객체가 메모리에 올라가있는 경우에(already fetched case) 쿼리를 최소화하고 싶을때
queryset.bulk_update() >> https://docs.djangoproject.com/en/5.1/ref/models/querysets/#bulk-update
Model.save()
가장 원초적인(?) 방법이다.
db에서 데이터를 가져와 객체로 메모리 할당 후 다시 DB에 저장한다.
그래서 update매서드보다 더 느리고 서버 메모리 차원에서 비효율적이다.
UPDATE vs INSERT 장고는 어떻게 구분할까?
데이터를 update할때 뿐만아니라 insert할때도 save()는 사용할 수 있다.
일단 장고가 알아서 구분해준다.
근데 어떻게 장고는 이걸 구분하느냐?!
기본키(Primary key)에 해당하는
데이터가 있으면 UPDATE
데이터가 없으면 INSERT
Saving objects => https://docs.djangoproject.com/en/5.1/ref/models/instances/#saving-objects
update_or_create(defaults=None, create_defaults=None)
말 그대로 업데이트 하거나 해당 데이터가 없으면 만들어준다.
default(dict) : 업데이트 하고자 하는 데이터
create_default : 생성할 때 사용하는 데이터
* create_default를 설정하지 않으면 default로 생성(create)까지 한다.
get_or_create()와 마찬가지로 return값은 (object, is_created) 튜플을 준다.
데이터를 업데이트 하는데 없으면 바로 만들고 싶을 때 사용하기 유용한 매서드다.
사용법
obj, created = Person.objects.update_or_create(
first_name="John",
last_name="Lennon",
defaults={"first_name": "Bob"},
create_defaults={"first_name": "Bob", "birthday": date(1940, 10, 9)},
)
"John Lennon"이라는 사람이 있으면 "Bob Lennon"으로 수정하고 없으면 "Bob", (생일 1940,10,9)인 데이터를 생성한다.
코드를 깔끔하게 만들어주는 좋은 매서드이자 장고의 매력이라 생각한다.
장고 공식 문서 => https://docs.djangoproject.com/en/5.1/ref/models/querysets/#update-or-create
참고사이트
https://velog.io/@fregataa/django-QuerySet.update-vs-QuerySet.bulkupdate-vs-Model.save
'파이썬 python > django' 카테고리의 다른 글
[django] database is locked - 원인파악 | 해결방안 (0) | 2024.11.06 |
---|---|
[django] django로 포트포워딩(port forwarding)하는 방법 (w. middleware) (0) | 2024.07.25 |
[django] annotate에 관하여... (0) | 2024.07.23 |
[django] django template에서 settings.py variable불러오는 방법 (0) | 2024.05.09 |
[django] ImageField upload_to 동적 업로드(함수 사용) (0) | 2022.06.25 |