TIL #35 Django : Model method

채록·2021년 1월 22일
0

Python & Django

목록 보기
6/34
post-thumbnail

🐶 들어가는 말

Django를 공부하면서 여러 메소드 들을 알게 되었다. 기본적이지만 자주 사용되는 메소드에는 대표적으로 다음과 같은 것들이 있다.

  • all() / values()
  • get() / filter()
  • create() / save()

비슷해 보이는 각 요소별로 차이점에 대해서 알아보자!

주 참고 정보 reference : Django 공식문서 https://docs.djangoproject.com/en/3.1/ref/models/querysets

영어문서 익숙해...ㅠ 전공을 바꿔도 벗어날수 없어





I. all() & values()

공통적인 것은 둘다 QuerySet의 형태로 출력된다는 것과, values()에 parameter가 입력되지 않을 경우 all()과 같이 모든 값을 출력한다는 것이다.

1. all()

all()은 현재 Queryset의 copy를 return한다고 한다.
Queryset형식 즉, list와 같은 모양새로 QuerySet에는 각각의 Instance들이 들어있어 출력하면 다음과 같이 나온다.

>>> from products.models import Category
>>> Category.objects.all()
<QuerySet [<Category: Category object (1)>, <Category: Category object (2)>, <Category: Category object (3)>, <Category: Category object (4)>, <Category: Category object (5)>, <Category: Category object (6)>, <Category: Category object (7)>]>

__str__() 메소드 추가예시

>>> from products.models import Menu
>>> Menu.objects.all()
<QuerySet [<Menu: 음료>, <Menu: 푸드>, <Menu: 상품>, <Menu: 카드>]>

2. values()

values의 입력형태는 values(*fields, **expressions)이다.
이 메소드는 all()과 마찬가지로 QuerySet을 반환하는데 all()과 달리 dictionary형태로 변환한다. dictionary를 포함한 QuerySet의 형태

Returns a QuerySet that returns dictionaries, rather than model instances, when used as an iterable.

글로썬 이해가 제대로 되지 않지만 출력 형태를 보면 all()과의 차이점을 볼 수 있다.

>>> from products.models import Drink
>>> Drink.objects.values()
<QuerySet [{'id': 1, 'name': '아인슈페너', 'name_en': 'Einspanner', 'category_id': 1}, {'id': 2, 'name': '아메리카노', 'name_en': 'Americano', 'category_id': 1}, {'id': 3, 'name': '딸기라떼', 'name_en': 'Strawberry latte', 'category_id': 2}, {'id': 4, 'name': '달고나 라떼', 'name_en': 'Dalgona Latte', 'category_id': 2}, {'id': 5, 'name': '석류애플라임', 'name_en': 'Pomegranate Apple Lime', 'category_id': 3}]>
>>> Drink.objects.values('id', 'name_en')
<QuerySet [{'id': 1, 'name_en': 'Einspanner'}, {'id': 2, 'name_en': 'Americano'}, {'id': 3, 'name_en': 'Strawberry latte'}, {'id': 4, 'name_en': 'Dalgona Latte'}, {'id': 5, 'name_en': 'Pomegranate Apple Lime'}]>

values()에 아무것도 입력하지 않는다면 마치 all() 처럼 모든 데이터를 출력하되, 그 형태가 dictionary일 것이고, values()안에 *fields 와 특정 **expression 을 지정하여 출력할 수 있다.



+) filter와 함께 이어서 사용도 가능하다 : filter(조건).values()

//1번
>>> Drink.objects.filter(category_id=1)
<QuerySet [<Drink: Drink object (1)>, <Drink: Drink object (2)>]>
//2번
>>> Drink.objects.filter(category_id=1).values()
<QuerySet [{'id': 1, 'name': '아인슈페너', 'name_en': 'Einspanner', 'category_id': 1}, {'id': 2, 'name': '아메리카노', 'name_en': 'Americano', 'category_id': 1}]>
//3번
>>> Drink.objects.filter(category_id=1).values('id', 'name_en')
<QuerySet [{'id': 1, 'name_en': 'Einspanner'}, {'id': 2, 'name_en': 'Americano'}]>
    1. filter로 조건만 잡아 출력했을 때
    1. filter로 조건 잡은 것을 values()를 통해 dictionary 형태로 출력
    1. filter로 조건 잡을 것을 name_en 이라는 parameter가 지정된 values()로 출력





II. get() & filter()

get()과 filter()는 모두 Django 에서 database 에 들어있는 data를 READ할때 사용되는 메소드 들이다. 즉, client에서 get()과 filter()를 통해 요청하면 과정을 거쳐 부합하는 data를 출력시키게 한다.



1. get()

get() 메소드는 조건에 맞는 단 하나의 데이터를 출력한다. 이때의 형태는 QuerySet이 아닌 단순히 object값 만을 출력한다.

>>> Drink.objects.get(id=1)
<Drink: Drink object (1)>

1) 만약 이 object의 특정 column의 값을 알고싶다면??

변수에 출력될 객체를 저장하여 변수.attribute 사용한다.

>>> drink=Drink.objects.get(id=1)
>>> drink.name
'아인슈페너'
>>> drink.name_en
'Einspanner'
>>> drink.category_id
1

2) FK속의 attribute를 읽는 법

>>> drink.category_id.name
Traceback (most recent call last):
  File "<console>", line 1, in <module>
AttributeError: 'int' object has no attribute 'name'

FK로 받는 category_id의 type이 int이기 때문에 이런식은 안된다

>>> drink.category.name
'에스프레소'

뒤에 _id는 쓰지 않는다! FK의 FK는 안됨 (직접 연결된 FK만)



2. filter()

filter()는 말 그대로 걸러서 출력하게 한다. 때문에 불특정 다수의 갯수의 값을 출력시킬수 있어, 그 형태는 list와 같은 QuerySet의 형태이다.

>>> Drink.objects.filter(id=1)
<QuerySet [<Drink: Drink object (1)>]>
>>> Drink.objects.filter(category_id=3)
<QuerySet [<Drink: Drink object (5)>, <Drink: Drink object (6)>]>

값이 1개이든지, 2개이상이든지 몇개와 상관없이 항상 QuerySet의 형태로 출력한다.

1) QuerySet은 index -1번째 라는 명령을 인식하지 못한다.!!

list에서는 뒤에서 앞으로 갯수를 셀때 -1부터 시작하지만, QuerySet은 -1번째 라는 개념을 인식하지 못한다.


'__str__' 함수 추가 예시

def __str__(self):
	return self.name #여기서 name 부분은 attribute

>>> Menu.objects.filter(id=1)
<QuerySet [<Menu: 음료>]>





III. create() & save()

두 메소드 모두 새롭게 값을 insert한다는 의미는 같다.



1. create()

명령어의 형태는 다음과 같다. create(**kwargs)
create는 새로운 object를 만듬과 동시에 저장하는 메소드 이다.
즉, table에 새로운 데이터를 추가(insert)하는 메소드로, 생성된 instance를 반환해준다.

class.objects.create(column명='넣을값')

+) key 값을 입력하지 않으면 안된다.

Django 연습중 반복되는 형태로 data를 추가하면서 실행해 보았다.
어차피 Product 라는 class에는 name / category_id / name_en 이라는 attribute가 고정되어 있으니 create 명령어를 입력할때 굳이 key값을 안쓰고, value만 순서에 맞게 입력해도 되지 않을까? 라고 생각했다.

결론은 안된다. 에러난다.

>> Drink.objects.create('레몬에이드', 3, 'Lemon Ade')
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/Users/생략/django/db/models/manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
TypeError: create() takes 1 positional argument but 4 were given

애초에 공식 document에서도 create의 parameter로 **kwargs의 형태를 받는다고 했던 것이 괜히 있는게 아니었다.


? null 설정안했을때 값 입력 안하고 create 하면 ?

create 할때 attribute중 null 의 기본값이 No로 되어있음을 확인했는데 create 할때 값을 넣지 않아도 그냥 입력 된다...

<Drink: Drink object (16)>
>> Drink.objects.create(category_id=1, name_en='water')
<Drink: Drink object (17)>

흠,, 이건 알아봐야겠다!




2. save()

save()는 insert 혹은 Update시에 사용되는 메소드이다. 주로 단일 객체의 update 시에 많이 사용된다.

1) insert 예

create() 메소드를 이용할땐 다음과 같다.

Drink.objects.create(name='물', category_id=1, name_en='water')

하지만이걸 save()를 통해 같게 기능하게 하려면 다음과 같이 하면 된다.

p = Drink(name='물', category_id=1, name_en='water')
p.save(force_insert=True)


2) update 예 - Django

아까 null 이 지정되지 않았을때 값을 입력하지 않으면 저장이 될까? 를 시도하다가 그냥 저장되버린 17번 id로 예시를 들어보았다.

>>> d = Drink.objects.get(id=17)
>>> d.name
''
>>> d.name='비타민워터'
>>> d.save()
>>> d.name
'비타민워터'
  • 변수 d에 pk 17번의 instance를 저장했다.
  • 원래 pk 17번은 name의 값이 없다. 따라서 '' 로 출력되었다.
  • d.name '비타민 워터' 라고 선언하였다. (name은 원래 Drink class에 속해있는 attribute이다.)
  • d.save() 로 값을 저장하였다.
  • 다시 d.name 을 입력하니 이전에 선언하고 저장한 '비타민 워터' 가 출력되었다.

3) update예 - database

위같은 예시에서 database상에는 어떤 변화가 있는지 알아보았다.

>>> a = Drink.objects.get(id=16)
>>> a.name
''
>>> a.name='수돗물'

새로 '수돗물' 이라고 선언했을 때 까지 table 의 상태는 변함이 없다.

a.save()

save 를 한 순간 database에 적용된다.




그렇다면 data를 update 할때 update랑 save()중 어떤게 더 좋은거지?? 🏃🏻‍♀️

profile
🍎 🍊 🍋 🍏 🍇

0개의 댓글