Django QuerySet METHOD

jhwang·2022년 5월 15일
0

Django Basics

목록 보기
8/14
post-thumbnail

1.. QuerySet ??

  • Django ORM에서 제공하는 데이터 타입
  • 데이터베이스에서 전달받은 객체 목록
  • 구조는 파이썬의 리스트(List)와 비슷한 형태이지만,
    파이썬의 기본 자료구조가 아니기 때문에 자료형 변환을 해줘야함.
  • No database acitivity actually occurs until you do something to evalutate the queryset.

objects'

  • 'Model Manager'라고 하며, Model과 데이터베이스 간에 연산을 수행하는 역할

  • 'objects'를 통해 데이터베이스와 연산해서 얻은 여러 모델 데이터가 담겨있는 것이 QuerySet


2.. Methods that return new QuerySets

<QuerySet [<Category: Category object (1)>, <Category: Category object (2)>]>

2-1.. all()

  • 해당 모델 테이블의 모든 데이터 조회
  • QuerySet타입으로 반환
In [4]: Dog.objects.all()
Out[4]: <QuerySet [<Dog: Dog object (1)>, <Dog: Dog object (2)>, <Dog: Dog object (3)>, <Dog: Dog object (4)>, <Dog: Dog object (5)>, <Dog: Dog object (6)>, <Dog: Dog object (7)>]>

2-2.. filter()

  • 특정 조건에 맞는 모든 데이터를 조회하고 싶을 때 사용
  • 한 테이블의 특정 레코드를 가져올 때 사용
  • QuerySet타입으로 반환
# owner_id가 1인 데이터만 조회
In [2]: Dog.objects.filter(owner_id=1)
Out[2]: <QuerySet [<Dog: Dog object (6)>, <Dog: Dog object (7)>]>

2-3.. exclude()

  • 특정 조건을 제외한 데이터만 조회하고 싶을 때 사용
  • QuerySet타입으로 반환
# owner_id가 1인 데이터를 제외한 모든 데이터 조회
In [3]: Dog.objects.exclude(owner_id=1)
Out[3]: <QuerySet [<Dog: Dog object (4)>, <Dog: Dog object (5)>, <Dog: Dog object (1)>, <Dog: Dog object (2)>, <Dog: Dog object (3)>]>

2-4.. values()

  • QuerySet의 내용을 딕셔너리(dict)형태로 반환
  • 인자값에 아무것도 넣지 않으면 해당 클래스의 모든 필드와 그 값을 보여주고,
    인자값에 특정 필드를 입력하면 입력한 필드에 대한 값을 반환
# 강아지 테이블의 모든 필드를 딕셔너리 형태로 반환
In [5]: Dog.objects.values()
Out[5]: <QuerySet [{'id': 1, 'name': '재롱', 'age': 3, 'owner_id': 3}, {'id': 2, 'name': '해피', 'age': 5, 'owner_id': 3}, {'id': 3, 'name': '연탄', 'age': 9, 'owner_id': 3}, {'id': 4, 'name': '포리', 'age': 17, 'owner_id': 2}, {'id': 5, 'name': '라온', 'age': 1, 'owner_id': 2}, {'id': 6, 'name': '욜로', 'age': 12, 'owner_id': 1}, {'id': 7, 'name': '콜라', 'age': 6, 'owner_id': 1}]>

# 강아지 테이블의 name 필드만 딕셔너리 형태로 반환
In [7]: Dog.objects.values('name')
Out[7]: <QuerySet [{'name': '재롱'}, {'name': '해피'}, {'name': '연탄'}, {'name': '포리'}, {'name': '라온'}, {'name': '욜로'}, {'name': '콜라'}]>

2-5.. values_list()

  • values()와 같으나, QuerySet의 내용을 딕셔너리가 아닌 리스트 타입으로 반환
In [8]: Dog.objects.values_list()
Out[8]: <QuerySet [(1, '재롱', 3, 3), (2, '해피', 5, 3), (3, '연탄', 9, 3), (4, '포리', 17, 2), (5, '라온', 1, 2), (6, '욜로', 12, 1), (7, '콜라', 6, 1)]>

In [9]: Dog.objects.values_list('name')
Out[9]: <QuerySet [('재롱',), ('해피',), ('연탄',), ('포리',), ('라온',), ('욜로',), ('콜라',)]>

2-6.. order_by()

  • 특정 필드를 기준으로 정렬을 할 때 사용
  • 특정 조건으로 정렬된 데이터 조회
  • 기본적으로 오름차순(ascending order)
  • 필드명 앞에 -가 붙으면 내림차순(descending order)
# korean_name 필드를 기준으로 오름차순 정렬
In : Drink.objects.order_by('korean_name')
Out: <QuerySet [<Drink: 나이트로 바닐라 크림>, <Drink: 나이트로 쇼콜라 클라우드>, <Drink: 딸기 요거트 블렌디드>, <Drink: 라임패션티>, <Drink: 말차 초콜릿 라떼>, <Drink: 망고 패션 후르츠 블렌디드>, <Drink: 블랙 티 레모네이드>, <Drink: 쿨라임 피지오>]>


# korean_name 필드를 기준으로 내림차순 정렬, 두번째 기준은 id 필드
In : Drink.objects.order_by('-korean_name', 'id')
Out: <QuerySet [<Drink: 쿨라임 피지오>, <Drink: 블랙 티 레모네이드>, <Drink: 망고 패션 후르츠 블렌디드>, <Drink: 말차 초콜릿 라떼>, <Drink: 라임패션티>, <Drink: 딸기 요거트 블렌디드>, <Drink: 나이트로 쇼콜라 클라우드>, <Drink: 나이트로 바닐라 크림>]>

2-7.. annonate()

  • annonate:: '주석을 달다' 라는 뜻
  • 각 컬럼별 주석을 달고 집계함수를 사용하여 반환
  • SQL의 group by Phrase와 같은 의미라고보면 될듯
  • QuerySet타입으로 반환
In : Nutrition.objects.values('drink_id__category_id').annotate(Sum('one_serving_kcal'))
Out: <QuerySet [{'drink_id__category_id': 1, 'one_serving_kcal__sum': Decimal('80.00')}, {'drink_id__category_id': 2, 'one_serving_kcal__sum': Decimal('410.00')}, {'drink_id__category_id': 3, 'one_serving_kcal__sum': Decimal('170.00')}, {'drink_id__category_id': 4, 'one_serving_kcal__sum': Decimal('425.00')}]>

위 QuerySet을 SQL로 표현하면,

select d.category_id, sum(n.one_serving_kcal)
  from nutritions n, drinks d 
 where n.drink_id = d.id 
 group by d.category_id
;

3.. Operators that return new QuerySets

3-1.. AND (&)

The following are equivalent:

Model.objects.filter(x=1) & Model.objects.filter(y=2)
Model.objects.filter(x=1, y=2)
from django.db.models import Q
Model.objects.filter(Q(x=1) & Q(y=2))

SQL equivalent:

SELECT ... WHERE x=1 AND y=2

3-2.. OR (|)

The following are equivalent:

Model.objects.filter(x=1) | Model.objects.filter(y=2)
from django.db.models import Q
Model.objects.filter(Q(x=1) | Q(y=2))

SQL equivalent

SELECT ... WHERE x=1 OR y=2

4.. Methods that do not return QuerySets

4-1.. get()

  • 조건에 맞는 하나의 데이터 조회
  • 하나의 row만 조회(주로 pk컬럼으로 조회)
  • (중요!!)결과가 1건 이상일 때는 에러를 발생
  • 객체 타입으로 반환 (QuerySet 타입 아님)
In : Drink.objects.get(id=1)
Out: <Drink: 나이트로 바닐라 크림>

# pk컬럼명 대신 그냥 pk 키워드로도 조회 가능
In : Drink.objects.get(pk=1)  
Out: <Drink: 나이트로 바닐라 크림>


# 조회 결과가 1건 이상일 땐 에러 반환
In : Drink.objects.get(category_id=1)
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/Users/yangah/miniconda3/envs/exercise/lib/python3.9/site-packages/django/db/models/manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/Users/yangah/miniconda3/envs/exercise/lib/python3.9/site-packages/django/db/models/query.py", line 433, in get
    raise self.model.MultipleObjectsReturned(
products.models.Drink.MultipleObjectsReturned: get() returned more than one Drink -- it returned 2!

4-2.. create()

  • 하나의 데이터를 생성하고, 해당 모델 데이터를 반환
In : Category.objects.create(name='콜드브루')
Out : <Category: Category object (1)>

#category 변수에 반환된 값을 저장하고, 생성된 data를 사용할 수 있다.
#인스턴스로 반환되므로 category.name으로 class 안에 변수에 접근할 수 있다.
In : category = Category.objects.create(name='콜드브루')
In : category.name
Out : '콜드브루'

참고) save method : INSERT 또는 UPDATE
Category(name='콜드브루').save()

4-3.. bulk_create()

  • 여러 개의 object를 한번에 생성할 때 사용
# Nutrition 클래스에 오브젝트 여러 개를 한 번에 생성

In : Nutrition.objects.bulk_create([
    ...: ...     Nutrition(one_serving_kcal = 5, sodium_mg = 5, saturated_fat_g = 0, sugers_g = 0, protein_g
    ...:  = 0, caffeine_mg = 245, drink_id = 2, size = 'Tall(톨)', size_fluid_ounce = 355, size_ml = 12),
    ...: ...     Nutrition(one_serving_kcal = 290, sodium_mg = 110, saturated_fat_g = 0.9, sugers_g = 57, pr
    ...: otein_g = 8, caffeine_mg = 0, drink_id = 4, size = 'Tall(톨)', size_fluid_ounce = 355, size_ml = 12
    ...: ),
    ...:  ^I    Nutrition(one_serving_kcal = 65, sodium_mg = 0, saturated_fat_g = 0, sugers_g = 17, protein_
    ...: g = 0, caffeine_mg = 30, drink_id = 5, size = 'Tall(톨)', size_fluid_ounce = 355, size_ml = 12),
    ...: ...     Nutrition(one_serving_kcal = 105, sodium_mg = 20, saturated_fat_g = 0, sugers_g = 26, prote
    ...: in_g = 0, caffeine_mg = 110, drink_id = 6, size = 'Tall(톨)', size_fluid_ounce = 355, size_ml = 12)
    ...: ,
    ...: ...     Nutrition(one_serving_kcal = 335, sodium_mg = 140, saturated_fat_g = 11, sugers_g = 32, pro
    ...: tein_g = 11, caffeine_mg = 62, drink_id = 7, size = 'Tall(톨)', size_fluid_ounce = 355, size_ml = 1
    ...: 2),
    ...: ...     Nutrition(one_serving_kcal = 90, sodium_mg = 15, saturated_fat_g = 0, sugers_g = 22, protei
    ...: n_g = 0, caffeine_mg = 93, drink_id = 8, size = 'Tall(톨)', size_fluid_ounce = 355, size_ml = 12),
    ...: ... ])
Out:
[<Nutrition: 나이트로 쇼콜라 클라우드 nutritions>,
 <Nutrition: 딸기 요거트 블렌디드 nutritions>,
 <Nutrition: 블랙 티 레모네이드 nutritions>,
 <Nutrition: 쿨라임 피지오 nutritions>,
 <Nutrition: 말차 초콜릿 라떼 nutritions>,
 <Nutrition: 라임패션티 nutritions>]

4-4.. get_or_create()

  • 해당 테이블에 조건에 맞는 데이터가 이미 존재한다면 get해오고, 없으면 create하는 Method
  • 튜플 타입을 반환해주는데 (True/False)형식으로 반환
  • 여기서 True/False는 이미 존재하는 데이터면(=get하는 경우) False, 없으면(=create하는 경우) True를 의미
# 이미 존재하는 데이터를 get_or_create 했을 때
In : Drink.objects.filter(korean_name='나이트로 쇼콜라 클라우드')
Out: <QuerySet [<Drink: 나이트로 쇼콜라 클라우드>]>

In : new_drink = Drink.objects.get_or_create(korean_name='나이트로 쇼콜라 클라우드')

# 기존에 있는 데이터 반환
In : new_drink
Out: (<Drink: 나이트로 쇼콜라 클라우드>, False)



# 없는 데이터를 get_or_create 했을 때
In : Drink.objects.filter(korean_name='new')
Out: <QuerySet []>

In : new_drink
Out: (<Drink: new>, True)

# 새로 추가된 것을 확인할 수 있다.
In : Drink.objects.filter(korean_name='new')
Out: <QuerySet [<Drink: new>]>

4-5.. latest()

  • 주어진 필드를 기준으로 가장 최신의 모델 데이터를 반환

4-6.. first() & last()

  • QuerySet 결과 중 가장 첫번째/마지막 row만 조회할 때 사용
  • 정렬하지 않은 쿼리셋이라면 Pk를 기준으로 정렬 후 반환
  • 만약 데이터가 없다면 None
# 전체 조회
In : Drink.objects.all()
Out: <QuerySet [<Drink: 나이트로 바닐라 크림>, <Drink: 나이트로 쇼콜라 클라우드>, <Drink: 망고 패션 후르츠 블렌디드>, <Drink: 딸기 요거트 블렌디드>, <Drink: 블랙 티 레모네이드>, <Drink: 쿨라임 피지오>, <Drink: 말차 초콜릿 라떼>, <Drink: 라임패션티>]>


# 가장 첫번째 row만 조회
In : Drink.objects.first()
Out: <Drink: 나이트로 바닐라 크림>


# 가장 마지막 row만 조회
In : Drink.objects.last()
Out: <Drink: 라임패션티>

4-7.. aggregate()

  • aggregate:: 집계, 합계
  • Django의 집계함수 모듈(Avg, Max, Min, Count, Sum, etc.)을 사용할 때 사용하는 Method
  • 집계함수들을 파라미터로 받으며, 딕셔너리 타입으로 반환
# 집계함수를 사용하려면 import 해줘야 함
In : from django.db.models import Max, Min, Avg, Sum


# Nutrition 테이블의 id 컬럼과 one_serving_kcal 컬럼만 조회
In : Nutrition.objects.values('id','one_serving_kcal')
Out: <QuerySet [{'id': 1, 'one_serving_kcal': Decimal('75.00')}, {'id': 2, 'one_serving_kcal': Decimal('120.00')}]>


# one_serving_kcal 값 모두 더하기
In : Nutrition.objects.aggregate(Sum('one_serving_kcal'))
Out: {'one_serving_kcal__sum': Decimal('195.00')}


# one_serving_kcal컬럼에서 가장 큰 값과 가장 작은 값의 차이
In : Nutrition.objects.aggregate(diff_kcal = Max('one_serving_kcal') - Min('one_serving_kcal'))
Out: {'diff_kcal': Decimal('45.00')}


# one_serving_kcal 컬럼 값들의 평균
In : Nutrition.objects.aggregate(avg_kcal = Avg('one_serving_kcal'))
Out: {'avg_kcal': Decimal('97.500000')}

4-8.. count()

  • 쿼리셋에 포함된 데이터의 개수를 리턴(정수로 반환)
# Drink 테이블에 몇 개의 데이터가 들어있는지 조회
In : Drink.objects.count()
Out: 8

4-9.. exists()

  • 해당 테이블에 데이터가 있는 지 확인
  • 있으면 Ture / 없으면 False 반환

4-10.. update()

  • 데이터를 수정할 때 사용
  • 여러 데이터 또는 여러 필드를 한번에 수정할 수 있음
  • 수정된 데이터의 개수를 정수로 반환
# filter로 조건을 걸고(id=8) 그 row의 특정 컬럼(discription) 값을 update
In : Drink.objects.filter(id=8).update(description = "Lime Passion 3")
Out: 1


# 결과 확인
In : Drink.objects.values('id','description').filter(id=8)
Out: <QuerySet [{'id': 8, 'description': 'Lime Passion 3'}]>
# 생성일이 2021년인 모든 포스트 데이터들의 context를 'codeit'으로 바꾸고
# 변경된 데이터의 개수를 리턴
Post.objects.filter('dt_created'__yeaer=2021).update(context='codeit')

Update 다른 방법

  • 업데이트할 row를 변수에 저장하고, 그 변수에서 각 필드에 접근하여 값을 변경
  • 반드시 .save()를 해야 변경사항이 저장
a = Drink.objects.get(id=8)

In : a
Out: <Drink: 라임패션티>


# id가 8인 row의 description 컬럼 값을 'Lime Passion 2'로 업데이트
In : a.description = "Lime Passion 2"

# 변경사항 저장 >> 실제 DB에 적용됨
In : a.save()


# 결과 확인
In : Drink.objects.values('id','description').filter(id=8)
Out: <QuerySet [{'id': 8, 'description': 'Lime Passion 2'}]>

4-11.. delete()

  • 데이터를 삭제할 때 사용
  • 삭제할 row를 변수에 저장하고, 그 변수에서 .delete()메소드로 해당 데이터 삭제
# 처음 데이터 확인
In : Menu.objects.all()
Out: <QuerySet [<Menu: 음료>, <Menu: 푸드>, <Menu: 상품>, <Menu: 카드>, <Menu: MD>]>


# 변수에 저장
In : a = Menu.objects.get(id=5)


# 삭제
In : a.delete()
Out: (1, {'products.Menu': 1})


# 결과 확인
In : Menu.objects.all()
Out: <QuerySet [<Menu: 음료>, <Menu: 푸드>, <Menu: 상품>, <Menu: 카드>]>
profile
"Your goals, Minus your doubts, Equal your reality"

0개의 댓글