[TIL] # 26 Django CRUD (1)

지난번에 공부했던 Create에 이어서
Read 보고 가겠습니다

오늘 공부해볼 데이터의 users에 대한 정보구요

READ

get()

User.objects.get(id = 1)
User.objects.get(id = 1).email
User.objects.get(id = 1).password

하나의 객체를 반환해주는 메서드 입니다
get을 사용하는 경우는 회원의 email을 가지고 온다거나, 아이디를 가지고 오는 등 ...
유니크한 값을 가지고 올때 사용 합니다

하나의 객체를 가지고 오기 때문에 내가 필요한 정보를 .(dot) 을 이용해서
바로 가지고 오면 됩니다

반환하는 개체가 많을 경우

User.objects.get(id__gte = 1)

MultipleObjectsReturned

장고에서 바로 에러를 띄웁니다 😖


filter()

user1 = User.objects.filter(id = 1)
user1[0].email
user1[0].password

앞에서 봤던 get과는 무언가를 가지고 온다는 비슷한 점이 있는데
다른 점이 있다면, filter의 경우는 쿼리셋을 반환합니다

이 쿼리셋의 경우는 파이썬의 리스트와 비슷하게 작동하기 때문에
리스트를 사용하는 것처럼 사용하면 됩니다

filter 와 list의 차이

list처럼 사용가능 하다는게 list에서 처럼 append가 되고, pop이 되는 등
list의 메서드를 사용가능 하다는게 아닌 순서를 가지고 오는데 있어 비슷하다는 것입니다

위에는 쿼리셋의 메서드, 아래는 list의 메서드

쿼리셋의 경우는 음수 사용이 안됩니다

여러개의 쿼리셋

jungs = User.objects.filter(email__startswith = "jung")
google_users = User.objects.filter(email__endswith = "jung")

쿼리셋을 이용해서 정보를 가지고 올 경우
for 문을 이용해서 가지고 올 수 있습니다


exclude()

제외한 나머지를 쿼리셋으로 가지고 옵니다

filter와 같이 쓰는 경우

users = User.objects.filter(email__endswith = "gmail.com").exclude(id =2)

이런식으로 같이 사용하여 google사용자 이지만, id = 2인 유저를 제외한
나머지를 가지고 옵니다

exists()

존재하는지 확인 하는 메서드로
True, False로 반환 합니다

get_or_create()

가지고 오는데, 만약 존재하지 않으면 만들어서 가지고 옵니다
만약 존재하면 False, 존재하지 않으면 True값을 가지고 옵니다

get_or_create의 경우 튜플로 반환 됩니다

count()

해당 테이블에 존재하는, 혹은 filter를 사용해서 가지고 온 쿼리셋의
숫자를 반환 합니다

int 으로 반환 됩니다

first()

가장 첫번째 객체를 반환합니다

last()

가장 마지막 객체를 반환합니다

aggregate()

dictionary 형태로 반환합니다
num_email이 키값, "email"을 가지고 있는 모든 유저의 수가 value 값으로 들어갑니다

어디에 사용할까?

aggregate의 경우는 집계함수를 이용하여 집계되어 나온 값의 수를 구할때 사용합니다

https://docs.djangoproject.com/en/3.1/topics/db/aggregation/

예제가 좋지 않은데 만약 책의 column중 총 페이지의 수가 있다고 치면
책의 총 페이지 갯수 혹은 Avg를 사용하여 모든 책에 대한 페이지의 평균값,
혹은 filter를 이용하여 가지고온 책들의 평균값 등... 을 구할때 사용합니다

values(), values_list()

values의 경우는 dictionary를 포함하는 쿼리셋으로 반환
values_list의 경우는 튜플의 형태로 반환

각각의 column이 key, data가 value값으로 딕셔너리 형태를 이루고 있습니다

select_related

ForeignKey를 사용하는 경우에 사용합니다

# get을 이용해서 가지고 올경우 	
post1 = Post.object.get(id = 1)				# Hit
post1.user						# Hit
post1.user.email					# Hit
# select_related를 이용해서 가지고 올경우 
post2 = Post.objects.select_related('user').get(id = 1)	# Hit
post2.user
post2.user.email
# get을 이용한 쿼리문 
print(Post.objects.filter(id = 1).query)
>>> SELECT `posts`.`id`, `posts`.`content`, `posts`.`user_id`, `posts`.`created`, `posts`.`updated` FROM `posts` WHERE `posts`.`id` = 1
print(Post.objects.select_related('user').filter(id = 1).query)
# select_related를 이용한 쿼리문 
>> SELECT `posts`.`id`, `posts`.`content`, `posts`.`user_id`, `posts`.`created`, `posts`.`updated`, `users`.`id`, `users`.`email`, `users`.`password` FROM `posts` INNER JOIN `users` ON (`posts`.`user_id` = `users`.`id`) WHERE `posts`.`id` = 1

ForeignKey로 참조를 하고 있는 상황일때,

get의 경우는 데이터가 필요할 때마다, DB를 Hit해서 데이터를 가지고 옵니다
총 3번의 데이터베이스 Hit이 발생했고

select_related의 경우는 이미 가지고 온 상태이기 때문에
1번의 Hit으로 데이터를 가지고 옵니다

여기서 DB를 Hit하면서 발생하는 시간, 메모리의 손실을 절약 할 수 있습니다

select를 사용해서 가지고 올때, select_related
둘 사이의 순서는 중요하지 않습니다


아아... 머리 다빠진다

좋은 웹페이지 즐겨찾기