Changes between Initial Version and Version 1 of Ticket #33137


Ignore:
Timestamp:
Sep 24, 2021, 7:00:27 AM (3 years ago)
Author:
Markus Holtermann
Comment:

Legend:

Unmodified
Added
Removed
Modified
  • Ticket #33137 – Description

    initial v1  
    22
    33Let's say you have two models `A` and `B` where `A.rel = MyOneToOneField(B)` and `A.deleted = BooleanField()`. In a regular `OneToOneField` there would now be a unique index on `A.rel`. However, by adding a unique constraint to `A._meta.constraints` over `rel` with a condition on `deleted=False`, `rel` only needs to be unique among the "undeleted" objects. Doing so is possible by forcing `MyOneToOneField.unique=False` (otherwise migrations create a constraint). However, this will mean, `SQLCompiler.get_related_selections()` fails when trying to do `B.objects.select_related("a")`, since `a` is not a valid field. That is because `SQLCompiler.get_related_selections._get_field_choices()` uses `f.field.unique` instead of `(f.field.many_to_one or f.field.one_to_one)`, I think. Because, essentially, `opts.related_objects` is build based on those `(many|one)_to_(many|one)` field attributes.
     4
     5I think, what would fix the behavior, could be something like this:
     6
     7{{{#!python
     8class SQLCompiler:
     9    def get_related_selections(self, select, opts=None, root_alias=None, cur_depth=1,
     10                               requested=None, restricted=None):
     11        def _get_field_choices():
     12            direct_choices = (f.name for f in opts.fields if f.is_relation)
     13            reverse_choices = (
     14                f.field.related_query_name()
     15                for f in opts.related_objects if (f.field.many_to_one or f.field.one_to_one)
     16            )
     17            return chain(direct_choices, reverse_choices, self.query._filtered_relations)
     18}}}
Back to Top