Opened 5 years ago
Closed 5 years ago
#30653 closed New feature (wontfix)
Annotate a whole ORM object with Subquery instead of just a column.
Reported by: | Ivaylo Donchev | Owned by: | Ivo Donchev |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | dev |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
It would be very useful to have a QuerySet method that annotates whole ORM object instead of separate columns.
Use cases
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) # :)
- 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
Change History (1)
comment:1 by , 5 years ago
Resolution: | → wontfix |
---|---|
Status: | assigned → closed |
Summary: | Annotate a whole ORM object with Subquery instead of just a column → Annotate a whole ORM object with Subquery instead of just a column. |
Version: | 2.2 → master |
Note:
See TracTickets
for help on using tickets.
Thanks for this ticket, however you can user Prefetch() to prefetch related objects with a custom queryset. I don't think that a new API is necessary, e.g.: