일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- Baekjoon
- Git
- API
- PYTHON
- 백준
- Algorithm
- web
- 알고리즘 문제
- django widget
- 장고
- 알고리즘
- AWS
- 알고리즘 연습
- django rest framework
- es6
- form
- c++
- js
- Django
- HTML
- java
- CSS
- javascript
- 파이썬
- 파이썬 알고리즘
- react
- MAC
- django ORM
- DRF
- 알고리즘 풀이
- Today
- Total
수학과의 좌충우돌 프로그래밍
[Django] ORM Cookbook, 정보를 조회하고 필요한 항목을 선별하는 방법(2) 본문
해당 포스팅은 Django ORM CookBook 을 공부하며 새로 알게된 사실이나 더 나아가 추가적으로 같이 알면 좋을 내용을 정리하고 있습니다.
10. JOIN
SQL에서는 JOIN문을 이용해 동일한 값을 가진 열을 기준으로 두 테이블을 결합할 수 있습니다.
django에서도 JOIN을 할 수 있는 방법이 존재합니다.
-
select_related
모든 Post를 가져오는 간단한 쿼리를 살펴봅시다.
post_all = Post.objects.all()
이에 대한 SQL 질의문입니다.
놀랍게도 Post에 대한 질의문과 Post와 OneToOne으로 연결되어 있는 User에 대한 질의가 함께 이루어집니다.
Post가 N개 있다면 각 Post에 해당하는 User를 조회하기 위해 N번의 추가적인 질의가 이루어집니다.
SELECT `post_post`.`id`, `post_post`.`user_id`, `post_post`.`title`, `post_post`.`content` FROM `post_post` SELECT `accounts_user`.`id`, `accounts_user`.`password`, `accounts_user`.`email` FROM `accounts_user` WHERE `accounts_user`.`id` = 2; SELECT `accounts_user`.`id`, `accounts_user`.`password`, `accounts_user`.`email` FROM `accounts_user` WHERE `accounts_user`.`id` = 2;
이번에는
select_related
를 사용하여 봅시다.post = Post.objects.select_related('user')
이에 대한 SQL 질의문입니다.
JOIN을 하기 때문에 더 복잡한 쿼리를 생성하지만 하나의 쿼리로 해결합니다.
SELECT `post_post`.`id`, `post_post`.`user_id`, `post_post`.`title`, `post_post`.`content`, `accounts_user`.`id`, `accounts_user`.`password`, `accounts_user`.`email`, FROM `post_post` INNER JOIN `accounts_user` ON (`post_post`.`user_id` = `accounts_user`.`id`)
추후에 post에 대한 user에 접근할 때도 DB에 접근하지 않습니다.
post[0].user
11. N번째 항목
django ORM에서 첫번째 항목과 마지막 항목은 각각 first()
와 last()
를 통해 구할 수 있습니다.
하지만 N번째 항목에 대해서는 따로 메서드를 제공하지 않습니다.
그렇기 때문에 N번째 항목에 대해서는 파이썬 인덱싱을 통해 구하게 됩니다.
user = User.objects.order_by('-last_login')[1]
이 때 SQL 질의문은 LIMIT OFFSET 구문을 사용하여 필요한 데이터만 가져옵니다.
SELECT `accounts_user`.`id`, `accounts_user`.`password`, `accounts_user`.`last_login`, `accounts_user`.`email`
FROM `accounts_user`
ORDER BY `accounts_user`.`last_login` DESC LIMIT 1 OFFSET 1;
12. 특정 열의 값이 동일한 항목
이번에는 특정 열의 값이 동일한 항목을 찾아봅시다.
User 모델 중 social
이 서로 동일한 사용자를 구한다고 가정합시다.
이 때는 Count
를 구한 후 이를 통해 찾을 수 있습니다.
from django.db.models import Count
duplicates = User.objects.values('social').annotate(social_count=Count('social'))
# <QuerySet [{'social': 'NONE', 'social_count': 2}, {'social': 'KAKAO', 'social_count': 1}]>
SELECT `accounts_user`.`social`, COUNT(`accounts_user`.`social`) AS `social_count` FROM `accounts_user` GROUP BY `accounts_user`.`social` ORDER BY NULL
이제 social_count
가 1보다 큰 값들에 대해서만 쿼리를 만들어줍니다.
duplicates = User.objects.values('social').annotate(social_count=Count('social')).filter(social_count__gt=1)
# <QuerySet [{'social': 'NONE', 'social_count': 2}]>
SELECT `accounts_user`.`social`, COUNT(`accounts_user`.`social`) AS `social_count`
FROM `accounts_user`
GROUP BY `accounts_user`.`social`
HAVING COUNT(`accounts_user`.`social`) > 1 ORDER BY NULL
위에서 날린 duplicates
를 이용하여 겹치는 User를 아래와 같이 구할 수 있습니다.
users = User.objects.filter(social__in=[item['social'] for item in duplicates])
SELECT `accounts_user`.`id`, `accounts_user`.`password`, `accounts_user`.`email`, `accounts_user`.`social`
FROM `accounts_user`
WHERE `accounts_user`.`social` IN ('NONE')
13. 고유한 필드 값을 가지는 항목
고유한 필드 값을 가지는 항목을 구해봅시다.
이름이 다른 사용자와 겹치지 않는 User는 아래와 같이 구할 수 있습니다.
distinct = User.objects.values(
'nickname'
).annotate(
name_count=Count('nickname')
).filter(name_count=1)
records = User.objects.filter(first_name__in=[item['nickname'] for item in distinct])
sql은 12 와 유사하여 생략하도록 하겠습니다.
'웹프로그래밍 > Django' 카테고리의 다른 글
[Django] ORM Cookbook, 항목을 생성·갱신·삭제하는 방법 (0) | 2020.08.27 |
---|---|
[Django] ORM Cookbook, 정보를 조회하고 필요한 항목을 선별하는 방법(3) (0) | 2020.08.27 |
[Django] ORM Cookbook, 정보를 조회하고 필요한 항목을 선별하는 방법(1) (0) | 2020.08.27 |
[Django] 한 모델이 여러 개의 모델과 관계를 맺어야하는 순간, contenttypes framework (2) | 2020.08.21 |
[Django] Logging 설정 및 SQL 쿼리 확인 (0) | 2020.08.15 |