#30653: Annotate a whole ORM object with Subquery instead of just a column
-------------------------------------+-------------------------------------
Reporter: Ivaylo | Owner: Ivo Donchev
Donchev |
Type: New | Status: assigned
feature |
Component: Database | Version: 2.2
layer (models, ORM) |
Severity: Normal | Keywords:
Triage Stage: | Has patch: 0
Unreviewed |
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
-------------------------------------+-------------------------------------
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
--
Ticket URL: <https://code.djangoproject.com/ticket/30653>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/054.c582ecbb0b281feccd4198e1b0108d96%40djangoproject.com.