Opened 14 months ago

Closed 7 months ago

#28442 closed Bug (fixed)

Error creating queryset with nested OuterRefs on a foreign key

Reported by: Abram Booth Owned by: Oliver Sauder
Component: Database layer (models, ORM) Version: 1.11
Severity: Normal Keywords:
Cc: Oliver Sauder Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Given a model like:

class Agent(models.Model):
    agency = models.ForeignKey('Agency')
    ...

Trying to make a queryset for use in a nested subquery will fail (traceback+error below):

q = Agent.objects.filter(agency_id=OuterRef(OuterRef('id')))

Tested in 1.11.1 and 1.11.3. Nested OuterRefs work fine with other types of fields.

Traceback:

[...]/django/db/models/manager.py in manager_method(self, *args, **kwargs)                                                                                                           
     83         def create_method(name, method):
     84             def manager_method(self, *args, **kwargs):                                                                                                                       
---> 85                 return getattr(self.get_queryset(), name)(*args, **kwargs)                                                                                                   
     86             manager_method.__name__ = method.__name__                                                                                                                        
     87             manager_method.__doc__ = method.__doc__                                                                                                                          

[...]/django/db/models/query.py in filter(self, *args, **kwargs)                                                                                                                     
    782         set.                                                                                                                                                                 
    783         """
--> 784         return self._filter_or_exclude(False, *args, **kwargs)
    785 
    786     def exclude(self, *args, **kwargs):                                                                                                                                      
    
[...]/django/db/models/query.py in _filter_or_exclude(self, negate, *args, **kwargs)                                                                                                 
    800             clone.query.add_q(~Q(*args, **kwargs))
    801         else:                                                                                                                                                                
--> 802             clone.query.add_q(Q(*args, **kwargs))                                                                                                                            
    803         return clone
    804                       
                                                                                                                                                                                     
[...]/django/db/models/sql/query.py in add_q(self, q_object)                                                                                                                         
   1248         existing_inner = set(                                                                                                                                                
   1249             (a for a in self.alias_map if self.alias_map[a].join_type == INNER))                                                                                             
-> 1250         clause, _ = self._add_q(q_object, self.used_aliases)                                                                                                                 
   1251         if clause:                                                                                                                                                           
   1252             self.where.add(clause, AND)
        
[...]/django/db/models/sql/query.py in _add_q(self, q_object, used_aliases, branch_negated, current_negated, allow_joins, split_subq)                                                
   1274                     child, can_reuse=used_aliases, branch_negated=branch_negated,
   1275                     current_negated=current_negated, connector=connector,                                                                                                    
-> 1276                     allow_joins=allow_joins, split_subq=split_subq,                                                                                                          
   1277                 )
   1278                 joinpromoter.add_votes(needed_inner)
                
[...]/django/db/models/sql/query.py in build_filter(self, filter_expr, branch_negated, current_negated, can_reuse, connector, allow_joins, split_subq)                               
   1204             else:
   1205                 lhs = MultiColSource(alias, targets, sources, field)                                                                                                         
-> 1206             condition = lookup_class(lhs, value)                                                                                                                             
   1207             lookup_type = lookup_class.lookup_name                                                                                                                           
   1208         else:                                                                                                                                                                
                                                                                                                                                                                     
[...]/django/db/models/lookups.py in __init__(self, lhs, rhs)                                                                                                                        
     22     def __init__(self, lhs, rhs):                                                                                                                                            
     23         self.lhs, self.rhs = lhs, rhs
---> 24         self.rhs = self.get_prep_lookup()
     25         if hasattr(self.lhs, 'get_bilateral_transforms'):
     26             bilateral_transforms = self.lhs.get_bilateral_transforms()
            
[...]/django/db/models/fields/related_lookups.py in get_prep_lookup(self)
    110                 # as we don't get to the direct value branch otherwise.                                                                                                      
    111                 target_field = self.lhs.output_field.get_path_info()[-1].target_fields[-1]                                                                                   
--> 112                 self.rhs = target_field.get_prep_value(self.rhs)
    113         
    114         return super(RelatedLookupMixin, self).get_prep_lookup()
                
[...]/django/db/models/fields/__init__.py in get_prep_value(self, value)                                                                                                             
    964         if value is None:                                                                                                                                                    
    965             return None
--> 966         return int(value)
    967     
    968     def contribute_to_class(self, cls, name, **kwargs):
            
TypeError: int() argument must be a string, a bytes-like object or a number, not 'OuterRef'

Change History (4)

comment:1 Changed 14 months ago by Tim Graham

Triage Stage: UnreviewedAccepted

comment:3 Changed 9 months ago by Oliver Sauder

Cc: Oliver Sauder added
Has patch: set
Last edited 7 months ago by Tim Graham (previous) (diff)

comment:6 Changed 9 months ago by Oliver Sauder

Owner: set to Oliver Sauder
Status: newassigned

comment:7 Changed 7 months ago by Tim Graham <timograham@…>

Resolution: fixed
Status: assignedclosed

In 6f0b8c1c:

Fixed #28442 -- Fixed crash with nested OuterRefs that reference AutoField.

Note: See TracTickets for help on using tickets.
Back to Top