objects'
'Model Manager'라고 하며, Model과 데이터베이스 간에 연산을 수행하는 역할
'objects'를 통해 데이터베이스와 연산해서 얻은 여러 모델 데이터가 담겨있는 것이 QuerySet
<QuerySet [<Category: Category object (1)>, <Category: Category object (2)>]>
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)>]>
filter()
QuerySet
타입으로 반환# owner_id가 1인 데이터만 조회
In [2]: Dog.objects.filter(owner_id=1)
Out[2]: <QuerySet [<Dog: Dog object (6)>, <Dog: Dog object (7)>]>
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)>]>
values()
딕셔너리(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': '콜라'}]>
values_list()
리스트 타입
으로 반환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 [('재롱',), ('해피',), ('연탄',), ('포리',), ('라온',), ('욜로',), ('콜라',)]>
order_by()
-
가 붙으면 내림차순(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: 나이트로 바닐라 크림>]>
annonate()
annonate
:: '주석을 달다' 라는 뜻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
;
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
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
(중요!!)결과가 1건 이상일 때는 에러를 발생
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!
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()
# 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>]
get
해오고, 없으면 create
하는 Method튜플
타입을 반환해주는데 (True/False)형식으로 반환# 이미 존재하는 데이터를 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>]>
# 전체 조회
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: 라임패션티>
aggregate
:: 집계, 합계딕셔너리 타입으로 반환
# 집계함수를 사용하려면 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')}
# Drink 테이블에 몇 개의 데이터가 들어있는지 조회
In : Drink.objects.count()
Out: 8
있으면 Ture
/ 없으면 False
반환# 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 다른 방법
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'}]>
# 처음 데이터 확인
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: 카드>]>