Opened 6 years ago
Last modified 23 months ago
#30129 closed New feature
Request to Allow F() Expressions in Subquery() on Insert — at Initial Version
Reported by: | Charlie McBride | Owned by: | |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 2.1 |
Severity: | Normal | Keywords: | Subquery, F, Query Expressions |
Cc: | Triage Stage: | Accepted | |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
I understand why F() expressions are generally disallowed inside insert statements, the columns you are referencing don't yet exist, so it wouldn't make any sense to do so. However, if you are performing an insert with a Subquery (as in the example below), it's possible to have otherwise valid statements rejected because of the blanket blacklist of F() expressions during inserts.
For example:
given the following models:
class Item(models.Model): pass class ItemVersion(models.Model): item = models.ForeignKey(Item, related_name='versions') version_number = models.IntegerField(default=0) class Meta: unique_together = ('item', 'version_number',)
I would like to be able to do the following operation to mitigate race conditions as described here (https://docs.djangoproject.com/en/2.1/ref/models/expressions/#avoiding-race-conditions-using-f)
item = Item.objects.create() # arbitrary number of other items created/destroyed etc item_version_2 = ItemVersion.objects.create( item=item, version_number=Subquery( item.versions.order_by('- version_number').annotate( max_version_number=Coalesce(Max('version_number'), 0) ).annotate( new_version_number=F('max_version_number) + 1 ).values('new_version_number')[:1] ) )
As written, I would expect the F() in the inner expression to always be resolvable, because it is in a Subquery (and not the result of an insert). However this query is blocked by the compiler because "F() expressions can only be used to update, not to insert." Would it be possible to allow F expressions in a Subquery even if it is being used in an insert? Is there an edge case that I'm missing that caused the team to not consider this?