РЕПЕТИТОР математика физика информатика
Для школьников и студентов. Подтягивание пробелов. ЦЭ, ЦТ, ОГЭ, ЕГЭ.
Идет набор на ЛЕТО. Жмите для подробностей:)
158 of 818 menu

Класс OuterRef

Класс OuterRef применяется в сочетании с классом Subquery для построения подзапросов, которые ссылаются на поля внешнего запроса. Это позволяет выполнять связанные подзапросы без использования дополнительных соединений таблиц. Класс принимает один обязательный аргумент - имя поля, на которое нужно сослаться.

Основное преимущество OuterRef заключается в том, что он позволяет строить динамические подзапросы, где условия фильтрации зависят от текущей строки внешнего запроса. Это мощный инструмент для создания сложных агрегаций и фильтраций, которые невозможно выполнить с помощью стандартных методов annotate и aggregate.

Синтаксис

OuterRef(field_name)

Модели для примеров

Для демонстрации работы класса OuterRef используем следующие модели:

from django.db import models class Author(models.Model): name = models.CharField(max_length=100) age = models.IntegerField() def __str__(self): return self.name class Book(models.Model): title = models.CharField(max_length=200) author = models.ForeignKey(Author, on_delete=models.CASCADE) price = models.DecimalField(max_digits=10, decimal_places=2) pages = models.IntegerField() published = models.BooleanField(default=True) def __str__(self): return self.title

Пример . С аннотацией

Давайте аннотируем каждого автора средней ценой его книг с помощью подзапроса с OuterRef:

from django.db.models import OuterRef, Subquery, Avg from myapp.models import Author, Book # Подзапрос для вычисления средней цены книг каждого автора avg_price_subquery = Book.objects.filter( author=OuterRef('pk') ).values('author').annotate( avg_price=Avg('price') ).values('avg_price') authors = Author.objects.annotate( avg_book_price=Subquery(avg_price_subquery) ) for author in authors: print(f"{author.name}: {author.avg_book_price}")

Результат выполнения кода:

"John Doe: 25.50" "Jane Smith: 30.75" "Bob Johnson: 22.33"

Пример . С фильтрацией

Используем OuterRef для фильтрации авторов, у которых есть хотя бы одна книга с ценой выше средней:

from django.db.models import OuterRef, Subquery, Exists, Avg from myapp.models import Author, Book # Подзапрос для проверки наличия книг с ценой выше средней expensive_books_subquery = Book.objects.filter( author=OuterRef('pk'), price__gt=Book.objects.filter( author=OuterRef('pk') ).values('author').annotate( avg_price=Avg('price') ).values('avg_price') ) authors = Author.objects.filter( Exists(expensive_books_subquery) ) for author in authors: print(author.name)

Результат выполнения кода:

"John Doe" "Jane Smith"

Пример . С подсчетом связанных записей

Вычислим для каждой книги разницу между её ценой и средней ценой книг этого автора:

from django.db.models import OuterRef, Subquery, Avg, F from myapp.models import Book # Подзапрос для получения средней цены книг автора author_avg_price = Book.objects.filter( author=OuterRef('author') ).values('author').annotate( avg_price=Avg('price') ).values('avg_price') books = Book.objects.annotate( price_difference=F('price') - Subquery(author_avg_price) ) for book in books: print(f"{book.title}: {book.price_difference}")

Результат выполнения кода:

"Book 1: 5.50" "Book 2: -2.25" "Book 3: 10.75" "Book 4: -1.50"

Смотрите также

  • класс Subquery,
    который используется для создания подзапросов
  • класс Exists,
    который проверяет существование записей в подзапросе
  • класс F,
    который позволяет ссылаться на поля модели в запросах
  • метод annotate,
    который добавляет вычисляемые поля к QuerySet
Мы используем cookie для работы сайта, аналитики и персонализации. Обработка данных происходит согласно Политике конфиденциальности.
принять все настроить отклонить