Django | QuerySet method(1) - CRUD

Sua·2021년 2월 13일
0

Django

목록 보기
17/23
post-thumbnail
post-custom-banner

QuerySet(쿼리셋)이란

  • 데이터베이스에서 전달받은 모델의 객체 목록
  • 데이터베이스의 여러 레코드(row)를 담은 형태
  • 리스트와 구조는 같지만, 파이썬 기본 자료구조가 아니여서 별도 자료형 변환이나 serializers가 필요
In : from products.models import Menu, Category, Product
In : menu = Menu.objects.all()
In : menu
Out : <QuerySet [<Menu: Menu object (1)>, <Menu: Menu object (2)>]>

In : type(menu)
Out : django.db.models.query.QuerySet
  • objects는 Model Manager
  • Django Model과 데이터베이스 사이의 Query Operation(질의 연산)의 인터페이스 역할
  • objects를 통해 반환되는 객체가 QuerySet

생성(Create)

create()

  • 데이터베이스에 새로운 객체를 생성하고 저장한다.
  • 생성된 인스턴스를 반환한다.
In : Menu.objects.create(name='음료')
Out : <Menu: 음료>

Model Instance를 save()로 저장

  • create()는 Model instance를 save()로 저장하는 방식과 동일하다.
In : menu = Menu(name='푸드')
In : menu.save()

왜 save()는 생성된 인스턴스를 반환하지 않을까?

bulk_create()

  • 한 번에 여러 개의 객체를 생성하고 저장한다.
  • 생성된 인스턴스를 리스트에 담아 반환한다.
In : Menu.objects.bulk_create([name='상품', name='카드'])
Out : [<Menu: 상품>, <Menu: 카드>]

get_or_create()

  • 데이터베이스에 객체가 있으면 가져오고, 없으면 객체를 생성한다.
  • (object, created)와 같이 튜플 형태로 반환된다. object에는 가져오거나 생성된 객체가 담기고, created에는 객체의 생성 여부가 담기는데 해당 객체가 생성된 것이라면 True, 데이터베이스에서 가져온 것이라면 False이다.
In  : Category.objects.get_or_create(name='콜드 브루 커피', menu_id='1')
Out : (<Category: 콜드 브루 커피>, False)

In  : Category.objects.get_or_create(name='에스프레소', menu_id='1')
Out : (<Category: 에스프레소>, True)

조회(Read)

get()

  • 해당 테이블에서 조건에 맞는 하나의 객체를 조회한다.
  • 조회된 인스턴스를 반환한다.
# id가 1인 카테고리 값 조회
In  : Category.objects.get(id=1)
Out : <Category: 콜드 브루 커피>
  • 조회된 값이 없으면 DoesNotExist 에러, 2개 이상이면MultipleObjectsReturned 에러 발생하므로, 찾고자 하는 값이 1개일 때 사용한다.
# 조회된 값이 2개 이상일 경우
MultipleObjectsReturned: get() returned more than one Category 
-- it returned more than 2!

# 조회된 값이 없을 경우
DoesNotExist: Category matching query does not exist.

all()

  • 해당 테이블의 모든 레코드를 조회한다.
  • QuerySet을 반환하며, QuerySet 안에는 각각의 인스턴스가 들어있다.
  • 즉, 해당 쿼리셋의 모든 요소를 반환한다. 현재 쿼리셋의 복사본을 반환한다고 볼 수 있다.
In  : Menu.objects.all()
Out : <QuerySet [<Menu: 상품>, <Menu: 음료>, <Menu: 카드>, <Menu: 푸드>]>

values()

  • 해당 테이블의 모든 레코드를 조회한다.
  • iterable로 사용될 때 인스턴스가 아닌 딕셔너리를 포함하는 QuerySet을 반환한다.
In  : Menu.objects.values()
Out : <QuerySet [{'id': 3, 'name': '상품'}, {'id': 1, 'name': '음료'}, {'id': 4, 'name': '카드'}, {'id': 2, 'name': '푸드'}]>
  • 인자값으로 필드이름을 넘겨서 원하는 필드 정보만 딕셔너리로 구성할 수도 있다.
In  : Menu.objects.values('name')
Out : <QuerySet [{'name': '상품'}, {'name': '음료'}, {'name': '카드'}, {'name': '푸드'}]>

values_list()

  • values()와 비슷하나, 반복될 때 딕셔너리가 아닌 튜플을 포함하는 QuerySet을 반환한다.
  • key는 없고 오직 value만 튜플로 반환된다.
In  : Menu.objects.values_list()
Out : <QuerySet [(3, '상품'), (1, '음료'), (4, '카드'), (2, '푸드')]>

exists()

  • filter()와 함께 사용해서 filter 조건에 맞는 데이터가 있는지 조회한다.
  • 존재하면 True 존재하지 않으면 False를 반환한다.
In  : Category.objects.filter(name='브루드 커피').exists()
Out : True

filter()

  • 해당 테이블에서 조건에 맞는 레코드를 조회한다.
  • QuerySet을 반환하며, QuerySet 안에는 각각의 인스턴스가 들어있다.
# Category 데이터 중 음료 Menu를 참조하고 있는 데이터 출력
# 방법 1
In  : Category.objects.filter(menu_id=1)
Out : <QuerySet [<Category: 콜드 브루 커피>, <Category: 블렌디드>, <Category: 프라푸치노>, <Category: 브루드 커피>, <Category: 에스프레소>]>


# 방법 2
In : Category.objects.filter(menu__name='음료')
Out : <QuerySet [<Category: 콜드 브루 커피>, <Category: 블렌디드>, <Category: 프라푸치노>, <Category: 브루드 커피>, <Category: 에스프레소>]>
  • 조건에 따른 조회 결과가 없을 경우, get()과는 달리DoesNotExist 에러 발생하지 않고 빈 쿼리셋이 반환된다.
In  : Category.objects.filter(menu_id=4)
Out : <QuerySet []>

exclude()

  • filter()와 반대로, 해당 테이블에서 lookup 조건에 맞지 않은 레코드를 조회한다.
  • QuerySet을 반환하며, QuerySet 안에는 각각의 인스턴스가 들어있다.
In  : Category.objects.exclude(menu__name='음료')
Out : <QuerySet [<Category: 머그>, <Category: 브레드>, <Category: 케이크>]>

AND, OR 조건

  • filter() 메소드 사용 시, AND 조건은 &로, OR 조건은 | 로 사용한다.
# AND 조건
In  : Product.objects.filter(is_new=1) & Product.objects.filter(category=2)
Out : <QuerySet [<Product: 딸기 젤리 블렌디드>]>

# OR 조건
In  : Product.objects.filter(is_new=1) | Product.objects.filter(category=2)
Out : <QuerySet [<Product: 나이트로 바닐라 크림>, <Product: 딸기 젤리 블렌디드>, <Product: 딸기 요거트 블렌디드>, <Product: 망고 바나나 블렌디드>]>
  • AND 조건은 & 없이 구현 가능하다.
In  : Product.objects.filter(is_new=1, category_id=2)
Out : <QuerySet [<Product: 딸기 젤리 블렌디드>]>```
  • OR 조건은 Q객체를 사용해 구현 가능하다.
In  : from django.db.models import Q # Q 모듈을 import해야 Q 객체를 사용할 수 있다.

In  : Product.objects.filter(Q(is_new=1) | Q(category_id=2))
Out : <QuerySet [<Product: 나이트로 바닐라 크림>, <Product: 딸기 젤리 블렌디드>, <Product: 딸기 요거트 블렌디드>, <Product: 망고 바나나 블렌디드>]>

first()

  • 조건에 맞는 QuerySet 결과 중 첫 번째 객체를 반환한다.
In  : Category.objects.first()
Out : <Category: 콜드 브루 커피>

last()

  • 조건에 맞는 QuerySet 결과 중 마지막 객체를 반환한다.
In  : Category.objects.last()
Out : <Category: 에스프레소>

count()

  • 조건에 맞는 QuerySet에 포함된 객체의 개수를 반환한다.
In  : Product.objects.filter(category_id=2).count()
Out : 3

order_by()

  • 특정 필드를 기준으로 정렬한다. 필드명 앞에 -가 붙으면 내림차순을 의미한다.
In  : Product.objects.order_by('korean_name')
Out : <QuerySet [<Product: 나이트로 바닐라 크림>, <Product: 나이트로 콜드 브루>, <Product: 돌체 콜드 브루>, <Product: 딸기 요거트 블렌디드>, <Product: 딸기 젤리 블렌디드>, <Product: 망고 바나나 블렌디드>, <Product: 제주 쑥떡 크림 프라푸치노>, <Product: 카라멜 마키아또>]>
In  : Product.objects.order_by('-korean_name')
Out : <QuerySet [<Product: 카라멜 마키아또>, <Product: 제주 쑥떡 크림 프라푸치노>, <Product: 망고 바나나 블렌디드>, <Product: 딸기 젤리 블렌디드>, <Product: 딸기 요거트 블렌디드>, <Product: 돌체 콜드 브루>, <Product: 나이트로 콜드 브루>, <Product: 나이트로 바닐라 크림>]>

변경(Update)

update()

  • 이미 존재하는 객체에 대한 필드값을 수정한다.
  • 업데이트된 행(row) 수를 반환한다.
In  : Product.objects.filter(id=6).update(description='망고 바나나 듬뿍 블렌디드')
Out : 1 # 업데이트된 row 개수

Model instance 속성을 변경하고, save()로 저장

  • update()는 Model instance의 속성을 변경하고 save()로 저장하는 방식과 동일하다.
product = Product.objects.get(id=6)
product.description = '망고 바나나 듬뿍 블렌디드'
product.save()

삭제(Delete)

delete()

  • 조건에 맞는 모든 행을 삭제한다.
  • 삭제된 객체 수와 객체 유형별 삭제 횟수가 있는 dictionary를 반환한다.
  • get(), filter(), all()과 함께 사용할 수 있다.
In  : Product.objects.filter(category_id=8).delete()
Out : (3, {'products.Image': 1, 'products.AllergyProduct': 1, 'products.Product': 1})

참고사이트
https://docs.djangoproject.com/en/3.1/ref/models/querysets/
https://wayhome25.github.io/django/2017/04/01/django-ep9-crud/
https://kimdoky.github.io/django/2020/02/03/django-queryset-api/
https://velog.io/@magnoliarfsit/ReDjango-7.-ORM%EA%B3%BC-Queryset
https://velog.io/@inyong_pang/Django-QuerySet
https://devvvyang.tistory.com/37?category=973523

profile
Leave your comfort zone
post-custom-banner

0개의 댓글