Opened 11 years ago
Last modified 10 years ago
#23854 new New feature
Add custom SelectRelated classes
| Reported by: | Anssi Kääriäinen | Owned by: | nobody |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | dev |
| Severity: | Normal | Keywords: | |
| Cc: | Simon Charette | Triage Stage: | Accepted |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
The idea is similar to the Prefetch object. One could for example do:
qs = Post.objects.select_related(latest_comment=Latest('comments', by='post_date'))
where the models are Post, and a list of comments to that post with related_name='comments'. Django would then generate a query to fetch the latest comment for each post. The SQL generated could be for example:
SELECT post.*, latest_comment.*
FROM post
LEFT JOIN (select author.*
from author
where author.post_date = (select max(post_date) from author inner_author where inner_author.post_id = author.post_id
) latest_comment ON latest_comment.post_id = post.id
It should also be possible to do qs.order_by('latest_comment__post_date') and other query operations on the select_related "annotation".
To implement this the following things are needed:
- necessary alterations to select_related() call
- a way to do custom subselect joins (see #23853)
- addition of "model annotations" to the query (so that resolve_ref() will know to resolve latest_comment to the custom select_related)
- substantial changes to the way select_related() resolvation works in compiler and QuerySet classes
Change History (6)
comment:1 by , 11 years ago
| Triage Stage: | Unreviewed → Accepted |
|---|
comment:2 by , 11 years ago
comment:3 by , 11 years ago
The problem with using annotate() is that is is used to annotate a single value to the model, and in addition annotate works only for the main model of the query, that is you can't annotate on some already select_related() model. While this can be a bit limiting in some cases (say, two "latest related" annotations in a row), it isn't that big of a problem.
Another solution is a new method, for example annotate_related().
The good thing about this is that there is still plenty of time to discuss the API before the ORM can actually support "latest related" queries :)
comment:4 by , 10 years ago
| Cc: | added |
|---|
comment:5 by , 10 years ago
See #25403 for a related or duplicate issue; in particular comment 4. If the solution for this ticket doesn't address that, please reopen that ticket.
comment:6 by , 10 years ago
Another use case for custom select related: selecting a specific item of a m2m relation with a through model.
class Item(Model):
# stuff here
class Group(Model):
items = ManyToManyField(Item, through='GroupItem')
class GroupItem(Model):
group = ForeignKey(group)
item = ForeignKey(item)
order = PositiveIntegerField()
class Meta:
unique_together = [('group', 'item'), ('group', 'order')]
A way to select_related the item that has order==0 would prove very useful.
Anssi, can you explain why you think this functionality should be part of
.select_related()rather than part of.annotate()?It seems to me that your example is an annotation. Annotations may or may not involve related tables / joins, but that doesn't mean they should be done via
select_related(). If this were implemented, how would one determine which types of query annotations would happen viaannotate()and which viaselect_related()?