[In-depth] django queryset + SQL

2025. 9. 30. 13:28ยทDjango-rest-framework

3๋…„์ฐจ ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž๋กœ์„œ ํ•ญ์ƒ ์จ์™”๋˜ orm์ด์ง€๋งŒ, ์“ฐ๋˜๊ฒƒ๋งŒ ์‚ฌ์šฉํ•˜๋‹ค๋ณด๋‹ˆ ์ž˜ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” queyset ํ™œ์šฉ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ๋Š” ์กฐ๊ธˆ ๋ฌด์ง€ํ–ˆ๋˜ ๊ฒƒ ๊ฐ™๋‹ค. ๊ทธ๋ž˜์„œ ๊ณต์‹ document๋ฅผ ๋ณด๊ณ  ์ฐจ๊ทผ์ฐจ๊ทผ ํ•˜๋‚˜ํ•˜๋‚˜ ์ •๋ฆฌ๋ฅผ ํ•ด๋ณด๋ฉฐ ํ•œ๋ฒˆ ๋” ๋จธ๋ฆฌ์— ์ƒˆ๊ธธ๋ ค๊ณ  ํ•œ๋‹ค.

 


[Queryset API]

 

filter(*args, **kwargs): ์กฐ๊ฑด์— ๋งž๋Š” ๊ฐ์ฒด๋“ค๋งŒ ๋‹ด์€ queryset์„ ๋ฐ˜ํ™˜, ์—ฌ๋Ÿฌ ์กฐ๊ฑด์„ ์ฃผ๋ฉด AND ์กฐ๊ฑด์œผ๋กœ ๋ฌถ์ธ๋‹ค.

- lookups (method: filter(), exclude(), get())

exact: ์ •ํ™•ํ•œ ์ผ์น˜ -> SQL: SELECT ... WHERE id = 14;

iexact: ๋Œ€์†Œ๋ฌธ์ž ๊ตฌ๋ถ„ ์—†๋Š” ์ •ํ™•ํ•œ ์ผ์น˜-> SQL:SELECT ... WHERE name ILIKE 'beatles blog';

contains: ํฌํ•จ ์—ฌ๋ถ€-> SQL: SELECT ... WHERE headline LIKE '%Lemon%';

icontains: ๋Œ€์†Œ๋ฌธ์ž ๋ฌด์‹œ ํฌํ•จ ์—ฌ๋ถ€-> SQL: SELECT ... WHERE headline ILIKE '%Lemon%';

in: ๋ฆฌ์ŠคํŠธ/์ฟผ๋ฆฌ์…‹์— ํฌํ•จ ์—ฌ๋ถ€-> SQL: SELECT ... WHERE id in (1, 3, 4);

gt, gte, lt, lte: ~๋ณด๋‹ค ํฌ๋‹ค, ~๋ณด๋‹ค ํฌ๊ฑฐ๋‚˜ ๊ฐ™๋‹ค, ~๋ณด๋‹ค ์ž‘๋‹ค, ~๋ณด๋‹ค ์ž‘๊ฑฐ๋‚˜ ๊ฐ™๋‹ค-> SQL: SELECT ... WHERE price >= 1000;

startswith: ํ•ด๋‹น ๋ฌธ์ž์—ด๋กœ ์‹œ์ž‘-> SQL: SELECT ... WHERE name LIKE 'Kim%';

istartswith: ๋Œ€์†Œ๋ฌธ์ž ๊ตฌ๋ฌธ ์—†์ด ์‹œ์ž‘-> SQL: SELECT ... WHERE LOWER(name) LIKE 'kim%'

endswith: ํ•ด๋‹น ๋ฌธ์ž์—ด๋กœ ๋๋‚จ-> SQL: SELECT ... WHERE name LIKE '%Kim';

iendswith: ๋Œ€์†Œ๋ฌธ์ž ๊ตฌ๋ถ„ ์—†์ด ๋๋‚จ-> SQL: SELECT ... WHERE LOWER(name) LIKE '%kim'

range: ๋ฒ”์œ„ ์กฐํšŒ-> SQL: SELECT ... WHERE date BETWEEN '2025-01-01' AND '2025-12-31'

date, month, year, day: ๋‚ ์งœ, ์›”, ๋…„, ์ผ-> SQL: SELECT ... WHERE DATE(timestamp) = '2025-09-30', WHERE EXTRACT(MONTH FROM order_date) = 9, WHERE EXTRACT(YEAR FROM order_date) = 2025, WHERE EXTRACT(DAY FROM order_date) = 30

week: ์ฃผ์ฐจ-> SQL: SELECT ... WHERE EXTRACT(WEEK FROM order_date) = 40

iso_year: ISO ์—ฐ๋„-> SQL: SELECT ... WHERE EXTRACT(ISOYEAR FROM order_date) = 2025

iso_week_day: ISO ์š”์ผ (1=์›”, 7=์ผ)-> SQL: SELECT ... WHERE EXTRACT(ISODOW FROM order_date) = 1

quarter: ๋ถ„๊ธฐ (1~4)-> SQL: SELECT ... WHERE EXTRACT(QUARTER FROM order_date) = 3

time, hour, minute, second: ์‹œ๊ฐ„, ์‹œ, ๋ถ„, ์ดˆ-> SQL: SELECT ... WHERE CAST(timestamp AS time) = '14:30:00', WHERE EXTRACT(HOUR FROM timestamp) = 14, WHERE EXTRACT(MINUTE FROM timestamp) = 30, WHERE EXTRACT(SECOND FROM timestamp) = 0

is_null: null ์—ฌ๋ถ€-> SQL: SELECT ... WHERE last_login IS NULL

regex: ์ •๊ทœ์‹ ๋งค์นญ-> SQL: SELECT ... WHERE username ~ '^[A-Z]'

iregex: ๋Œ€์†Œ๋ฌธ์ž ๊ตฌ๋ถ„ ์—†๋Š” ์ •๊ทœ์‹ ๋งค์นญ-> SQL: SELECT ...WHERE username ~* '^[a-z]'

 

exclude(*args, **kwargs): ์กฐ๊ฑด์— ๋งž๋Š” ๊ฐ์ฒด๋“ค์„ ์ œ์™ธํ•œ queryset์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

 

annotate(*args, **kwargs): queryset์˜ ๊ฐ ๊ฐ์ฒด์— ๊ณ„์‚ฐ๋œ ํ•„๋“œ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค. ์ง‘๊ณ„, ์กฐ๊ฑด, ๋‹จ์ˆœ ๊ฐ’ ๋“ฑ ๋‹ค์–‘ํ•œ ๊ฐ’์„ ๊ฐ ๊ฐ์ฒด์— ๋ถ™์ธ๋‹ค. ์›๋ณธ ๋ชจ๋ธ์—๋Š” ์—†๋Š” ์ž„์‹œ ํ•„๋“œ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค. alies๋„ ์ง€์ • ๊ฐ€๋Šฅํ•˜๋‹ค.

 

alias(*args, **kwargs): annotate()์™€ ์œ ์‚ฌํ•˜์ง€๋งŒ ๊ฐ์ฒด์— ๊ฐ’์„ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๊ณ , ํ‘œํ˜„์‹์„ ๋‚˜์ค‘์— ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์ €์žฅํ•œ๋‹ค. ๊ฒฐ๊ณผ๊ฐ’ ์ž์ฒด๊ฐ€ ํ•„์š” ์—†์ง€๋งŒ ๋‹ค๋ฅธ queryset ๋ฉ”์„œ๋“œ ๋“ฑ์—์„œ ํ™œ์šฉํ•  ๋•Œ ์œ ์šฉํ•˜๋‹ค. ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฐ’์„ DB์—์„œ ์„ ํƒํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์„ฑ๋Šฅ ์ตœ์ ํ™” ๋ฉด์—์„œ๋„ ์œ ์šฉํ•˜๋‹ค.

from django.db.models import Count, F
# 1. alias๋กœ ํ‘œํ˜„์‹ ์ •์˜
blogs = Blog.objects.alias(entries=Count("entry"))
# 2. alias๋ฅผ filter์—์„œ ํ™œ์šฉ
blogs_with_many_entries = blogs.filter(entries__gt=5)

# Blog ๊ฐ์ฒด๋งˆ๋‹ค Entry ๊ฐœ์ˆ˜๋ฅผ ๊ณ„์‚ฐ(alias), ์ด๋ฅผ annotate๋กœ ์‹ค์ œ ํ•„๋“œ์ฒ˜๋Ÿผ ์“ฐ๊ณ , ๋งˆ์ง€๋ง‰์— ๋ชจ๋“  Blog์˜ Entry ์ดํ•ฉ์„ ๊ตฌํ•œ๋‹ค.
Blog.objects.alias(entries=Count("entry")).annotate(
    entries=F("entries")
).aggregate(Sum("entries"))

 

order_by(*fileds): queryset์˜ ์ •๋ ฌ์„ ์ง€์›ํ•œ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ queryset์€ ๋ชจ๋ธ์˜ Meta.ordering์—์„œ ์ง€์ •ํ•œ ์ˆœ์„œ๋กœ ์ •๋ ฌ๋œ๋‹ค. ๋ฌด์ž‘์œ„ ์ •๋ ฌ์—๋Š” "?"์ด ์‚ฌ์šฉ๋˜๋ฉฐ DB์— ๋”ฐ๋ผ ์„ฑ๋Šฅ์ด ์ €ํ•˜๋  ์ˆ˜ ์žˆ๋Š” ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋‹ค. nulls_first / nulls_last๋กœ null ์ •๋ ฌ ์ œ์–ด๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค. ๋˜ํ•œ distinct()์™€ ํ•จ๊ป˜ ์‚ฌ์šฉ ์‹œ ๊ด€๊ณ„ ํ•„๋“œ ์ •๋ ฌ์ด ์˜ˆ์ƒ๊ณผ ๋‹ค๋ฅด๊ฒŒ ์ž‘๋™ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋Œ€์†Œ๋ฌธ์ž ๊ตฌ๋ถ„ ์—†์ด ์ •๋ ฌํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” Lower()๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ๋˜ ์˜ˆ๋ฅผ ๋“ค์–ด Objects.order_by("A").order_by("B")๋ฅผ ํ•˜๊ฒŒ ๋˜๋ฉด ๋งˆ์ง€๋ง‰ order_by๋งŒ ์ ์šฉ๋œ๋‹ค.

 

reverse(): queryset์˜ ์ˆœ์„œ๋ฅผ ๋’ค๋ฐ”๊พธ๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.qs.reverse().reverse() ์ด๋Ÿฐ์‹์œผ๋กœ ํ˜ธ์ถœํ•˜๋ฉด ์›๋ž˜ ์ˆœ์„œ๋กœ ๋Œ์•„์˜ค๊ฒŒ ๋œ๋‹ค.

 

distinct(*fields): qQuerySet์—์„œ ์ค‘๋ณต๋œ ํ–‰(row)์„ ์ œ๊ฑฐํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๋ฉ”์„œ๋“œ๋กœ, SQL์˜ SELECT DISTINCT์™€ ๋Œ€์‘๋œ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ๋‹จ์ˆœํ•œ ์ฟผ๋ฆฌ์—์„œ๋Š” ์ค‘๋ณต์ด ๊ฑฐ์˜ ๋ฐœ์ƒํ•˜์ง€ ์•Š์ง€๋งŒ, ์—ฌ๋Ÿฌ ํ…Œ์ด๋ธ”์„ ์กฐ์ธํ•˜๊ฑฐ๋‚˜ ๋ณต์žกํ•œ ์ฟผ๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•  ๊ฒฝ์šฐ ์ค‘๋ณต๋œ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜ํƒ€๋‚  ์ˆ˜ ์žˆ์–ด ์ด๋•Œ distinct()๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ค‘๋ณต์„ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ๋‹ค. ๋‹ค๋งŒ, order_by()์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ์ฃผ์˜๊ฐ€ ํ•„์š”ํ•˜๋‹ค. order_by()์—์„œ ์ง€์ •ํ•œ ํ•„๋“œ๋“ค์ด SQL์˜ SELECT ์ ˆ์— ํฌํ•จ๋˜๊ธฐ ๋•Œ๋ฌธ์—, ๊ฒ‰๋ณด๊ธฐ์—๋Š” ์ค‘๋ณต์ด ์ œ๊ฑฐ๋˜์ง€ ์•Š์€ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ผ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์˜ˆ์ƒ๊ณผ ๋‹ค๋ฅธ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜ํƒ€๋‚  ์ˆ˜ ์žˆ๋‹ค. ๋˜ํ•œ, values()์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ๋•Œ๋„ ์ •๋ ฌ ๊ธฐ์ค€์ด values()์— ํฌํ•จ๋˜์–ด ์žˆ์ง€ ์•Š์œผ๋ฉด ์ค‘๋ณต ์ œ๊ฑฐ๊ฐ€ ์˜๋„ํ•œ ๋Œ€๋กœ ๋™์ž‘ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ distinct()๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ์ฟผ๋ฆฌ์˜ ์ •๋ ฌ ๊ธฐ์ค€๊ณผ ์„ ํƒ๋œ ์ปฌ๋Ÿผ์„ ํ•จ๊ป˜ ๊ณ ๋ คํ•ด์•ผ ํ•œ๋‹ค.

 

values(): queryset๋ฅผ ์ˆœํšŒํ•  ๋•Œ ๋ชจ๋ธ ์ธ์Šคํ„ด์Šค ๋Œ€์‹  ๋”•์…”๋„ˆ๋ฆฌ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ํ•˜๋Š” ๋ฉ”์„œ๋“œ, ๊ฐ ๋”•์…”๋„ˆ๋ฆฌ๋Š” ๋ชจ๋ธ ๊ฐ์ฒด๋ฅผ ๋‚˜ํƒ€๋‚ด๋ฉฐ key๋Š” ๋ชจ๋ธ์˜ ํ•„๋“œ ์ด๋ฆ„๊ณผ ๋Œ€์‘๋œ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ชจ๋“  ํ•„๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜์ง€๋งŒ values("")๋กœ ์ง€์ •๋„ ๊ฐ€๋Šฅํ•˜๋‹ค.ํ‚ค์›Œ๋“œ ์ธ์ž๋กœ ๊ณ„์‚ฐ์‹์ด๋‚˜ ํ‘œํ˜„์‹๋„ ํฌํ•จ ๊ฐ€๋Šฅ(values(lower_name=Lower("name"))) ํ•˜๋‹ค. ๊ด€๊ณ„ ํ•„๋“œ๋„ ์กฐํšŒ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, ๋‹ค๋Œ€๋‹ค๋‚˜ ์—ญ์ฐธ์กฐ๋Š” ๊ฒฐ๊ณผ๊ฐ€ ๊ณฑํ•ด์งˆ ์ˆ˜๋„ ์žˆ๋‹ค.

 

values_list(): values()์™€ ์œ ์‚ฌํ•˜์ง€๋งŒ ๋”•์…”๋„ˆ๋ฆฌ ๋Œ€์‹  ํŠœํ”Œ์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ๋‹จ์ผ ํ•„๋“œ ์กฐํšŒ์‹œ flat=True๋ฅผ ์ง€์ •ํ•˜๋ฉด ํŠœํ”Œ ๋Œ€์‹  ๋‹จ์ผ ๊ฐ’์œผ๋กœ ๋ฐ˜ํ™˜๋˜๋ฉฐ named=True๋ฅผ ์ง€์ •ํ•˜๋ฉด namedTuple๋กœ ๋ฐ˜ํ™˜ ๊ฐ€๋Šฅํ•˜๋‹ค.

 

dates(field, kind, order='ASC'): queryset์—์„œ ํŠน์ • ๋‚ ์งœ ํ•„๋“œ์˜ ๋ชจ๋“  ๋‚ ์งœ๋ฅผ datetime.date ๊ฐ์ฒด ๋ฆฌ์ŠคํŠธ๋กœ ๋ฐ˜ํ™˜ํ•œ๋‹ค. field๋Š” ๋ชจ๋ธ์˜ DateFiled ์ด๋ฆ„, kind๋Š” ๋ฐ˜ํ™˜ํ•  ๋‚ ์งœ ๋‹จ์œ„ ์ง€์ • ("year", "month", "week", "day"), order๋Š” ์ •๋ ฌ ์ˆœ์„œ์ด๋‹ค. ๊ฒฐ๊ณผ ๋ฆฌ์ŠคํŠธ์—๋Š” ์ง€์ •ํ•œ ๋‹จ์œ„๋กœ ์ค‘๋ณต ์ œ๊ฑฐ ํ›„ ๋ฐ˜ํ™˜๋˜๋ฉฐ filter์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋ฉด ํŠน์ • ์กฐ๊ฑด์— ๋งž๋Š” ๋‚ ์งœ๋งŒ ์ถ”์ถœํ•  ์ˆ˜ ์žˆ๋‹ค.

 

datetimes(field, kind, order='ASC', tzinfo=None): queryset์—์„œ ํŠน์ • DatetimeField์˜ ๋ชจ๋“  ๋‚ ์งœ/์‹œ๊ฐ„์„ datetime.datetime ๊ฐ์ฒด ๋ฆฌ์ŠคํŠธ๋กœ ๋ณ€ํ™˜ํ•˜๋ฉฐ, kind์—๋Š” ๋ฐ˜ํ™˜ํ•  ๋‹จ์œ„ ("year", "month", "week", "day", "hour", "minute", "second")๊ฐ€ ๋“ค์–ด๊ฐ€๋ฉฐ ์ง€์ •ํ•œ ๋‹จ์œ„๋กœ truncated๋˜์–ด ๋ฐ˜ํ™˜ํ•œ๋‹ค. tzinfo๋Š” ๋ฐ˜ํ™˜ ์ „ ์‹œ๊ฐ„๋Œ€๋ฅผ ๋ณ€ํ™˜ํ•  tzinfo ๊ฐ์ฒด๋กœ, None์ด๋ฉด ํ˜„์žฌ Django ์‹œ๊ฐ„๋Œ€๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. timezone.utc์ด ๋“ค์–ด๊ฐ€๋ฉด utc ์‹œ๊ฐ„๋Œ€๋กœ ๋ณ€ํ™˜๋œ๋‹ค.

 

none(): ์ ˆ๋Œ€ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š๋Š” ๋นˆ queryset ์ƒ์„ฑํ•˜๋ฉฐ, isinstance(Entry.objects.none(), EmptyQuerySet)  # True ์ด๋Ÿฐ์‹์œผ๋กœ ์‚ฌ์šฉ๋œ๋‹ค.

 

all(): ํ˜„์žฌ queryset์˜ ๋ณต์‚ฌ๋ณธ์„ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ, ๊ธฐ๋ณธ์ ์œผ๋กœ ๋งŽ์ด ์‚ฌ์šฉ๋œ๋‹ค.

 

union(*other_qs, all=False): sql์˜ UNION ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•ด ๋‘ ๊ฐœ ์ด์ƒ์˜ queryset ๊ฒฐ๊ณผ๋ฅผ ํ•ฉ์น˜๋Š” ๋ฉ”์„œ๋“œ์ด๋‹ค. ๊ธฐ๋ณธ ๋™์ž‘์€ ์ค‘๋ณต๊ฐ’์„ ์ œ๊ฑฐํ•˜๊ณ  ํ•ฉ์นœ๋‹ค. ์ค‘๋ณต์„ ํ—ˆ์šฉํ•˜๋ ค๋ฉด all=True ์ธ์ž๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ์ฒซ ๋ฒˆ์งธ ๊ธฐ์ค€ queryset์œผ๋กœ ๋ชจ๋ธ์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

 

intersection(*other_qs): sql์˜ INTERSECT ์—ฐ์‚ฐ๊ณผ ๋™์ผํ•˜๋‹ค. ์—ฌ๋Ÿฌ queryset์—์„œ ๊ณตํ†ต์œผ๋กœ ์กด์žฌํ•˜๋Š” ๊ฐ’๋งŒ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ์ค‘๋ณต์€ ์ œ๊ฑฐ๋œ๋‹ค. ์ฒซ ๋ฒˆ์งธ ๊ธฐ์ค€ queryset์œผ๋กœ ๋ชจ๋ธ์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

qs1 = Author.objects.values_list("name")           # [('Alice',), ('Bob',), ('Charlie',)]
qs2 = Entry.objects.values_list("headline")       # [('Bob',), ('Zebra News',), ('Charlie',)]
qs3 = Extra.objects.values_list("title")          # [('Charlie',), ('Alice',)]

qs_common = qs1.intersection(qs2, qs3)
print(list(qs_common))  # [('Charlie',)]

 

difference(*other_qs): sql์˜ EXCEPT ์—ฐ์‚ฐ๊ณผ ๋™์ผํ•˜๋‹ค. ์ฒซ ๋ฒˆ์งธ queryset์—๋Š” ์กด์žฌํ•˜์ง€๋งŒ, ๋‹ค๋ฅธ Queryset์—๋Š” ์—†๋Š” ๊ฐ’๋“ค๋งŒ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์ฒซ ๋ฒˆ์งธ ๊ธฐ์ค€ queryset์œผ๋กœ ๋ชจ๋ธ์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

 

extra(): django orm๋งŒ์œผ๋กœ ํ‘œํ˜„ํ•˜๊ธฐ ์–ด๋ ค์šด ๋ณต์žกํ•œ SQL ๊ตฌ๋ฌธ์„ queryset์— ์ง์ ‘์ถ”๊ฐ€ํ•  ๋•Œ ์‚ฌ์šฉ, ์ตœํ›„์˜ ์ˆ˜๋‹จ์œผ๋กœ ์‚ฌ์šฉํ•˜๊ธธ ๊ถŒ์žฅํ•œ๋‹ค. ์˜ค๋ž˜๋œ API์ด๊ธฐ ๋•Œ๋ฌธ์— ํ–ฅํ›„ ์—†์–ด์งˆ ์˜ˆ์ •์ด๋ผ๊ณ  ํ•œ๋‹ค.

 

defer(*fields): ๋ชจ๋ธ์˜ ์ผ๋ถ€ ํ•„๋“œ๋ฅผ ๋‚˜์ค‘์— ๋ถˆ๋Ÿฌ์˜ค๋„๋ก ์ง€์—ฐ์‹œํ‚ค๋Š” ๊ฒƒ์ด๋‹ค. ๋ชจ๋ธ์— ๋ฐ์ดํ„ฐ๊ฐ€ ๋งŽ๊ณ  ์ผ๋ถ€ ํ•„๋“œ๋Š” ๋ฌด๊ฒ๊ฑฐ๋‚˜ ํ•„์š” ์—†๋Š” ๊ฒฝ์šฐ์— ์‚ฌ์šฉํ•œ๋‹ค.

 

only(*fields): ์ฆ‰์‹œ ๋ถˆ๋Ÿฌ์˜ฌ ํ•„๋“œ๋งŒ ์ง€์ •ํ•˜๋ฉฐ, ๋‚˜๋จธ์ง€๋Š” defer์ด ์ ์šฉ๋œ๋‹ค. ๊ฑฐ์˜ ๋ชจ๋“  ํ•„๋“œ๋ฅผ ์ง€์—ฐ์‹œํ‚ค๊ณ  ํ•„๋“œ ์ผ๋ถ€๋งŒ ์ฆ‰์‹œ ๊ฐ€์ ธ์˜ฅ ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

 

using(alias): ์—ฌ๋Ÿฌ DB๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ํŠน์ • DB๋ฅผ ์„ ํƒํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด Entry.objects.using("backup") ์‹์œผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด django ํ”„๋กœ์ ํŠธ์— DATABASES = {'defualt': {}, 'backup': {}} ์ด๋ ‡๊ฒŒ ๋‘ ๊ฐœ์˜ DB๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•œ๋‹ค.  DB ์ง€์ • ์—†์ด ์กฐํšŒํ•˜๋ฉด ํ•ญ์ƒ default DB์—์„œ ๊ฐ€์ ธ์˜จ๋‹ค. ํŠน์ • DB๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ์ฒซ๋ฒˆ์งธ ์ค„ ์ฒ˜๋Ÿผ ์ง€์ •ํ•˜๋ฉด backup DB์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค. ์ฆ‰, ๋™์ผํ•œ ๋ชจ๋ธ Entry๋ผ๋„ DB๋ฅผ ๋ฐ”๊ฟ”์„œ ์กฐํšŒ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค. **** ํ•˜์ง€๋งŒ Entry.objects.using("backup").create(title="Test") ์ฒ˜๋Ÿผ DB๋ฅผ ๋ฐ”๊พธ๋ฉด ์“ฐ๊ธฐ๋„ ํ•ด๋‹น DB์—์„œ ์ด๋ฃจ์–ด์ง€๊ธฐ ๋•Œ๋ฌธ์— ์ฃผ๋กœ ์ฝ๊ธฐ ์ „์šฉ ์ฟผ๋ฆฌ์—์„œ ์‚ฌ์šฉ๋œ๋‹ค.

 

raw(raw_query, params=(), translations=None, using=None): SQL์„ ์ง์ ‘ ์‹คํ–‰ํ•˜๊ณ , ๊ฒฐ๊ณผ๋ฅผ ๋ชจ๋ธ ์ธ์Šคํ„ด์Šค๋กœ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

# ORM์œผ๋กœ ์•ˆ๋˜๋Š” ๋ณต์žกํ•œ ์ฟผ๋ฆฌ
entries = Entry.objects.raw("SELECT * FROM entry WHERE rating > %s", [5])
for e in entries:
    print(e.title)

 


[Queryset method]

 

get(*args, **kwargs): ์กฐ๊ฑด์— ๋งž๋Š” ๊ฐ์ฒด ํ•˜๋‚˜๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค. ๋ฌด์กฐ๊ฑด ํ•˜๋‚˜๋งŒ ์กด์žฌํ•ด์•ผํ•˜๋ฉฐ, ๊ฐ์ฒด๊ฐ€ ์—†์„ ๋•DoesNotExist, ๊ฐ์ฒด๊ฐ€ ์—ฌ๋Ÿฌ๊ฐœ์ผ ๋• MultipleObjectsReturned ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

 

create(): ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•จ๊ณผ ๋™์‹œ์— ์ €์žฅ๊นŒ์ง€ ํ•œ๋ฒˆ์— ์ˆ˜ํ–‰ํ•œ๋‹ค. pk๋ฅผ ์ˆ˜๋™์œผ๋กœ ์ง€์ •ํ•ด์„œ ์ค‘๋ณต๋˜๋ฉด IntegrityError๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

 

get_or_create(): ๊ฐ์ฒด๊ฐ€ ์กด์žฌํ•˜๋ฉด ๊ฐ€์ ธ์˜ค๊ณ  ์—†์œผ๋ฉด ์ƒ์„ฑํ•œ๋‹ค. ๋ฐ˜ํ™˜๊ฐ’์— obj, created์—์„œ๋Š” created๊ฐ€ True๋ฉด ์ƒˆ๋กœ ์ƒ์„ฑ๋œ ๊ฐ’์ด๋‹ค. ํ‚ค์›Œ๋“œ ์ธ์ž๊ฐ€ ์œ ์ผํ•ด์•ผ ๋™์‹œ์„ฑ ๋ฌธ์ œ ๋ฐฉ์ง€๊ฐ€ ๊ฐ€๋Šฅํ•˜๋ฉฐ ์—ฌ๋Ÿฌ ๊ฐœ ๋ฐœ๊ฒฌ๋˜๋ฉด ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ MultipleObjectsReturned ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

 

update_or_create(): ๊ฐ์ฒด๊ฐ€ ์กด์žฌํ•˜๋ฉด ์—…๋ฐ์ดํŠธํ•˜๊ณ , ์—†์œผ๋ฉด ์ƒˆ๋กœ ์ƒ์„ฑํ•œ๋‹ค. defaults๋Š” ์—…๋ฐ์ดํŠธ ์‹œ ํ•„๋“œ๊ณ  create_defuaults๋Š” ์ƒ์„ฑ ์‹œ์˜ ํ•„๋“œ์ด๋‹ค.

 

bulk_create(): ์—ฌ๋Ÿฌ ๊ฐ์ฒด๋ฅผ ํ•œ๋ฒˆ์— DB์— ์ €์žฅํ•œ๋‹ค.

objs = Entry.objects.bulk_create([
    Entry(headline="This is a test"),
    Entry(headline="This is only a test"),
])

 

bulk_update(): ์—ฌ๋Ÿฌ ๊ฐ์ฒด๋ฅผ ํšจ์œจ์ ์œผ๋กœ ์—…๋ฐ์ดํŠธ ๊ฐ€๋Šฅํ•˜๋‹ค.

objs[0].headline = "Updated 1"
objs[1].headline = "Updated 2"
Entry.objects.bulk_update(objs, ["headline"])

 

count(): DB์˜ ๊ฐœ์ˆ˜ ์กฐํšŒ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค. ์ด๋ฏธ queryset์ด ํ‰๊ฐ€๋œ ๊ฒฝ์šฐ len()์ด ๋” ๋น ๋ฅด๋‹ค.

 

in_bulk(): pk ๋˜๋Š” ํŠน์ • ์œ ๋‹ˆํฌ ํ•„๋“œ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋”•์…”๋„ˆ๋ฆฌ๋กœ ๋ฐ˜ํ™˜๋œ๋‹ค.

 

iterator(): ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ์ ์œผ๋กœ ๊ฒฐ๊ณผ๋ฅผ ํ•œ ๋ฒˆ์— ์ฝ์ง€ ์•Š๊ณ  ์ˆœํšŒํ•œ๋‹ค. ๋Œ€์šฉ๋Ÿ‰ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ์— ์œ ์šฉํ•˜๋‹ค.

 

latest() / earliest(): ํŠน์ • ํ•„๋“œ ๊ธฐ์ค€์œผ๋กœ ๊ฐ€์žฅ ์ตœ์‹  / ๊ฐ€์žฅ ์˜ค๋ž˜๋œ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. 

 

first() / last(): queryset์˜ ์ฒซ ๋ฒˆ์งธ / ๋งˆ์ง€๋ง‰ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ ๊ฐ์ฒด๊ฐ€ ์—†์œผ๋ฉด None์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

 

aggregate(): queryset์˜ ์ง‘๊ณ„๋ฅผ dict์œผ๋กœ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

 

exists(): ์กฐ๊ฑด์— ๋งž๋Š” ๊ฐ์ฒด๊ฐ€ ์žˆ์œผ๋ฉด True๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ, if queryset: ๋ณด๋‹ค ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ๋ถ€ํ•˜๊ฐ€ ์ ๋‹ค.

 

contains(): queryset์— ํŠน์ • ๊ฐ์ฒด๊ฐ€ ํฌํ•จ๋ผ ์žˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

 

update(): ์กฐ๊ฑด์— ๋งž๋Š” ๊ฐ์ฒด๋ฅผ ํ•œ๋ฒˆ์— sql๋กœ ์—…๋ฐ์ดํŠธํ•œ๋‹ค. save() ๋ฐ˜๋ณต ํ˜ธ์ถœ์ด ๋ถˆํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํšจ์œจ์ ์ด๋‹ค.

Entry.objects.filter(pub_date__year=2010).update(comments_on=False)

 

delete(): ์กฐ๊ฑด์— ๋งž๋Š” ๊ฐ์ฒด๋ฅผ ํ•œ๋ฒˆ์— ์‚ญ์ œํ•œ๋‹ค.

 

as_manager(): queryset ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ง„ ์ปค์Šคํ…€ Manager๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

MyQuerySet.as_manager()

# ์‚ฌ์šฉ์˜ˆ์‹œ

from django.db import models

# 1. ์ปค์Šคํ…€ QuerySet ์ •์˜
class EntryQuerySet(models.QuerySet):
    def published(self):
        return self.filter(is_published=True)
    
    def recent(self):
        return self.order_by('-created_at')

# 2. QuerySet ๋ฉ”์„œ๋“œ๋ฅผ Manager๋กœ ๋ณ€ํ™˜
class Entry(models.Model):
    title = models.CharField(max_length=200)
    is_published = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)

    objects = EntryQuerySet.as_manager()

 

explain(): ์ฟผ๋ฆฌ ์‹คํ–‰์˜ ๊ณ„ํš์„ ์กฐํšŒํ•œ๋‹ค.

print(Entry.objects.filter(title="My Blog").explain())

 

reference: django document https://docs.djangoproject.com/en/5.2/

'Django-rest-framework' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[In-depth] django orm ํ…Œ์ŠคํŠธ์ฝ”๋“œ ๊ด€๋ จ  (0) 2025.09.30
[Django] Django-Channels  (0) 2025.05.12
JSONField ์„ค๋ช… ๋ฐ ๋™์ž‘๋ฐฉ์‹  (0) 2023.11.03
exists ๋‘๊ฐ€์ง€ ๋ฐฉ์‹  (0) 2023.03.30
swg_serializers ๊ด€๋ จ  (0) 2023.03.30
'Django-rest-framework' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
  • [In-depth] django orm ํ…Œ์ŠคํŠธ์ฝ”๋“œ ๊ด€๋ จ
  • [Django] Django-Channels
  • JSONField ์„ค๋ช… ๋ฐ ๋™์ž‘๋ฐฉ์‹
  • exists ๋‘๊ฐ€์ง€ ๋ฐฉ์‹
kasie
kasie
3๋…„์ฐจ ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž์˜ ์„ฑ์žฅ ๊ธฐ๋ก, ๊ทธ๋ฆฌ๊ณ  ์‹ค์ „ ๊ฐœ๋ฐœ ๋…ธํŠธ! ๐Ÿš€
  • kasie
    ๐ŸŽต return 200 – ์ฝ”๋“œ๋„ ๋ธ”๋กœ๊ทธ๋„, ์ •์ƒ ์ž‘๋™ ์ค‘
    kasie
  • ์ „์ฒด
    ์˜ค๋Š˜
    ์–ด์ œ
    • All (80)
      • Dev-Note (7)
      • Trouble-Shooting (4)
      • Docker (8)
      • SQLAlchemy (1)
      • Django-rest-framework (32)
      • TypeScript & NestJS (4)
      • Kotlin & Spring Boot (3)
      • Git (3)
      • Refactoring (3)
      • Academics (15)
  • ๋ธ”๋กœ๊ทธ ๋ฉ”๋‰ด

    • ํ™ˆ
  • ๋งํฌ

  • ๊ณต์ง€์‚ฌํ•ญ

  • ์ธ๊ธฐ ๊ธ€

  • ํƒœ๊ทธ

    Document
    ์šฐ๋ถ„ํˆฌ ๋ฆฌ๋ˆ…์Šค #๋ฆฌ๋ˆ…์Šค #์šฐ๋ถ„ํˆฌ #ํŠน์ˆ˜๋ฌธ์ž #๋ฆฌ๋ˆ…์ŠคํŠน์ˆ˜๋ฌธ์ž #VM #VMWARE #vm #vmware
    ์ •์ฒ˜๊ธฐ
    ์ˆ˜์ œ๋น„
    ๊ณต์‹๋ฌธ์„œ
    ๋น…๋ถ„๊ธฐํ•„๊ธฐ
    ORM
    ์ •๋ณด์ฒ˜๋ฆฌ๊ธฐ์‚ฌ ํ•„๊ธฐ
    ๋น…๋ฐ์ดํ„ฐ๋ถ„์„๊ธฐ์‚ฌ
    ๋น…๋ถ„๊ธฐ
    ์šฐ๋ถ„ํˆฌ๋ฆฌ๋ˆ…์Šค #์ •๋ฆฌ #ํ”„๋กœ์„ธ์Šค๊ด€๋ฆฌ๋ช…๋ น #ps #๋ฆฌ๋ˆ…์Šค #Linux #linux #vmware
    ํ•„๊ธฐ
    ์œ ํˆฌ๋ธŒ
    ์ •๋ณด์ฒ˜๋ฆฌ๊ธฐ์‚ฌ ํ•„๊ธฐ 3ํšŒ
    django
    DRF
    ์‹œ๋‚˜๊ณต
    cbt
    2022
    ์ •๋ณด์ฒ˜๋ฆฌ๊ธฐ์‚ฌ
  • ์ตœ๊ทผ ๋Œ“๊ธ€

  • ์ตœ๊ทผ ๊ธ€

  • hELLOยท Designed By์ •์ƒ์šฐ.v4.10.5
kasie
[In-depth] django queryset + SQL
์ƒ๋‹จ์œผ๋กœ

ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”