November 06, 2020
filter(**kwargs)
μ§μ λ μ‘°ν λ§€κ° λ³μμ μΌμΉνλ κ°μ²΄λ₯Ό ν¬ν¨νλ μλ‘μ΄ QuerySet
μ λ°ννλ€.
μ‘°ν λ§€κ° λ³μ (**kwargs)
λ νλ μ‘°ν νμμ΄μ΄μΌ νλ€. μ¬λ¬ λ§€κ° λ³μλ κΈ°λ³Έ SQLλ¬Έμμ AND
λ₯Ό ν΅ν΄ κ²°ν©λλ€.
λ 볡μ‘ν 쿼리 (μλ₯Όλ€μ΄ OR
λ¬Έμ΄ μλ 쿼리)λ₯Ό μ€νν΄μΌ νλ κ²½μ° Q objects
λ₯Ό μ¬μ©ν μ μλ€.
exclude(**kwargs)
μ§μ λ μ‘°ν λ§€κ° λ³μμ μΌμΉνμ§ μλ κ°μ²΄λ₯Ό ν¬ν¨νλ μλ‘μ΄ QuerySet
μ λ°ννλ€.
μ‘°ν λ§€κ° λ³μ (**kwargs)
λ νλ μ‘°ν νμμ΄μ΄μΌ νλ€. μ¬λ¬ λ§€κ° λ³μλ κΈ°λ³Έ SQLλ¬Έμμ AND
λ₯Ό ν΅ν΄ κ²°ν©λλ©° μ μ²΄κ° NOT()
μΌλ‘ λ¬Άμ¬ μλ€.
μλ μμ λ pub_date
κ° 2005-01-03μ΄ν μ΄λ©°(AND
) μ λͺ©μ΄ βHelloβλͺ¨λ νλͺ©μ μ μΈνλ€.
Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3), headline='Hello')
SQLλ¬ΈμΌλ‘λ λ€μκ³Ό κ°λ€.
SELECT ...
WHERE NOT (pub_date > '2005-01-03' AND headline = 'Hello')
μλ μμ λ pub_date
κ° 2005-01-03μ΄ν μ΄κ³ (OR
) μ λͺ©μ΄ βHelloβλͺ¨λ νλͺ©μ μ μΈνλ€.
Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3)).exclude(headline='Hello')
SQLλ¬ΈμΌλ‘λ λ€μκ³Ό κ°λ€.
SELECT ...
WHERE NOT pub_date > '2005-1-3'
AND NOT headline = 'Hello'
λλ²μ§Έ μμ λ λ μ νμ μ΄λ©° λ 볡μ‘ν 쿼리 (μλ₯Όλ€μ΄ OR
λ¬Έμ΄ μλ 쿼리)λ₯Ό μ€νν΄μΌ νλ κ²½μ° Q objects
λ₯Ό μ¬μ©ν μ μλ€.
annotate(*args, **kwargs)
μ 곡λ 쿼리 μ λͺ©λ‘μ μ¬μ©νμ¬ QuerySet
μ κ° κ°μ²΄μ μ£Όμμ μΆκ°νλ€. μμ λ¨μ κ°, λͺ¨λΈμ νλμ λν μ°Έμ‘° (λλ λͺ¨λ κ΄κ³ λͺ¨λΈ), λλ κ°μ²΄μ κ΄λ ¨λ κ°μ²΄μ λν κ³μ°λ μ§κ³ μ (νκ· , ν©κ³ λ±)μΌ μ μλ€.
annotate()
μ κ° μΈμλ λ°νλλ QuerySet
μ κ° κ°μ²΄μ μΆκ°λλ μ£Όμμ΄λ€.
**kwargs
λ₯Ό μ¬μ©νμ¬ μ§μ λ μ£Όμμ ν€μλ μ£Όμμ λ³μΉμΌλ‘ μ¬μ©λλ€. μ΅λͺ
μΈμμλ μ§κ³ ν¨μμ μ΄λ¦κ³Ό μ§κ³λλ λͺ¨λΈ νλμ λ°λΌ μμ±λ λ³μΉμ΄ μλ€. λ¨μΌ νλλ₯Ό μ°Έμ‘°νλ μ§κ³μλ§ μ΅λͺ
μΈμκ° λ μ μλ€. κ·Έ λ°μ λͺ¨λ κ²μ ν€μλ μΈμμ¬μΌ νλ€.
μλ₯Όλ€μ΄ λΈλ‘κ·Έ λͺ©λ‘μ μ‘°μνλ κ²½μ° κ° λΈλ‘κ·Έμ μμ±λ νλͺ© μλ₯Ό νμΈν μ μλ€.
>>> from django.db.models import Count
>>> q = Blog.objects.annotate(Count('entry'))
# 첫λ²μ§Έ λΈλ‘κ·Έ μ΄λ¦
>>> q[0].name
'Blogasaurus'
# 첫λ²μ§Έ λΈλ‘κ·Έμ νλͺ© μ
>>> q[0].entry__count
42
Blog λͺ¨λΈμ μ체μ μΌλ‘ entry__count
μμ±μ μ μνμ§ μμ§λ§ **kwargs
λ₯Ό μ¬μ©νμ¬ μ§κ³ ν¨μλ₯Ό μ§μ νλ©΄ μ£Όμμ μ΄λ¦μ μ¬μ©μκ° μμ±ν μ μμΌλ©° μ μ΄ ν μ μλ€.
>>> q = Blog.objects.annotate(number_of_entries=Count('entry'))
# μ 곡λ μ΄λ¦ number of entriesμ μ¬μ©νλ 첫λ²μ§Έ λΈλ‘κ·Έμ νλͺ© μ
>>> q[0].number_of_entries
42
μ§κ³μ λν μμΈν λ΄μ©μ λ€μμ μ°Έκ³ νλ€.
order_by(*fields)
κΈ°λ³Έμ μΌλ‘ QuerySet
μ μν΄ λ°νλ κ²°κ³Όλ λͺ¨λΈμ Meta
ν΄λμ€μ μλ ordering
μ΅μ
μ μν΄ μ 곡λλ ordering tuple
μ λ°λΌ μ λ ¬λλ€. νμ§λ§ order_by
λ©μλλ₯Ό μ¬μ©νμ¬ QuerySet
λ³λ‘ μ΄λ₯Ό μ¬μ μ ν μ μλ€.
Entry.objects.filter(pub_date__year=2005).order_by('-pub_date', 'headline')
μμ κ²°κ³Όλ pub_date
λ₯Ό λ΄λ¦Όμ°¨μμΌλ‘ μ λ ¬ν λ€μ μ λͺ©μ μ€λ¦μ°¨μμΌλ‘ μ λ ¬λλ€. pub_date
μμ -
κΈ°νΈλ λ΄λ¦Όμ°¨μμ μλ―Ένλ€. 무μμλ‘ μ λ ¬νλ €λ©΄ λ€μκ³Ό κ°μ΄ ?
λ₯Ό μ¬μ©νλ€.
Entry.objects.order_by('?')
μ°Έκ³ λ‘ order_by('?')
λ μ±λ₯μ΄ λ§€μ° μμ’μΌλ μ¬μ©μ μμ νλ κ²μ΄ μ’λ€.
λ€λ₯Έ λͺ¨λΈμ νλλ³λ‘ μ λ ¬νλ €λ©΄ λͺ¨λΈ κ΄κ³μμ 쿼리ν λμ λμΌν ꡬ문μ μ¬μ©νλ€. μ¦, νλ μ΄λ¦, double underscore(__
), μ λͺ¨λΈμ νλ μ΄λ¦λ±μ΄ κ²°ν©νλ €λ λͺ¨λΈ μλ§νΌ κ³μλλ€. μλ₯Όλ€λ©΄ μλμ κ°λ€.
Entry.objects.order_by('blog__name', 'headline')
λ€λ₯Έ λͺ¨λΈκ³Ό κ΄λ ¨λ νλλ₯Ό κΈ°μ€μΌλ‘ μ λ ¬νλ €κ³ νλ©΄ Django
λ κ΄λ ¨ λͺ¨λΈμ κΈ°λ³Έ μμλ₯Ό μ¬μ©νκ±°λ Meta
ν΄λμ€μ ordering
μ΄ μ§μ λμ§ μμ κ²½μ° κ΄λ ¨ λͺ¨λΈμ Primary Key
λ₯Ό κΈ°μ€μΌλ‘ μ λ ¬νλ€. μλ₯Όλ€μ΄, Blogλͺ¨λΈμλ κΈ°λ³Έμμκ° μ§μ λμ΄ μμ§ μκΈ°λλ¬Έμ
Entry.objects.order_by('blog')
μ΄κ²μ λ€μκ³Ό κ°λ€.
Entry.objects.order_by('blog__id')
λ§μ½ Blogλͺ¨λΈμ ordering = ['name']
μ΄ μ§μ λμ΄ μλ κ²½μ°λ λ€μκ³Ό κ°λ€.
Entry.objects.order_by('blog__name')
λν ννμμμ asc()
λλ desc()
λ₯Ό νΈμΆνμ¬ μΏΌλ¦¬ ννμλ³λ‘ μ λ ¬ ν μ λ μλ€.
Entry.objects.order_by(Coalesce('summary', 'headline').desc())
Entry.objects.order_by(Coalesce('summary', 'headline').asc())
asc()
μ desc()
μμλ null
κ°μ μ λ ¬νλ λ°©λ²μ μ μ΄νλ μΈμ nulls_first
λ° nulls_last
κ° μλ€.
π‘M:M λλ μμ°Έμ‘°κ΄κ³μμμ
order_by()
κ²°κ³Όλ₯Ό μ λ ¬νκΈ° μν΄ λ€μ€ κ° νλλ₯Ό μ§μ ν μ μλ€.
# Model class Event(Model): parent = models.ForeignKey( 'self', on_delete=models.CASCADE, related_name='children', ) date = models.DateField()
Event.objects.order_by('children__date')
μ¬κΈ°μμ κ° μ΄λ²€νΈμ λν΄ μ μ¬μ μΌλ‘ μ¬λ¬ μ£Όλ¬Έ λ°μ΄ν°κ° μμ μ μλ€. μ¬λ¬ νμ νλͺ©μ΄ μλ κ° μ΄λ²€νΈλ
order_by()
κ° μμ±νλ μQuerySet
μ μ¬λ¬λ² λ°νλλ€. μ¦,QuerySet
μμorder_by()
λ₯Ό μ¬μ©νλ©΄ μ²μμ μμ νλ κ² λ³΄λ€ λ λ§μ νλͺ©μ λ°ν ν μ μλ€. μ΄λ μλ§λ μμνμ§λ μΈλͺ¨μμ§λ μμ λ°μ΄ν°κ° λ κ²μ΄λ€.λ°λΌμ λ€μ€ κ° νλλ₯Ό μ¬μ©νμ¬ κ²°κ³Όλ₯Ό μ λ ¬ ν λλ μ£Όμν΄μΌ νλ€. μ£Όλ¬Ένλ κ° νλͺ©μ λν΄ νλμ μ£Όλ¬Έ λ°μ΄ν°λ§ μλ€κ³ νμ ν μ μλ€λ©΄ μ΄ λ°©λ²μ λ¬Έμ λμ§ μλλ€. κ·Έλ μ§ μμ κ²½μ° κ²°κ³Όκ° μμ ν κ²°κ³ΌμΈμ§ νμΈν΄μΌ ν νμκ° μλ€.
β οΈ
order_by()
λ 쿼리λ₯Ό λ°μμν¨λ€.
order_by()
μ μΆκ°λλ κ° νλλ 쿼리λ₯Ό λ°μμν¨λ€. μΆκ°νλ μΈλν€ μμ ν¬ν¨λλ€.쿼리μ μμκ° μ§μ λμ§ μμ κ²½μ° λ°μ΄ν°λ² μ΄μ€μμ μ§μ λμ§ μμ μμλ‘ κ²°κ³Όκ° λ¦¬ν΄λλ€. νΉμ μμλ‘ μ λ ¬ν λλ κ²°κ³Όμμ κ° κ°μ²΄λ₯Ό κ³ μ νκ² μλ³νλ νλ μ§ν©μΌλ‘
order_by()
ν λλ§ λ³΄μ₯λλ€. μλ₯Ό λ€μ΄ μ΄λ¦ νλκ° κ³ μ νμ§ μμ κ²½μ° μ΄λ¦μ κΈ°μ€μΌλ‘ μ λ ¬νλ€κ³ ν΄μ μ΄λ¦μ΄ κ°μ κ°μ²΄κ° νμ κ°μ μμλ‘ νμλλ κ²μ μλλ€.
reverse()
reverse()
λ©μλλ₯Ό μ¬μ©νλ©΄ QuerySet
μ μμκ° λ¦¬ν΄νλ μμλ₯Ό λ°λλ‘ λ§λ€μ μλ€. reverse()
λ₯Ό λλ² νΈμΆνλ€λ©΄ λ€μ μ μ λ°©ν₯μΌλ‘ λλμ μ¨λ€.
쿼리μ μμ λ§μ§λ§ 5κ° νλͺ©μ κ²μνλ €λ©΄ λ€μκ³Ό κ°μ΄ μ¬μ© ν μ μλ€.
my_queryset.reverse()[:5]
μ΄κ²μ Python
μμ μνμ€ λμ μ¬λΌμ΄μ€ νλκ²κ³Ό μμ ν κ°μ§ μλ€. μμ μλ λ§μ§λ§ νλͺ©μ λ¨Όμ λ°νν λ€μ λλ²μ§Έλ‘ 5κ°λ₯Ό λ°ννλ μ μ°¨λ₯Ό μ§ννλ€. Python
μμλ seq[-5:]
μ κ°μ΄ μνμ€μ μμλ₯Ό λ°λλ‘ λ€μ§μ§ μμλ λ§μ§λ§ 5κ°μ νλͺ©μ κ°μ Έμ¬ μ μμ§λ§ Django
μμλ μ΄λ° κ³Όμ μ SQLμμ ν¨μ¨μ μΌλ‘ μν ν μ μκΈ°λλ¬Έμ λμμ μ¬λΌμ΄μ€μ κ°μ μμΈμ€ λͺ¨λλ₯Ό μ§μνμ§ μλλ€.
λν reverse()
λ μΌλ°μ μΌλ‘ μ μ λ μμκ° μλ 쿼리μ
μμλ§ νΈμΆλμ΄μΌ νλ€. (κΈ°λ³Έ μμλ₯Ό μ μνλ λͺ¨λΈμ λν΄ μΏΌλ¦¬ ν λ λλ order_by()
λ₯Ό μ¬μ© ν λ), λ§μ½ μ£Όμ΄μ§ 쿼리μ
μ λν΄ μ΄λ¬ν μμκ° μ μλμ΄ μμ§ μμ κ²½μ° reverse()
λ₯Ό νΈμΆ ν΄λ ν¨κ³Όκ° μλ€.
distinct()
# Only PostgreSQL
distinct(*fields)
SQLλ¬Έλ²μμ SELECT DISTINCT
λ₯Ό μ¬μ©νλ μλ‘μ΄ QuerySetμ 리ν΄νλ€. μ΄λ κ² νλ©΄ 쿼리 κ²°κ³Όμμ μ€λ³΅ νμ΄ μ κ±°λλ€.
κΈ°λ³Έμ μΌλ‘ QuerySet
μ μ€λ³΅νμ μ κ±°νμ§ μλλ€. μ€μ λ‘ Bolg.objects.all()
κ³Ό κ°μ κ°λ¨ν 쿼리λ κ²°κ³Ό νμ΄ μ€λ³΅ λ κ°λ₯μ±μ΄ μκΈ° λλ¬Έμ μ΄λ κ±°μ λ¬Έμ κ° λμ§ μλλ€. κ·Έλ¬λ μΏΌλ¦¬κ° μ¬λ¬ ν
μ΄λΈμ κ±Έμ³μΌ νλ€λ©΄ μ€λ³΅λλ κ²°κ³Όλ₯Ό μ»μ μ μλ€ μ΄λ΄λ distinct()
λ₯Ό μ¬μ©νλ€.
PostgreSQLμμλ distinct()
μ Positional argumentsλ₯Ό μ λ¬ ν μ μλ€. μ΄λ μΈμ κ°μ νλ κ°μ΄λ€. μ΄κ²μ SELECT DISTINCT ON
κ³Ό κ°μ SQLμΏΌλ¦¬λ‘ λ³νλλ€ νμ§λ§ Raw SQLκ³Ό μ°¨μ΄μ μ΄ μ‘΄μ¬νλλ° μΌλ°μ μΈ distinct()
νΈμΆμ κ²½μ° λ°μ΄ν° λ² μ΄μ€λ ꡬλ³λλ νμ κ²°μ ν λ κ° νμ κ° νλλ₯Ό λΉκ΅νλ€. νμ§λ§ ORMμμλ μ§μ λ νλλ₯Ό μΈμλ‘ κ°λ distinct()
νΈμΆμ κ²½μ° λ°μ΄ν°λ² μ΄μ€κ° μ§μ λ νλ μ΄λ¦λ§ λΉκ΅νλ€.
π‘νλλ₯Ό μΈμλ‘ κ°λ
distinct()
νλ μ΄λ¦μ μ§μ ν λ QuerySetμλ
order_by()
κ° νμνλ©°order_by()
μ νλλdistinct()
μ μ 곡λ νλμ λμΌνκ² μ§μ λμ΄μΌ νλ€.μλ₯Όλ€μ΄
SELECT DISTINCT ON (a)
λ aμ΄μ κ° κ°μ λν 첫 λ²μ§Έ νμ μ 곡νλ€. λ§μ½ orderingμ΄ λμ΄ μμ§ μλ€λ©΄ μμμ νμ΄ λ¦¬ν΄λλ€.μμ (PostgreSQLμμλ§ κ°λ₯)
>>> Author.objects.distinct() >>> Entry.objects.order_by('pub_date').distinct('pub_date') >>> Entry.objects.order_by('blog').distinct('blog') >>> Entry.objects.order_by('author', 'pub_date').distinct('author', 'pub_date') >>> Entry.objects.order_by('blog__name', 'mod_date').distinct('blog__name', 'mod_date') >>> Entry.objects.order_by('author', 'pub_date').distinct('author')
β οΈ
order_by()
μdistinct()
order_by()
νΈμΆμ μ¬μ©λ λͺ¨λ νλλ SQLSELECT
컬λΌμ ν¬ν¨λλ€. μ΄λ‘ μΈν΄distinct()
μ ν¨κ» μ¬μ©νλ©΄ μκΈ°μΉ μμ κ²°κ³Όκ° λ°μν μ μλ€. λ§μ½ μ°κ³λ λͺ¨λΈμ νλλ₯Ό κΈ°μ€μΌλ‘ μ λ ¬νλ©΄ ν΄λΉ νλκ° μ νν μ΄μ μΆκ°λκ³ κ·Έλ μ§ μμΌλ©΄ μ€λ³΅λ νμ΄ κ΅¬λ³λλ κ² μ²λΌ λ³΄μΌ μ μλ€. μΆκ° μ΄μ λ°νλ κ²°κ³Όμ νμλμ§ μκΈ° λλ¬Έμ (μμ μ§μ μ μ§μνκΈ° μν΄ μ‘΄μ¬νλ κ²½μ°μλ§ λ¦¬ν΄κ°μ νμ) λλλ‘ λͺ ννμ§ μμ κ²°κ³Όκ° λ°νλλ κ²μ²λΌ 보μΈλ€.λ§μ°¬κ°μ§λ‘
values()
λ₯Ό μ¬μ©νμ¬ μ νν μ΄μ μ ννλ κ²½μ°order_by()
(λλ κΈ°λ³Έ ordering)μ μ¬μ©λ μ΄μ΄ κ³μ κ΄λ ¨λλ©° κ²°κ³Όμ κ³ μ μ±μ μν₯μ λ―ΈμΉ μ μλ€.μ¬κΈ°μ μ€μνκ²μ μ¬λ¬ λͺ¨λΈμ΄ μ°κ΄λμ΄ μλ 쿼리μ μ
distinct()
λ₯Ό μ¬μ©νλ κ²½μ° μ λ ¬ κΈ°μ€μ΄ κ΄λ ¨ λͺ¨λΈμ νλλΌλ©΄ μ£Όμν΄μΌ νλ€λ κ²μ΄λ€. λ§μ°¬κ°μ§λ‘,**distinct()
λ°values()
λ₯Ό ν¨κ» μ¬μ©ν λλvalues()
μ νλκ° μλ μ΄μΈμ νλλ‘ μ λ ¬ ν λ μ£Όμ**ν΄μΌ νλ€.λν
order_by()
λ μ μλ κΈ°λ³Έ κ΄λ ¨ λͺ¨λΈ μμλ₯Ό μ¬μ©νλ€.DISTINCT ON
μμ΄ORDER BY
μ μ μμ λΆλΆμ μλ μκ³Ό μΌμΉνλμ§ νμΈνλ €λ©΄ κ΄κ³μ_id
λλ μ°Έμ‘°λ νλλ₯Ό κΈ°μ€μΌλ‘ λͺ μμ μΌλ‘ μ λ ¬ν΄μΌ ν μλ μλ€. μλ₯Ό λ€μ΄ Blogλͺ¨λΈμ΄ μ΄λ¦μΌλ‘ μ λ ¬μ μ λ ¬ν κ²½μ°Entry.objects.order_by('blog').distinct('blog')
μ μμλ 쿼리κ°
blog__name
μΌλ‘ μ λ ¬λμ΄DISTINCT ON
ννμκ³Ό μΌμΉνμ§ μκΈ° λλ¬Έμ μλνμ§ μλλ€. λ ννμμ΄ μΌμΉνλμ§ νμΈνλ €λ©΄ κ΄κ³_id
νλ (μ΄ κ²½μ°blog_id
)λλ μ°Έμ‘° λ νλ (blog_pk
)λ₯Ό κΈ°μ€μΌλ‘ λͺ μμ μΌλ‘ μ λ ¬ν΄μΌ νλ€.
values(*field, **expressions)
iterableλ‘ μ¬μ©λ λ λͺ¨λΈ μΈμ€ν΄μ€κ° μλ dictionary
μ λ°ννλ QuerySet
μ λ°ννλ€.
κ° dirctionary
λ λͺ¨λΈ κ°μ²΄μ μμ± μ΄λ¦μ ν΄λΉνλ ν€κ° μλ κ°μ²΄λ₯Ό λνλΈλ€. λ€μμ μμ λ values()
κ° λ°ννλ dictionary
μ μΌλ° λͺ¨λΈ κ°μ²΄λ₯Ό λΉκ΅νλ€.
# μ΄ λͺ©λ‘μλ Blog κ°μ²΄κ° ν¬ν¨λμ΄ μλ€.
>>> Blog.objects.filter(name__startswith='Beatles')
<QuerySet [<Blog: Beatles Blog>]>
# μ΄ λͺ©λ‘μλ dictionaryκ° ν¬ν¨λμ΄ μλ€.
>>> Blog.objects.filter(name__startswith='Beatles').values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>
values()
λ©μλλ SELECT
κ° μ νλμ΄μΌ νλ νλ μ΄λ¦μ μ§μ νλ optional positional arguments μΈ *fields
λ₯Ό μ¬μ©νλ€. νλλ₯Ό μ§μ νλ©΄ κ° dictionary
μλ μ§μ ν νλμ λν keyμ λμνλ valueλ§ ν¬ν¨λλ€. νλλ₯Ό μ§μ νμ§ μμΌλ©΄ dictionary
μ λ°μ΄ν°λ² μ΄μ€ ν
μ΄λΈμ λͺ¨λ νλμ λν keyμ valueκ° ν¬ν¨λλ€.
>>> Blog.objects.values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>
>>> Blog.objects.values('id', 'name')
<QuerySet [{'id': 1, 'name': 'Beatles Blog'}]>
values()
λ©μλλ annotate()
λ‘ μ λ¬λλ optional keyword argumentsμΈ **expresstions
μ μ¬μ©νλ€.
>>> from django.db.models.functions import Lower
>>> Blog.objects.values(lower_name=Lower('name'))
<QuerySet [{'lower_name': 'beatles blog'}]>
values()
λ©μλλ μ λ ¬λ μ¬μ©μ μ§μ μ‘°νλ₯Ό μ¬μ©ν μ μλ€.
>>> from django.db.models import CharField
>>> from django.db.models.functions import Lower
>>> CharField.register_lookup(Lower)
>>> Blog.objects.values('name__lower')
<QuerySet [{'name__lower': 'beatles blog'}]>
values()
μ λ΄μ μ§κ³λ λμΌν values()
μ λ΄μ λ€λ₯Έ μΈμ λ³΄λ€ μ°μ μμκ° λλ€. λ€λ₯Έ κ°μΌλ‘ κ·Έλ£Ήν ν΄μΌνλ κ²½μ° value()
μ κ³Ό λΆλ¦¬νμ¬ μ§κ³ν¨μλ₯Ό μ¬μ©ν΄μΌ νλ€.
>>> from django.db.models import Count
>>> Blog.objects.values('entry__authors', entries=Count('entry'))
<QuerySet [{'entry__authors': 1, 'entries': 20}, {'entry__authors': 1, 'entries': 13}]>
>>> Blog.objects.values('entry__authors').annotate(entries=Count('entry'))
<QuerySet [{'entry__authors': 1, 'entries': 33}]>
μ¬μ© κ°λ₯ν μΌλΆ νλμ κ°λ§ νμνκ³ λͺ¨λΈ μΈμ€ν΄μ€ κ°μ²΄μ κΈ°λ₯μ΄ νμνμ§ μλ€λ κ²μ μκ³ μμλ μ μ©νλ€. μ¬μ©ν΄μΌ νλ νλλ§ μ ννλ κ²μ΄ ν¨μ¨μ μ΄λ€.
λ§μ§λ§μΌλ‘ values()
νΈμΆ νμ filter()
, order_by()
λ±μ νΈμΆ ν μ μλ€. μ΄λ μ΄ λ νΈμΆμ΄ λμΌνλ€λ κ²μ μλ―Ένλ€.
Blog.objects.values().order_by('id')
Blog.objects.order_by('id').values()
OneToOneField
, ForeignKey
λ° ManyToManyField
μμ±μ ν΅ν΄ μμ°Έμ‘°κ° μλ κ΄λ ¨ λͺ¨λΈμ νλλ₯Ό μ°Έμ‘° ν μλ μλ€.
>>> Blog.objects.values('name', 'entry__headline')
<QuerySet [{'name': 'My blog', 'entry__headline': 'An entry'},
{'name': 'My blog', 'entry__headline': 'Another entry'}, ...]>
β οΈ
ManyToManyField
μμvalues()
μ¬μ©μ μ£Όμ μ¬ν
ManyToManyField
μμ± λ° μμ°Έμ‘° κ΄κ³μλ μ¬λ¬ νμ΄ μμ μ μμΌλ―λ‘ μ΄λ₯Ό ν¬ν¨νμ¬ κ²°κ³Ό μ§ν©μ 리ν΄κ°μ΄ λ°°λ‘ λμ΄λλ κ²°κ³Όλ₯Ό μ»μ μ μλ€. μ΄λvalues()
쿼리μ μ΄λ¬ν νλλ₯Ό μ¬λ¬ κ° ν¬ν¨νλ κ²½μ° νΉν μμ£Ό λ°μνλ©°, μ΄ κ²½μ° κ°λ₯ν λͺ¨λ μ‘°ν©μ΄ λ°νλλ€.
λ§μ½ μΈλν€μΈ foo
λΌλ νλκ° μλ κ²½μ° κΈ°λ³Έμ μΌλ‘ values()
νΈμΆμ μ€μ κ°μ μ μ₯νλ μ¨κ²¨μ§ λͺ¨λΈ μμ±μ μ΄λ¦μ΄κΈ° λλ¬Έμ foo_id
λΌλ dictionary
keyλ₯Ό λ°ννκ² λλ€. (foo
μμ±μ μ°κ΄ λͺ¨λΈμ λνλΈλ€) values()
λ₯Ό νΈμΆνκ³ νλ μ΄λ¦μ μ λ¬ν λ foo
λλ foo_id
λ₯Ό μ λ¬ν μ μμΌλ©° λμΌν κ²°κ³Όλ₯Ό μ»μ μ μλ€. (dictionary
keyλ μ λ¬ν νλ μ΄λ¦κ³Ό μΌμΉνλ€.)
>>> Entry.objects.values()
<QuerySet [{'blog_id': 1, 'headline': 'First Entry', ...}, ...]>
>>> Entry.objects.values('blog')
<QuerySet [{'blog': 1}, ...]>
>>> Entry.objects.values('blog_id')
<QuerySet [{'blog_id': 1}, ...]>
distinct()
μ ν¨κ» values()
λ₯Ό μ¬μ©ν λ μ¬μ©νλ μμκ° κ²°κ³Όμ μν₯μ μ€ μ μλ€.extra()
νΈμΆ νμ values()
μ μ μ¬μ©νλ κ²½μ° extra()
μμ μ νμΈμλ‘ μ μλ λͺ¨λ νλκ° values()
νΈμΆμ λͺ
μμ μΌλ‘ ν¬ν¨λμ΄μΌ νλ€. values()
νΈμΆ μ΄νμ μνλ extra()
νΈμΆμ μΆκ°λ‘ μ νλ νλκ° λ¬΄μλλ€.values()
λ€μ only()
λ° defer()
λ₯Ό νΈμΆνλ κ²μ μλ―Έκ° μμΌλ―λ‘ TypeError
κ° λ°μνλ€.λ³νκ³Ό μ§κ³λ₯Ό κ²°ν©νλ €λ©΄ λͺ
μμ μΌλ‘ λλ values()
μ λν ν€μλ μΈμλ‘ λ κ°μ annotate()
νΈμΆμ μ¬μ©ν΄μΌ νλ€. μμ κ°μ΄ ν΄λΉ νλ μ νμ λ³νμ΄ λ±λ‘λ κ²½μ° μ²«λ²μ§Έ annotate(0
λ₯Ό μλ΅ ν μ μμΌλ―λ‘ λ€μ μμ λ λμΌν κ²°κ³Όλ₯Ό κ°λλ€.
>>> from django.db.models import CharField, Count
>>> from django.db.models.functions import Lower
>>> CharField.register_lookup(Lower)
>>> Blog.objects.values('entry__authors__name__lower').annotate(entries=Count('entry'))
<QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]>
>>> Blog.objects.values(
... entry__authors__name__lower=Lower('entry__authors__name')
... ).annotate(entries=Count('entry'))
<QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]>
>>> Blog.objects.annotate(
... entry__authors__name__lower=Lower('entry__authors__name')
... ).values('entry__authors__name__lower').annotate(entries=Count('entry'))
<QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]>
values_list(*fields, flat=False, named=False)
λ°ν κ°μ΄ values()
μ λ€λ₯΄κ² ννμ λ°ννλ€λ μ μ μ μΈνλ©΄ values()
μ μ μ¬νλ€. κ° ννμλ values_list()
νΈμΆμ μ λ¬λ κ° νλ λλ ννμμ κ°μ΄ ν¬ν¨λλ€. λ°λΌμ 첫λ²μ§Έ νλͺ©μ 첫λ²μ§Έ νλμ΄λ€. μλ₯Όλ€λ©΄ λ€μκ³Ό κ°λ€.
>>> Entry.objects.values_list('id', 'headline')
<QuerySet [(1, 'First entry'), ...]>
>>> from django.db.models.functions import Lower
>>> Entry.objects.values_list('id', Lower('headline'))
<QuerySet [(1, 'first entry'), ...]>
λ¨μΌ νλλ§ μ λ¬νλ κ²½μ° flat
λ§€κ° λ³μλ μ λ¬ν μ μλ€. True
λ©΄ 리ν΄λ κ²°κ³Όκ° λ¨μΌ ννμ΄ μλλΌ λ¨μΌ κ°μμ μλ―Ένλ€.
>>> Entry.objects.values_list('id').order_by('id')
<QuerySet[(1,), (2,), (3,), ...]>
>>> Entry.objects.values_list('id', flat=True).order_by('id')
<QuerySet [1, 2, 3, ...]>
λ¨, νλκ° λκ° μ΄μμΈ κ²½μ° flat
μ μλ¬λ₯Ό λ°μ μν¨λ€.
named = True
λ₯Ό μ λ¬νμ¬ namedtuple()
μ κ²°κ³Όλ‘ μ»μ μ μλ€.
>>> Entry.objects.values_list('id', 'headline', named=True)
<QuerySet [Row(id=1, headline='First entry'), ...]>
namedtuple()
μ μ΄μ©νλ©΄ κ²°κ³Όλ₯Ό λ μ½κΈ° μ½κ² λ§λ€ μ μμ§λ§ namedtuple()
νμΌλ‘ λ³νλλ©΄μ μ½κ°μ μ±λ₯ μ νκ° λ°μλλ€.
values_list()
μ κ°μ μ λ¬νμ§ μμΌλ©΄ μ μΈλ μμλλ‘ λͺ¨λΈμ λͺ¨λ νλκ° λ°νλλ€.
μΌλ°μ μΌλ‘ values_list()
λ₯Ό μ¬μ©νλκ²μ νΉμ λͺ¨λΈ μΈμ€ν΄μ€μ νΉμ νλμ κ°μ κ°μ Έμ¬ λ μ¬μ©νλ€. μ΄λ₯Ό μν΄ values_list()
λ€μ get()
μ νΈμΆνλ€.
>>> Entry.objects.values_list('headline', flat=True).get(pk=1)
'First entry'
values()
λ° values_list()
λ λͺ¨λ νΉμ μ¬μ© μ¬λ‘μ λν μ΅μ νλ₯Ό μν κ²μ΄λ€. λͺ¨λΈ μΈμ€ν΄μ€λ₯Ό λ§λλ μ€λ²ν€λ μμ΄ λ°μ΄ν° νμ μ§ν©μ κ²μνλ€. λ°λΌμ M:M λ° κΈ°ν λ€μ€ κ΄κ³ (μ : 1:Mκ΄κ³μμ μμ°Έμ‘°)λ₯Ό λ€λ£° λ βνλμ ν, νλμ κ°μ²΄βκ° μ μ©λμ§ μκ³ λͺ¨λ λΆλ¦¬ λλ€.
λ€μμ ManyToManyField
λ₯Ό 쿼리 ν λμ λμμ΄λ€.
>>> Author.objects.values_list('name', 'entry__headline')
<QuerySet [('Noam Chomsky', 'Impressions of Gaza'),
('George Orwell', 'Why Socialists Do Not Believe in Fun'),
('George Orwell', 'In Defence of English Cooking'),
('Don Quixote', None)]>
λ€μμ μ±
μ μμ±ν μμ±μλ μ¬λ¬λ² νμλκ³ νλͺ©μ΄ μλ μμ±μλ entry__headline
μ΄ None
μΌλ‘ νμλλ κ²μ νμΈ ν μ μλ€.
λ§μ°¬κ°μ§λ‘ μμ°Έμ‘°λ₯Ό 쿼리ν λ μμ±μκ° μλ νλͺ©μ λν΄ None
μΌλ‘ νμλλ€.
>>> Entry.objects.values_list('authors')
<QuerySet [('Noam Chomsky',), ('George Orwell',), (None,)]>
date(field, kind, order='ASC')
QuerySet
μ λ΄μ© λ΄μμ νΉμ μ’
λ₯μ μ¬μ© κ°λ₯ν λͺ¨λ λ μ§λ₯Ό λνλ΄λ datetime.date
κ°μ²΄ λͺ©λ‘μΌλ‘ νκ°λλ QuerySet
μ 리ν΄νλ€.
νλλ λͺ¨λΈμ DateField
μ΄μΌ νλ€. kind
λ year
, month
, week
, day
μ΄μΌ νλ€. κ²°κ³Ό λͺ©λ‘μ κ° datetime.date
κ°μ²΄λ μ£Όμ΄μ§ μ νμΌλ‘ λ°μ΄ν°λ₯Ό μλΌλΈλ€.
year
λ νλμ λν λͺ¨λ κ³ μ μ°λ κ°μ΄ λ΄κΈ΄ listλ₯Ό λ°ννλ€.month
λ νλμ λν κ³ μ ν μ°λ/μ κ°μ΄ λ΄κΈ΄ listλ₯Ό λ°ννλ€.week
λ νλμ λν λͺ¨λ κ³ μ ν μ°λ/μ£Ό κ°μ΄ λ΄κΈ΄ listλ₯Ό λ°ννλ©° λͺ¨λ λ μ§λ μμμΌμ΄λ€.day
λ νλμ λν λͺ¨λ κ³ μ ν μ°/μ/μΌ κ°μ΄ λ΄κΈ΄ listλ₯Ό λ°ννλ€.κΈ°λ³Έμ μΌλ‘ μ λ ¬λλ μμλ ASC
(μ€λ¦μ°¨μ)μ΄λ©° order
λ₯Ό μ§μ ν λλ ASC
λλ DESC
μ¬μΌ νλ€.
>>> Entry.objects.dates('pub_date', 'year')
[datetime.date(2005, 1, 1)]
>>> Entry.objects.dates('pub_date', 'month')
[datetime.date(2005, 2, 1), datetime.date(2005, 3, 1)]
>>> Entry.objects.dates('pub_date', 'week')
[datetime.date(2005, 2, 14), datetime.date(2005, 3, 14)]
>>> Entry.objects.dates('pub_date', 'day')
[datetime.date(2005, 2, 20), datetime.date(2005, 3, 20)]
>>> Entry.objects.dates('pub_date', 'day', order='DESC')
[datetime.date(2005, 3, 20), datetime.date(2005, 2, 20)]
>>> Entry.objects.filter(headline__contains='Lennon').dates('pub_date', 'day')
[datetime.date(2005, 3, 20)]
datetimes(field_name, kind, order='ASC', tzinfo=None, is_dst=None)
QuerySet
μ λ΄μ© λ΄μμ νΉμ μ’
λ₯μ μ¬μ© κ°λ₯ν λͺ¨λ λ μ§λ₯Ό λνλ΄λ datetime.datetime
κ°μ²΄ λͺ©λ‘μΌλ‘ νκ°λλ QuerySet
μ 리ν΄νλ€.
field_name
μ λͺ¨λΈμ DateTimeField
μ¬μΌ νλ€. kind
λ year
, month
, week
, day
, hour
, minute
, second
μ΄μΌ νλ€. κ²°κ³Ό λͺ©λ‘μ κ° datetime.datetime
κ°μ²΄λ μ£Όμ΄μ§ μ νμΌλ‘ λ°μ΄ν°λ₯Ό μλΌλΈλ€.
κΈ°λ³Έμ μΌλ‘ μ λ ¬λλ μμλ ASC
(μ€λ¦μ°¨μ)μ΄λ©° order
λ₯Ό μ§μ ν λλ ASC
λλ DESC
μ¬μΌ νλ€.
tzinfo
λ μλ₯΄κΈ° μ μ datetime
μ΄ λ³νλλ μκ°λλ₯Ό μ μνλ€. μ€μ λ‘ μ£Όμ΄μ§ datetime
μ μ¬μ©μ€μΈ μκ°λμ λ°λΌ λ€λ₯Έ ννμ κ°λλ€. μ΄ λ§€κ° λ³μλ datetime.tzinfo
κ°μ²΄μ¬μΌ νλ€. None
μ΄λ©΄ Djangoμ νμ¬ μκ°λλ₯Ό μ¬μ©νλ€. USE_TZ
κ° False
λ©΄ μλ¬΄λ° λ³νκ° μλ€.
is_dst
λ pytz
κ° μλ¨Ένμμ μ¬μ©νλμ§μ λν μ¬λΆλ₯Ό λνλΈλ€. κΈ°λ³Έμ μΌλ‘ (is_dst = None
) pyzt
λ μ΄λ¬ν λ μ§ μκ°μ λν΄ μμΈλ₯Ό λ°μμν¨λ€.
π‘λ°μ΄ν°λ² μ΄μ€μ μκ°λλ₯Ό μ¬μ©νλ
datetime()
datetime()
μ λ°μ΄ν°λ² μ΄μ€μμ μ§μ μκ°λ λ³νμ μννλ€. λ°λΌμ λ°μ΄ν°λ² μ΄μ€λtzinfo.tzname (None)
μ κ°μ ν΄μ ν μ μμ΄μΌ νλ€. λ°λΌμ λ°μ΄ν°λ² μ΄μ€λ λ€μκ³Ό κ°μ μꡬμ¬νμ΄ μΆ©μ‘±λμ΄μΌ νλ€.
- SQLite : μꡬ μ¬νμ΄ μλ€. λ³νμ
Python
μμpytz
λ₯Ό μ¬μ©νμ¬ μνλλ©° μ΄ ν¨ν€μ§λ Djangoλ₯Ό μ€μΉν λ μ΄λ―Έ μ€μΉλμ΄ μλ ν¨ν€μ§μ΄λ€.- PostgreSQL : μꡬμ¬ν μμ (μ°Έμ‘°)
- Oracle : μꡬμ¬ν μμ (μ°Έμ‘°)
- MySQL :
mysql_tzinfo_to_sql
μ μ¬μ©νμ¬ μκ°λ ν μ΄λΈμ κ°μ Έμ¨λ€. (μ°Έκ³ )
none()
none()
μ νΈμΆνλ©΄ κ°μ²΄λ₯Ό λ°ννμ§ μλ 쿼리μ
μ΄ μμ±λκ³ κ²°κ³Όμ μμΈμ€ ν λ μΏΌλ¦¬κ° μ€νλμ§ μλλ€. qs.none()
쿼리μ
μ EmptyQuerySet
μ μΈμ€ν΄μ€κ° λλ€.
>>> Entry.objects.none()
<QuerySet []>
>>> from django.db.models.query import EmptyQuerySet
>>> isinstance(Entry.objects.none(), EmptyQuerySet)
True
all()
νμ¬ QuerySet
(λλ QuerySet
νμ ν΄λμ€)μ 볡μ¬λ³Έμ λ°ννλ€. μ΄λ λͺ¨λΈ κ΄λ¦¬μ λλ QuerySet
μ μ λ¬νκ³ κ²°κ³Όμ λν μΆκ° νν°λ§μ μννλ €λ μν©μμ μ μ©ν μ μλ€. λ κ°μ²΄ λͺ¨λ all()
μ νΈμΆ νλ©΄ μμ
ν QuerySet
μ νμ€νκ² κ°κ²λλ€.
QuerySet
μ΄ νκ° λ λ μΌλ°μ μΌλ‘ κ²°κ³Όλ₯Ό μΊμνλ€. QuerySet
μ΄ νκ° λ μ΄ν λ°μ΄ν°λ² μ΄μ€μ λ°μ΄ν°κ° λ³κ²½λ κ²½μ° μ΄μ μ νκ°λ QuerySet
μμ all()
μ νΈμΆνμ¬ λμΌν 쿼리μ λν μ
λ°μ΄νΈ λ κ²°κ³Όλ₯Ό μ»μ μ μλ€.
union(*other_qs, all=False)
SQLμ UNION
μ μ¬μ©νμ¬ λ μ΄μμ QuerySet
κ²°κ³Όλ₯Ό κ²°ν©νλ€.
>>> qs1.union(qs2, qs3)
UNION μ°μ°μλ κΈ°λ³Έμ μΌλ‘ κ³ μ ν κ°λ§ μ ννλ€. (distinct()
κ° κΈ°λ³Έμ μΌλ‘ μνλ¨.) μ΄ λ μ€λ³΅ κ°μ νμ©νλ €λ©΄ all = True
μΈμλ₯Ό μ¬μ©νλ€.
union()
, intersection()
, difference()
λ μΈμκ° λ€λ₯Έ λͺ¨λΈμ QuerySet
μΈ κ²½μ°μλ 첫λ²μ§Έ QuerySet
μ νμ λͺ¨λΈ μΈμ€ν΄μ€λ₯Ό λ°ννλ€. SELECT
λͺ©λ‘μ΄ λͺ¨λ QuerySet
μμ λμΌνλ©΄ λ€λ₯Έ λͺ¨λΈμ μ λ¬νλ κ²μ΄ μλνλ€. (μ΅μν μ ν, μ νμ΄ λμΌν μμλ©΄ μ΄λ¦μ΄ μ€μνμ§ μλ€.) μ΄λ¬ν κ²½μ° QuerySet
μ μ μ©λ QuerySet
λ©μλμ 첫λ²μ§Έ QuerySet
μ μ΄ μ΄λ¦μ μ¬μ©ν΄μΌ νλ€.
>>> qs1 = Author.objects.values_list('name')
>>> qs2 = Entry.objects.values_list('headline')
>>> qs1.union(qs2).order_by('name')
λν κ²°κ³Ό QuerySetμλ LIMIT
, OFFSET
, COUNT(*)
, ORDER BY
λ° μ΄ μ§μ (μ¬λΌμ΄μ±, count()
, order_by()
, value()
, values_list()
)λ§ νμ©λλ€. λ°μ΄ν°λ² μ΄μ€λ κ²°ν© λ 쿼리μμ νμ©λλ μμ
μ μ νμ λλ€. μλ₯Ό λ€μ΄ λλΆλΆμ λ°μ΄ν°λ² μ΄μ€λ κ²°ν© λ 쿼리μμ LIMIT
λλ OFFSET
μ νμ©νμ§ μλλ€.
intersection(*other_qs)
SQLμ INTERSECT
λ₯Ό μ¬μ©νμ¬ λ μ΄μμ QuerySet
μ κ΅μ§ν©μ λ°ννλ€.
>>> qs1.intersection(qs2, qs3)
intersection()
μ μ νμ¬νμ union()
κ³Ό λμΌνλ€.
difference(*other_qs)
SQLμ EXCEPT
μ°μ°μλ₯Ό μ¬μ©νμ¬ λ μ΄μμ QuerySet
μ μ°¨μ§ν©μ λ°ννλ€.
>>> qs1.difference(qs2, qs3)
difference()
μ μ νμ¬νμ union()
κ³Ό λμΌνλ€.
extra(select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
λλλ‘ Django 쿼리 ꡬ문 λ§μΌλ‘λ 볡μ‘ν WHERE
μ μ μ½κ² ννν μ μλ€. μ΄λ¬ν μν©μ μν΄ Djangoλ extra()QuerySet
νμ μλ₯Ό μ 곡νλ€. μ΄κ²μ QuerySet
μ μν΄ μμ±λ SQLμ νΉμ μ μ μ½μ
νκΈ° μν λ°©λ²μ΄λ€.
π‘μ΄ λ°©λ²μ μ΅νμ μλ¨μΌλ‘ μ¬μ©ν κ²
extra()
λ ν₯ν Djangoμμ μ§μμ μ€λ¨νλ €λ μ€λλ APIμ΄λ€. λ€λ₯Έ 쿼리μ λ©μλλ₯Ό μ¬μ©νμ¬ μΏΌλ¦¬λ₯Ό ννν μ μλ κ²½μ°μλ§ μ¬μ©ν κ²μ κΆμ₯νλ€. Djangoλ λ μ΄μextra()
μ λν λ²κ·Έλ₯Ό κ°μ νκ±°λ μμ νμ§ μλλ€.>>> qs.extra( ... select={'val': "select col from sometable where othercol = %s"}, ... select_params=(someparam,), ... )
μ΄κ²μ
RawSQL
μ μ¬μ©νλ λ€μκ³Ό λμΌνλ€.>>> qs.annotate(val=RawSQL("select col from sometable where othercol = %s", (someparam,)))
RawSQL
μ¬μ©μ μ£Όμ μ΄μ μ νμν κ²½μ°output_field
λ₯Ό μ€μ ν μ μλ€λ κ²μ΄λ€. μ£Όλ λ¨μ μ raw SQLμμ 쿼리μ μ μΌλΆ ν μ΄λΈ λ³μΉμ μ°Έμ‘°νλ©΄ Djangoκ° ν΄λΉ λ³μΉμ λ³κ²½ν μ μλ€λ κ²μ΄λ€. (μ: 쿼리μ μ΄ λ λ€λ₯Έ 쿼리μμ μλΈμΏΌλ¦¬λ‘ μ¬μ©λλ κ²½μ°)
β οΈ SQL injectionμ μ·¨μ½ν
extra()
extra()
λ₯Ό μ¬μ©ν λλ SQL injection곡격μ λ§€μ° μ·¨μ½νλ―λ‘ μ¬μ©μκ° λ§€κ° λ³μλ₯Ό μ¬μ©νμ¬ μ μ΄ν μ μλ λͺ¨λ λ§€κ° λ³μλ₯Ό μ΄μ€μΌμ΄νν΄μΌ νλ€.λν SQLλ¬Έμμ΄μμ μ리 νμμλ₯Ό μΈμ©νμ§ μμμΌ νλ€. μ΄ μμ λ
%s
μ£Όμμ''
μ¬μ©μΌλ‘ μ΄ν΄ SQL injectionμ μ·¨μ½νλ€.SELECT col FROM sometable WHERE othercol = '%s' # unsafe!
Djangoμ SQL injection λ³΄νΈ μλ λ°©μμ λν΄μ μ¬κΈ°λ₯Ό μ°Έκ³ νλλ‘ νμ.
defer(*fields)
μΌλΆ 볡μ‘ν λ°μ΄ν° λͺ¨λΈλ§μμλ λͺ¨λΈμ λ§μ νλκ° ν¬ν¨λλ©°, κ·Έμ€ μΌλΆμλ λ§μ λ°μ΄ν°(ex. TextField
)κ° ν¬ν¨λ μ μκ±°λ Python κ°μ²΄λ‘ λ³ννκΈ° μν΄ λ¬΄κ±°μ΄ μ²λ¦¬κ° νμν μ μλ€. λ°μ΄ν°λ₯Ό μ²μ κ°μ Έμ¬ λ νΉμ νλκ° νμνμ§ μ¬λΆλ₯Ό μ μ μλ μν©μμ 쿼리μ
μ κ²°κ³Όλ₯Ό μ¬μ©νλ κ²½μ° Djangoμ λ°μ΄ν°λ² μ΄μ€μμ κ²μνμ§ μλλ‘ μ§μ ν μ μλ€.
μ΄λ λ‘λ λμ§ μλλ‘ νλμ΄λ¦μ defer()
μ μ λ¬νμ¬ μνλλ€.
# bodyμ headlineνλλ₯Ό λͺ¨λ κ²μμμ μ μΈ μν¨λ€.
Entry.objects.defer("body").filter(rating=5).defer("headline")
μ§μ°λ μ§ν©μ νλκ° μΆκ°λλ μμλ μ€μνμ§ μλ€. μ΄λ―Έ κ²μνμ§ μλλ‘ μ κ±°λ νλ μ΄λ¦μΌλ‘ defer()
λ₯Ό νΈμΆνλ κ²μ ν΄κ° λμ§ μλλ€. (νλλ μ¬μ μ΄ κ²μμμ μ μΈλμ΄ μλ€.)
double underscore (__
)λ₯Ό μ¬μ©νμ¬ κ΄λ ¨ νλλ₯Ό ꡬλΆνμ¬ κ΄λ ¨λ λͺ¨λΈμ νλλ₯Ό κ²μμμ μ μΈμν¬ μ μλ€.(select_related
λ₯Ό ν΅ν΄ 쿼리μ
μ κ°μ Έμ¬ κ²½μ°)
Blog.objects.select_related().defer("entry__headline", "entry__body")
κ²μμμ μ μΈλ νλ μ§ν©μ ν΄μ νλ €λ©΄ defer()
μ λ§€κ°λ³μλ‘ None
μ μ λ¬νλ€.
# λͺ¨λ νλλ₯Ό κ°μ Έμ¨λ€.
my_queryset.defer(None)
λͺ¨λΈμ μΌλΆ νλλ κ²μμμ μ μΈλμ§ μλλ€. νΉν Primary Keyλ κ²μμμ μ μΈ μν¬ μ μλ€. select_related()
λ₯Ό μ¬μ©νμ¬ κ΄λ ¨ λͺ¨λΈμ κ²μνλ κ²½μ° κΈ°λ³Έ λͺ¨λΈμμ κ΄λ ¨λͺ¨λΈλ‘ μ°κ²°λλ νλλ₯Ό κ²μμμ μ μΈμν€λ©΄ μλλ€. λ§μ½ κ²μμμ μ μΈλλ€λ©΄ μλ¬κ° λ°μνλ€.
κ²μμμ μ μΈλ νλκ° μλ μΈμ€ν΄μ€μ λν΄ save()
λ₯Ό νΈμΆνλ©΄ κ²μλ νλλ§ μ μ₯λλ€.
only(*fields)
only()
λ©μλλ defer()
μ λ°λλλ κ°λ
μ΄λ€. λͺ¨λΈμ κ²μν λ λ°λμ ν¬ν¨λμ΄μΌ νλ νλλ₯Ό μ¬μ©νμ¬ νΈμΆνλ€. κ±°μ λͺ¨λ νλλ₯Ό κ²μμμ μ μΈν΄μΌ νλ λͺ¨λΈμ΄ μλ κ²½μ° only()
λ₯Ό μ¬μ©νλ©΄ μ½λκ° λ κ°κ²°ν΄ μ§ μ μλ€.
μ΄λ¦, λμ΄, μμ μ κΈ°κ° μλ λͺ¨λΈμ΄ μλ€κ³ κ°μ νκ³ λ€μ λ κ°μ 쿼리μ μ κ²μλλ νλμ μ νμ μμ΄μ λμΌνλ€.
Person.objects.defer("age", "biography")
Person.objects.only("name")
only()
λ₯Ό νΈμΆ ν λλ§λ€ μ¦μ λ‘λν νλ μΈνΈλ₯Ό λ체 νλ€. λ©μλ μ΄λ¦μ mnemonic
μ΄λ€. ν΄λΉ νλ λ§ μ¦μ λ‘λλλ©° λλ¨Έμ§λ κ²μμμ μ μΈλλ€. λ°λΌμ only()
λ₯Ό μ°μμ μΌλ‘ νΈμΆνλ©΄ λ§μ§λ§ νλλ§ κ³ λ €λλ€.
# μ΅μ’
κ²°κ³Όλ `headline`μ μ μΈν λͺ¨λ κ²μ΄ κ²μμμ μ μΈ λλ€.
Entry.objects.only("headline", "body").defer("body")
# μ΅μ’
κ²°κ³Όλ `headline`κ³Ό `body`λ₯Ό μ¦μ λ‘λνλ€. (only()λ κΈ°μ‘΄ νλ μΈνΈλ₯Ό λ체νλ€.)
Entry.objects.defer("body").only("headline", "body")
defer()
μ λͺ¨λ μ£Όμ μ¬νμ only()
μλ μ μ©λλ€. λ€λ₯Έ μ΅μ
μ λ€ μ¬μ©ν νμλ§ μ‘°μ¬μ€λ½κ² μ¬μ©ν΄μΌ νλ€.only()
λ₯Ό μ¬μ©νκ³ select_related()
λ₯Ό μ¬μ©νμ¬ μμ² λ νλλ₯Ό μλ΅νλ κ²λ μλ¬κ° λ°μνλ€.
κ²μμμ μ μΈλ νλκ° μλ μΈμ€ν΄μ€μ λν΄ save()
λ₯Ό νΈμΆνλ©΄ κ²μλ νλλ§ μ μ₯λλ€.
using(alias)
μ΄ λ©μλλ λ μ΄μμ λ°μ΄ν°λ² μ΄μ€λ₯Ό μ¬μ©νλ κ²½μ° μΏΌλ¦¬μ
μ΄ νκ° λ λ°μ΄ν°λ² μ΄μ€λ₯Ό μ μ΄νκΈ° μν κ²μ΄λ€. μ΄ λ©μλμ λ§€κ°λ³μλ DATABASES
μ μ μλ λ°μ΄ν°λ² μ΄μ€ λ³λͺ
μ΄λ€.
# 'default'λΌκ³ μ§μ λ λ°μ΄ν°λ² μ΄μ€λ₯Ό μ¬μ©νλ€.
>>> Entry.objects.all()
# 'backup'λΌκ³ μ§μ λ λ°μ΄ν°λ² μ΄μ€λ₯Ό μ¬μ©νλ€.
>>> Entry.objects.using('backup')
select_for_update(nowait=False, skip_locked=False, of=())
νΈλμμ
μ΄ λλ λκΉμ§ νμ λ½μ κ±Έκ³ μ§μλλ λ°μ΄ν°λ² μ΄μ€μμ SELECT ... FOR UPDATE
SQLλ¬Έμ μμ±νλ 쿼리μ
μ λ°ννλ€.
from django.db import transaction
entries = Entry.objects.select_for_update().filter(author=request.user)
with transaction.atomic():
for entry in entries:
...
쿼리μ μ νκ° λ λ (μ΄ κ²½μ° νλͺ©μ νλͺ©μ λν΄) μΌμΉνλ λͺ¨λ νλͺ©μ νΈλμμ λΈλ‘μ΄ λλ λκΉμ§ λ½μ΄ κ±Έλ¦°λ€. μ¦, λ€λ₯Έ νΈλμμ μ΄ ν΄λΉ νλͺ©μ λν λ½μ λ³κ²½νκ±°λ νλνμ§ λͺ»νλλ‘ νλ€.
μΌλ°μ μΌλ‘ λ€λ₯Έ νΈλμμ
μ΄ μ νν ν μ€μ νλμ λν΄ μ΄λ―Έ λ½μ΄ κ±Έλ¦° κ²½μ° λ½μ΄ ν΄μ λ λ κΉμ§ μΏΌλ¦¬κ° μ°¨λ¨λλ€. μ΄κ²μ΄ μνλ λμμ΄ μλ κ²½μ° select_for_update(nowait = True)
λ₯Ό νΈμΆνλ€. μ΄λ κ²νλ©΄ νΈμΆμ΄ μ°¨λ¨λμ§ μλλ€ μΆ©λνλ λ½μ΄ μ΄λ―Έ λ€λ₯Έ νΈλμμ
μ μν΄ νλ λ κ²½μ° μΏΌλ¦¬μ
μ΄ νκ° λ λ λ°μ΄ν°λ² μ΄μ€ μλ¬κ° λ°μνλ€. λμ select_for_update(skip_locked = True)
λ₯Ό μ¬μ©νμ¬ λ½μ΄ κ±Έλ¦° νμ 무μν μλ μλ€. nowait
κ³Ό skip_locked
λ μνΈ λ°°νμ μ΄λ©° λ μ΅μ
μ λͺ¨λ νμ±ν ν μνμμ select_for_update()
λ₯Ό νΈμΆνλ©΄ ValueError
κ° λ°μνλ€.
κΈ°λ³Έμ μΌλ‘ select_for_update()
λ 쿼리μμ μ νν λͺ¨λ νμ λ½μ 건λ€. μλ₯Ό λ€μ΄ select_related()
μ μ§μ λ κ΄λ ¨ κ°μ²΄μ νμ 쿼리 μ
λͺ¨λΈμ νκ³Ό ν¨κ» μ κΈ΄λ€. μνμ§ μλ κ²½μ° select_related()
μ λμΌν νλ ꡬ문μ μ¬μ©νμ¬ select_for_update(of = (...))
λ₯Ό ν΅ν΄ λ½μ κ±Έλ €λ κ΄λ ¨ κ°μ²΄λ₯Ό μ§μ νλ€. κ²μμ΄ μΈνΈμ λͺ¨λΈμ μ°Έμ‘°νλ €λ©΄ self
λ₯Ό μ¬μ©νλ€.
π‘
select_for_update(of=(...))
μμ μμ λͺ¨λΈ λ½ κ±ΈκΈ°λ€μ€ ν μ΄λΈ μμμ μ¬μ©ν λ μμ λͺ¨λΈμ λ½μ κ±Έλ €λ©΄
of
μΈμμ μμ λ§ν¬ νλ (κΈ°λ³Έμ μΌλ‘<parent_model_name>_ptr
)λ₯Ό μ§μ ν΄μΌ νλ€. μλ₯Ό λ€λ©΄Restaurant.objects.select_for_update(of=('self', 'place_ptr'))
nullable
κ΄κ³μλ select_for_update()
λ₯Ό μ¬μ©ν μ μλ€.
>>> Person.objects.select_related('hometown').select_for_update()
Traceback (most recent call last):
...
django.db.utils.NotSupportedError: FOR UPDATE cannot be applied to the nullable side of an outer join
μ΄λ¬ν μ νμ ννΌνκΈ° μν΄ null
μ΄ νμ μλ κ²½μ° null
κ°μ²΄λ₯Ό μ μΈ μν¬ μ μλ€.
>>> Person.objects.select_related('hometown').select_for_update().exclude(hometown=None)
<QuerySet [<Person: ...)>, ...]>
νμ¬ PostgreSQL, Oracle, MySQLλ°μ΄ν°λ² μ΄μ€λ select_for_update()
λ₯Ό μ§μνλ€. κ·Έλ¬λ MariaDB 10.3+λ nowait
λ§ μ§μλλ©° MySQL 8.0.1+λ nowait
λ° skip_locked
λ₯Ό μ§μνλ€. MySQLκ³Ό MariaDBλ of
μΈμλ₯Ό μ§μνμ§ μλλ€.
MySQLκ³Ό κ°μ΄ μ΄λ¬ν μ΅μ
μ μ§μνμ§ μλ λ°μ΄ν°λ² μ΄μ€λ₯Ό μ¬μ©νμ¬ nowait=True, skip_locked = True
λλ select_for_update(of=(...))
λ₯Ό μ λ¬νλ©΄ NotSupportedError
κ° λ°μνλ€.
SELECT ... FOR UPDATE
λ₯Ό μ§μνλ λ°μ΄ν°λ² μ΄μ€μ μλ μ»€λ° λͺ¨λμμ select_for_update()
λ₯Ό μ¬μ©νμ¬ μΏΌλ¦¬μΈνΈλ₯Ό νκ°νλ κ²μ μ΄ κ²½μ° νμ λ½μ΄ κ±Έλ¦¬μ§ μκΈ° λλ¬Έμ TransactionManagementError
κ° λ°μνλ€. λ§μ½ μλ¬κ° λ°μνμ§ μκ² νμ©νλ€λ©΄ νΈλμμ
μΈλΆμ νΈλμμ
μμ μ€ν λ κ²μΌλ‘ μμλλ μ½λλ₯Ό νΈμΆνμ¬ λ°μ΄ν° μμμ΄ μ½κ² λ°μν μ μλ€.
SELECT ... FOR UPDATE
λ₯Ό μ§μνμ§ μλ λ°μ΄ν°λ² μ΄μ€ (ex. SQLite)μμ select_for_update()
λ₯Ό μ¬μ©νλ©΄ ν¨κ³Όκ° μλ€. SELECT ... FOR UPDATE
λ 쿼리μ μΆκ°λμ§ μμΌλ©° μλ μ»€λ° λͺ¨λμμ select_for_update()
λ₯Ό μ¬μ©νλ©΄ μ€λ₯κ° λ°μνμ§ μλλ€.
β οΈ TestCaseμμ
select_for_update()
μ¬μ©μ μ£Όμ μ¬ν
select_for_update()
λ μΌλ°μ μΌλ‘ μλ μ»€λ° λͺ¨λμμ μ€ν¨νμ§λ§ TestCaseλ νΈλμμ μ κ° ν μ€νΈλ₯Ό μλμΌλ‘ λννλ―λ‘atomic()
λΈλ‘ μΈλΆμμλ TestCaseμμselect_for_update()
λ₯Ό νΈμΆνλ©΄TransactionManagementError
λ₯Ό λ°μμν€μ§ μκ³ (μλ§λ μκΈ°μΉ μκ²) ν΅κ³Όλλ€.select_for_update()
λ₯Ό μ λλ‘ ν μ€νΈ νλ €λ©΄TransactionTestCase
λ₯Ό μ¬μ©ν΄μΌ νλ€.
π‘μ§μλμ§ μλ νν : Window function
select_for_update()
PostgreSQLμ Window function expressionμ μ§μνμ§ μλλ€.
raw(raw_query, params=None, translations=None)
raw SQL 쿼리λ₯Ό λ°μμ μ€ννκ³ django.db.models.query.RawQuerySet
μΈμ€ν΄μ€λ₯Ό λ°ννλ€. μ΄ RawQuerySet
μΈμ€ν΄μ€λ κ°μ²΄ μΈμ€ν΄μ€λ₯Ό μ 곡νκΈ° μν΄ μΌλ° QuerySet
μ²λΌ λ°λ³΅ λ μ μλ€.
μμΈν λ΄μ©μ μ¬κΈ°λ₯Ό μ°Έμ‘°νλ€.
β οΈ
raw()
μ¬μ©μ μ£Όμ μ¬ν
raw()
λ νμ μ 쿼리λ₯Ό νΈλ¦¬κ±°νκ³ μ΄μ νν°λ§μ κ³ λ €νμ§ μλλ€. λ°λΌμ μΌλ°μ μΌλ‘ Manager λλ μλ‘μ΄ μΏΌλ¦¬μ μΈμ€ν΄μ€μμ νΈμΆν΄μΌ νλ€.