Opened 6 months ago

Last modified 2 weeks ago

#28442 assigned Bug

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: yes
Easy pickings: no UI/UX: no


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.


[...]/django/db/models/ 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/ in filter(self, *args, **kwargs)                                                                                                                     
    782         set.                                                                                                                                                                 
    783         """
--> 784         return self._filter_or_exclude(False, *args, **kwargs)
    786     def exclude(self, *args, **kwargs):                                                                                                                                      
[...]/django/db/models/ 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
[...]/django/db/models/sql/ 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/ 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/ 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/ 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/ 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)
    114         return super(RelatedLookupMixin, self).get_prep_lookup()
[...]/django/db/models/fields/ in get_prep_value(self, value)                                                                                                             
    964         if value is None:                                                                                                                                                    
    965             return None
--> 966         return int(value)
    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 (6)

comment:1 Changed 6 months ago by Tim Graham

Triage Stage: UnreviewedAccepted

comment:2 Changed 5 months ago by Hyeon-mook Jerry Choi

Owner: changed from nobody to Hyeon-mook Jerry Choi
Status: newassigned

comment:3 Changed 2 weeks ago by Oliver Sauder

Cc: Oliver Sauder added
Has patch: set


@Hyeon-mook Jerry Choi
I have just bumped into this issue. I have created a patch as there hasn't been any update on this issue for more than 5 months and I also coudn't find a branch on your GitHub fork. Let me know whether you still work on it or otherwise I will claim the ticket.

comment:4 Changed 2 weeks ago by Tim Graham

Patch needs improvement: set

comment:5 Changed 2 weeks ago by Hyeon-mook Jerry Choi

Owner: Hyeon-mook Jerry Choi deleted
Status: assignednew

I am sorry, I didn't care about this. I deassign now.

comment:6 Changed 2 weeks ago by Oliver Sauder

Owner: set to Oliver Sauder
Status: newassigned
Note: See TracTickets for help on using tickets.
Back to Top