Opened 6 years ago

Closed 6 years ago

Last modified 4 years ago

#10955 closed (fixed)

`select_related()` doesn't work with proxy models.

Reported by: mrmachine Owned by: jacob
Component: Database layer (models, ORM) Version: master
Severity: Keywords: proxy model select_related
Cc: mitsuhiko Triage Stage: Unreviewed
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: UI/UX:

Description

I get a traceback if I call get() on a queryset for a proxy model which is using select_related(), or simply no objects if I try to access the queryset itself.

# models

class Country(models.Model):
	name = models.CharField(max_length=50, unique=True)

class State(models.Model):
	name = models.CharField(max_length=50)
	country = models.ForeignKey(Country)

	def __unicode__(self):
		return self.name

class StateProxy(State):
	class Meta:
		proxy = True

# interactive shell

>>> country = Country.objects.create(name='Australia')
>>> state = State.objects.create(name='New South Wales', country=country)

>>> State.objects.select_related()
[<State: New South Wales>]

>>> StateProxy.objects.select_related()
[]

# should have got [<State: New South Wales>]

>>> StateProxy.objects.get(name='New South Wales')
<StateProxy: New South Wales>

>>> StateProxy.objects.select_related().get(name='New South Wales')
Traceback (most recent call last):
  File "<console>", line 1, in ?
  File "/path/to/django/db/models/manager.py", line 120, in get
    return self.get_query_set().get(*args, **kwargs)
  File "/path/to/django/db/models/query.py", line 269, in get
    num = len(clone)
  File "/path/to/django/db/models/query.py", line 68, in __len__
    self._result_cache = list(self.iterator())
  File "/path/to/django/db/models/query.py", line 207, in iterator
    for row in self.query.results_iter():
  File "/path/to/django/db/models/sql/query.py", line 276, in results_iter
    for rows in self.execute_sql(MULTI):
  File "/path/to/django/db/models/sql/query.py", line 2301, in execute_sql
    sql, params = self.as_sql()
  File "/path/to/django/db/models/sql/query.py", line 384, in as_sql
    self.pre_sql_setup()
  File "/path/to/django/db/models/sql/query.py", line 571, in pre_sql_setup
    self.fill_related_selections()
  File "/path/to/django/db/models/sql/query.py", line 1361, in fill_related_selections
    lhs_col = int_opts.parents[int_model].column
AttributeError: 'NoneType' object has no attribute 'column'

# should have got <StateProxy: New South Wales>

Attachments (3)

10955-proxy_select_related-r10643.diff (1.5 KB) - added by mrmachine 6 years ago.
10955_proxy_select_related_r10697.diff (9.6 KB) - added by clement 6 years ago.
initial patch, fixes select_related + filter on proxy, and type issue on subproxy
10955_proxy_select_related_no_manager_fix_r10697.diff (8.2 KB) - added by clement 6 years ago.
patch without manager fix (covered by #10953)

Download all attachments as: .zip

Change History (12)

Changed 6 years ago by mrmachine

Changed 6 years ago by clement

initial patch, fixes select_related + filter on proxy, and type issue on subproxy

comment:1 Changed 6 years ago by clement

  • Has patch set
  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset

There was a possible bug on subproxy (proxy of proxy) manager creation, giving the following results on the API tests:

>>> MyPersonProxy.objects.all() 
[<MyPerson: Bazza del Frob>, <MyPerson: Foo McBar>, <MyPerson: homer>]

bypassed that by forcing manager inheritance (of abstract and concrete managers) from the model base (before skipping proxy for populating fields), but not sure this is the needed behaviour here.

Patch mostly adresses proxy skipping when joining fields (traversing multiple levels of nested proxies) and ancestors chain when populating select fields on proxy models. Added also some regression tests on proxy + model inheritance, subproxy select_related().filter(...), and ForeignKey( proxy / subproxy )

comment:2 Changed 6 years ago by Alex

I have a patch on another issue (I forget the number) that solves the manager issue.

Changed 6 years ago by clement

patch without manager fix (covered by #10953)

comment:3 Changed 6 years ago by clement

@Alex:

I suppose #10953 , attached a new patch with no modifications in django.models.base.ModelBase

comment:4 Changed 6 years ago by mitsuhiko

  • Owner changed from nobody to mitsuhiko

comment:5 Changed 6 years ago by mitsuhiko

The patch for this and #10953 is attached to my github repo: http://github.com/mitsuhiko/django/tree/ticket-10953

comment:6 Changed 6 years ago by jacob

  • Owner changed from mitsuhiko to jacob
  • Status changed from new to assigned

comment:7 Changed 6 years ago by mitsuhiko

  • Cc mitsuhiko added

comment:8 Changed 6 years ago by jacob

  • Resolution set to fixed
  • Status changed from assigned to closed

(In [10738]) Fixed #10953, #10955: proxies of proxies now work correctly, though I still don't quite understand why you'd want to do such a thing. Thanks, Armin Ronacher.

comment:6 Changed 4 years ago by jacob

  • milestone 1.1 deleted

Milestone 1.1 deleted

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