수색…


소개

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()

flagTrue 설정된 모델 개체 :

MyModel.objects.filter(flag=True)

model_num 이 25보다 큰 모델 객체 :

MyModel.objects.filter(model_num__gt=25)

name 이 "Cheap Item"이고 flagFalse 설정된 모델 개체 :

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 개체는 먼저 와야. 다음 쿼리는 ( flagTrue 또는 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_relatedManyToManyField 당신이 나중에있는 필드에 액세스 할 필요가 있음을 알고있는 경우 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의 동의하에 위에 나열된 답변에서 게시되었습니다.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow