Django
쿼리 세트
수색…
소개
Queryset
은 근본적으로 데이터베이스 쿼리를 컴파일하여 Model
에서 파생 된 객체의 목록입니다.
독립 실행 형 모델에 대한 간단한 쿼리
다음은 몇 가지 테스트 쿼리를 실행하는 데 사용할 간단한 모델입니다.
class MyModel(models.Model):
name = models.CharField(max_length=10)
model_num = models.IntegerField()
flag = models.NullBooleanField(default=False)
id / pk가 4 인 단일 모델 객체 가져 오기 :
(ID가 4 인 항목이 없거나 둘 이상의 항목이있는 경우 예외가 발생합니다.)
MyModel.objects.get(pk=4)
모든 모델 객체 :
MyModel.objects.all()
flag
가 True
설정된 모델 개체 :
MyModel.objects.filter(flag=True)
model_num
이 25보다 큰 모델 객체 :
MyModel.objects.filter(model_num__gt=25)
name
이 "Cheap Item"이고 flag
가 False
설정된 모델 개체 :
MyModel.objects.filter(name="Cheap Item", flag=False)
특정 문자열에 대한 간단한 검색 name
모델 (대소 문자 구분) :
MyModel.objects.filter(name__contains="ch")
특정 문자열에 대한 간단한 검색 name
모델 (대소 문자 구분 안 함) :
MyModel.objects.filter(name__icontains="ch")
Q 개체를 사용한 고급 쿼리
주어진 모델 :
class MyModel(models.Model):
name = models.CharField(max_length=10)
model_num = models.IntegerField()
flag = models.NullBooleanField(default=False)
Q
개체를 사용하여 조회 쿼리에서 AND
, OR
조건을 만들 수 있습니다. 예를 들어 flag=True
또는 model_num>15
모든 개체를 model_num>15
.
from django.db.models import Q
MyModel.objects.filter(Q(flag=True) | Q(model_num__gt=15))
위의 내용은 AND와 마찬가지로 WHERE flag=True OR model_num > 15
변환됩니다.
MyModel.objects.filter(Q(flag=True) & Q(model_num__gt=15))
Q
객체를 사용하면 ~
사용하여 NOT 쿼리를 작성할 수도 있습니다. flag=False
model_num!=15
인 모든 객체를 얻고 싶다면 다음 과 model_num!=15
하면됩니다.
MyModel.objects.filter(Q(flag=True) & ~Q(model_num=15))
Q 객체와의 "정상"파라미터를 사용하는 경우 filter()
다음 Q
개체는 먼저 와야. 다음 쿼리는 ( flag
가 True
또는 15
보다 큰 모델 번호로 설정된) 모델과 "H"로 시작하는 모델을 검색합니다.
from django.db.models import Q
MyModel.objects.filter(Q(flag=True) | Q(model_num__gt=15), name__startswith="H")
참고 : Q
개체는 filter
, exclude
, get
과 같은 키워드 인수를 사용하는 조회 함수와 함께 사용할 수 있습니다. get
과 함께 사용할 때 하나의 객체 만 반환하거나 MultipleObjectsReturned
예외가 발생하는지 확인하십시오.
ManyToManyField에서 쿼리 수 줄입니다 (n + 1 문제).
문제
# models.py:
class Library(models.Model):
name = models.CharField(max_length=100)
books = models.ManyToManyField(Book)
class Book(models.Model):
title = models.CharField(max_length=100)
# views.py
def myview(request):
# Query the database.
libraries = Library.objects.all()
# Query the database on each iteration (len(author) times)
# if there is 100 librairies, there will have 100 queries plus the initial query
for library in libraries:
books = library.books.all()
books[0].title
# ...
# total : 101 queries
해결책
사용하십시오 prefetch_related
에 ManyToManyField
당신이 나중에있는 필드에 액세스 할 필요가 있음을 알고있는 경우 ManyToManyField
필드.
# views.py
def myview(request):
# Query the database.
libraries = Library.objects.prefetch_related('books').all()
# Does not query the database again, since `books` is pre-populated
for library in libraries:
books = library.books.all()
books[0].title
# ...
# total : 2 queries - 1 for libraries, 1 for books
prefetch_related
는 조회 필드에도 사용할 수 있습니다.
# models.py:
class User(models.Model):
name = models.CharField(max_length=100)
class Library(models.Model):
name = models.CharField(max_length=100)
books = models.ManyToManyField(Book)
class Book(models.Model):
title = models.CharField(max_length=100)
readers = models.ManyToManyField(User)
# views.py
def myview(request):
# Query the database.
libraries = Library.objects.prefetch_related('books', 'books__readers').all()
# Does not query the database again, since `books` and `readers` is pre-populated
for library in libraries:
for book in library.books.all():
for user in book.readers.all():
user.name
# ...
# total : 3 queries - 1 for libraries, 1 for books, 1 for readers
그러나 일단 쿼리 세트가 실행되면 데이터베이스를 다시 찾지 않고 가져온 데이터를 변경할 수 없습니다. 다음은 예를 들어 추가 쿼리를 실행합니다.
# views.py
def myview(request):
# Query the database.
libraries = Library.objects.prefetch_related('books').all()
for library in libraries:
for book in library.books.filter(title__contains="Django"):
print(book.name)
다음은 Django 1.7에서 소개 된 Prefetch
객체를 사용하여 최적화 할 수 있습니다.
from django.db.models import Prefetch
# views.py
def myview(request):
# Query the database.
libraries = Library.objects.prefetch_related(
Prefetch('books', queryset=Book.objects.filter(title__contains="Django")
).all()
for library in libraries:
for book in library.books.all():
print(book.name) # Will print only books containing Django for each library
외래 키 필드에서 쿼리 수 줄입니다 (n + 1 문제).
문제
장고 querysets은 게으른 방식으로 평가됩니다. 예 :
# models.py:
class Author(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
author = models.ForeignKey(Author, related_name='books')
title = models.CharField(max_length=100)
# views.py
def myview(request):
# Query the database
books = Book.objects.all()
for book in books:
# Query the database on each iteration to get author (len(books) times)
# if there is 100 books, there will have 100 queries plus the initial query
book.author
# ...
# total : 101 queries
위의 코드는 django가 데이터베이스에 각 책의 저자를 쿼리하도록합니다. 이는 비효율적이며 단일 쿼리 만 갖는 것이 좋습니다.
해결책
나중에 ForeignKey
필드에 액세스해야하는 경우 ForeignKey
select_related
를 사용하십시오.
# views.py
def myview(request):
# Query the database.
books = Books.objects.select_related('author').all()
for book in books:
# Does not query the database again, since `author` is pre-populated
book.author
# ...
# total : 1 query
select_related
는 조회 필드에도 사용할 수 있습니다.
# models.py:
class AuthorProfile(models.Model):
city = models.CharField(max_length=100)
class Author(models.Model):
name = models.CharField(max_length=100)
profile = models.OneToOneField(AuthorProfile)
class Book(models.Model):
author = models.ForeignKey(Author, related_name='books')
title = models.CharField(max_length=100)
# views.py
def myview(request):
books = Book.objects.select_related('author')\
.select_related('author__profile').all()
for book in books:
# Does not query database
book.author.name
# or
book.author.profile.city
# ...
# total : 1 query
장고 queryset에 대한 SQL 가져 오기
queryset의 query
속성은 SQL에 해당하는 쿼리 구문을 제공합니다.
>>> queryset = MyModel.objects.all()
>>> print(queryset.query)
SELECT "myapp_mymodel"."id", ... FROM "myapp_mymodel"
경고:
이 출력은 디버깅 목적으로 만 사용해야합니다. 생성 된 쿼리는 백엔드와 관련이 없습니다. 따라서 매개 변수는 올바르게 인용되지 않으므로 SQL 인젝션에 취약하게되고 데이터베이스 백엔드에서 쿼리가 실행되지 않을 수도 있습니다.
QuerySet에서 처음이자 마지막 레코드 얻기
첫 번째 객체를 얻으려면 :
MyModel.objects.first()
마지막 객체 가져 오기 :
MyModel.objects.last()
필터 사용 첫 번째 개체 :
MyModel.objects.filter(name='simple').first()
필터 사용 마지막 객체 :
MyModel.objects.filter(name='simple').last()
F 객체를 사용한 고급 쿼리
F () 객체는 모델 필드 또는 주석 된 열의 값을 나타냅니다. 실제로 데이터베이스에서 파이썬 메모리로 가져 오지 않고 모델 필드 값을 참조하고이를 사용하여 데이터베이스 작업을 수행 할 수 있습니다. - F () 표현식
쿼리에서 다른 필드의 값을 참조해야 할 때마다 F()
개체를 사용하는 것이 적합합니다. 그 자체로 F()
객체는 아무 의미도 없으며 쿼리 세트 외부에서 호출 될 수 없으며 호출되어서는 안됩니다. 같은 쿼리 세트에서 필드의 값을 참조하는 데 사용됩니다.
예를 들어, 주어진 모델 ...
SomeModel(models.Model):
...
some_field = models.IntegerField()
... 사용자는 F()
사용하여 필터링하는 동안 id
필드의 값 을 참조 하여 some_field
값이 해당 id
두 배인 객체를 쿼리 할 수 있습니다.
SomeModel.objects.filter(some_field=F('id') * 2)
F('id')
는 동일한 인스턴스의 id
값을 참조하기 id
. Django는이를 사용하여 해당 SQL 문을 생성합니다. 이 경우에는 다음과 매우 유사합니다.
SELECT * FROM some_app_some_model
WHERE some_field = ((id * 2))
F()
표현식을 사용하지 않으면 원시 SQL 또는 파이썬에서 필터링 (이는 많은 오브젝트가있는 경우 특히 성능이 저하됨)으로 수행됩니다.
참고 문헌 :
F()
클래스 정의에서 :
기존 쿼리 개체에 대한 참조를 확인할 수있는 개체입니다. - F 소스
참고 :이 예제는 TinyInstance의 동의하에 위에 나열된 답변에서 게시되었습니다.