﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
30653	Annotate a whole ORM object with Subquery instead of just a column.	Ivaylo Donchev	Ivo Donchev	"It would be very useful to have a QuerySet method that annotates whole ORM object instead of separate columns.


== Use cases

1. `select_related` does not support using annotations of selected object. Example:

{{{
class User(Model):
    first_name = CharField(max_length=20)
    last_name = CharField(max_length=20)

    objects = UserQueySet.as_manager()


class UserQuerySet(QuerySet):
    def with_annotated_full_name(self):
        return self.annotate(
            full_name=ExpressionWrapper(
                expression=OuterRef('first_name') + Value(' ') + OuterRef('last_name')
                output_field=CharField()
            )
        )


class Car(Model):
    brand = CharField(max_length=20)
    owner = ForeignKey(User)
    

users_with_annotated_full_names = User.objects.with_annotated_full_name()  # each user will have `.full_name`
cars_with_users = Car.objects.select_realted('user')  # No way to get the `user.full_name` annotation :(


# With annotated object it'll look like:
cars_with_users_with_annotated_full_name = Car.objects.annotate_object(
    field_name='owner_with_annotated_full_name',
    queryset=User.objects.filter(id=OuterRef('owner'))[:1]
)



for car in cars_with_users_with_annotated_full_name:
    print(car.user.full_name)  # :)
}}}


2. You need to make a query for every object to get some non-related object. Example:

{{{
class Teacher(Model):
    name = CharField(max_length=20)
    grade = IntegerField()


class Student(Model):
    name = CharField(max_length=20)
    grade = IntegerField()


def get_students_with_their_teacher():
    # Students must be ditributed between 3 teachers according to `grade` so each student should know it's teacher
    return Student.objects.annotate_object(
        field_name='teacher',
        queryset=Teacher.objects.filter(grade=OuterRef('grade'))[:1]
    )

students = get_students_with_their_teacher()

for student in students:
    print(student.teacher)  # == Teacher.objects.get(grade=...) but not making an extra query
}}}


Having this as additional method in the ORM may be really useful when you want to preserve the declarative syntax of Django ORM when using List APIs/Views and avoid additional methods that attaches objects dynamically and mutates the ORM objects"	New feature	closed	Database layer (models, ORM)	dev	Normal	wontfix			Unreviewed	0	0	0	0	0	0
