Ticket #10955: 10955_proxy_select_related_r10697.diff
File 10955_proxy_select_related_r10697.diff, 9.6 KB (added by , 16 years ago) |
---|
-
django/db/models/sql/query.py
778 778 qn2 = self.connection.ops.quote_name 779 779 aliases = set() 780 780 only_load = self.deferred_to_columns() 781 proxied_model = opts.proxy and opts.proxy_for_model or 0 781 # Skip all proxy to the root proxied model 782 int_opts = opts 783 proxied_model = None 784 while int_opts.proxy: 785 proxied_model = int_opts.proxy_for_model 786 int_opts = proxied_model._meta 787 782 788 if start_alias: 783 789 seen = {None: start_alias} 784 790 for field, model in opts.get_fields_with_model(): … … 1301 1307 opts = self.model._meta 1302 1308 root_alias = self.tables[0] 1303 1309 seen = {None: root_alias} 1304 proxied_model = opts.proxy and opts.proxy_for_model or 0 1310 1311 # Skip all proxy to the root proxied model 1312 int_opts = opts 1313 proxied_model = None 1314 while int_opts.proxy: 1315 proxied_model = int_opts.proxy_for_model 1316 int_opts = proxied_model._meta 1317 1305 1318 for field, model in opts.get_fields_with_model(): 1306 1319 if model not in seen: 1307 1320 if model is proxied_model: … … 1376 1389 alias = root_alias 1377 1390 alias_chain = [] 1378 1391 for int_model in opts.get_base_chain(model): 1392 # Proxy model have elements in base chain 1393 # with no parents, assign the new options 1394 # object and skip to the next base in that 1395 # case 1396 if not int_opts.parents[int_model]: 1397 int_opts = int_model._meta 1398 continue 1379 1399 lhs_col = int_opts.parents[int_model].column 1380 1400 dedupe = lhs_col in opts.duplicate_targets 1381 1401 if dedupe: … … 1720 1740 raise MultiJoin(pos + 1) 1721 1741 if model: 1722 1742 # The field lives on a base class of the current model. 1723 proxied_model = opts.proxy and opts.proxy_for_model or 0 1743 # Skip the chain of proxy to the concrete proxied model 1744 int_opts = opts 1745 proxied_model = None 1746 while int_opts.proxy: 1747 proxied_model = int_opts.proxy_for_model 1748 int_opts = proxied_model._meta 1749 1724 1750 for int_model in opts.get_base_chain(model): 1725 1751 if int_model is proxied_model: 1726 1752 opts = int_model._meta -
django/db/models/base.py
138 138 'with field of similar name from ' 139 139 'base class %r' % 140 140 (field.name, name, base.__name__)) 141 142 # Stores real base (before skipping proxy classes) 143 # for managers inheritance. Managers should be inherited 144 # from concrete and abstract managers of immediate bases 145 base_orig = base 141 146 if not base._meta.abstract: 142 147 # Concrete classes... 143 148 while base._meta.proxy: … … 162 167 new_class._meta.parents.update(base._meta.parents) 163 168 164 169 # Inherit managers from the abstract base classes. 165 new_class.copy_managers(base ._meta.abstract_managers)170 new_class.copy_managers(base_orig._meta.abstract_managers) 166 171 167 172 # Proxy models inherit the non-abstract managers from their base, 168 173 # unless they have redefined any of them. 169 174 if is_proxy: 170 new_class.copy_managers(base ._meta.concrete_managers)175 new_class.copy_managers(base_orig._meta.concrete_managers) 171 176 172 177 # Inherit virtual fields (like GenericForeignKey) from the parent 173 178 # class -
django/db/models/options.py
461 461 if ancestor in self.parents: 462 462 return self.parents[ancestor] 463 463 for parent in self.parents: 464 if parent._meta.get_ancestor_link(ancestor): 465 return self.parents[parent] 464 # Tries to get a link field from the immediate parent 465 parent_link = parent._meta.get_ancestor_link(ancestor) 466 if parent_link: 467 # In case of a proxied model, the first link 468 # of the chain to the ancestor is that parent 469 # links 470 return self.parents[parent] or parent_link 466 471 467 472 def get_ordered_objects(self): 468 473 "Returns a list of Options objects that are ordered with respect to this object." -
tests/modeltests/proxy_models/models.py
82 82 class LowerStatusPerson(MyPersonProxy): 83 83 status = models.CharField(max_length=80) 84 84 85 # We can still use `select_related()` to include related models in our querysets. 86 class Country(models.Model): 87 name = models.CharField(max_length=50) 88 89 class State(models.Model): 90 name = models.CharField(max_length=50) 91 country = models.ForeignKey(Country) 92 93 def __unicode__(self): 94 return self.name 95 96 class StateProxy(State): 97 class Meta: 98 proxy = True 99 100 # Proxy models still works with filters (on related fields) 101 # and select_related, even when mixed with model inheritance 102 class BaseUser(models.Model): 103 name = models.CharField(max_length=255) 104 105 class TrackerUser(BaseUser): 106 status = models.CharField(max_length=50) 107 108 class ProxyTrackerUser(TrackerUser): 109 class Meta: 110 proxy = True 111 112 113 class Issue(models.Model): 114 summary = models.CharField(max_length=255) 115 assignee = models.ForeignKey(TrackerUser) 116 117 def __unicode__(self): 118 return ':'.join((self.__class__.__name__,self.summary,)) 119 120 class Bug(Issue): 121 version = models.CharField(max_length=50) 122 reporter = models.ForeignKey(BaseUser) 123 124 class ProxyBug(Bug): 125 """ 126 Proxy of an inherited class 127 """ 128 class Meta: 129 proxy = True 130 131 132 class ProxyProxyBug(ProxyBug): 133 """ 134 A proxy of proxy model with related field 135 """ 136 class Meta: 137 proxy = True 138 139 class Improvement(Issue): 140 """ 141 A model that has relation to a proxy model 142 or to a proxy of proxy model 143 """ 144 version = models.CharField(max_length=50) 145 reporter = models.ForeignKey(ProxyTrackerUser) 146 associated_bug = models.ForeignKey(ProxyProxyBug) 147 148 class ProxyImprovement(Improvement): 149 class Meta: 150 proxy = True 151 85 152 __test__ = {'API_TESTS' : """ 86 153 # The MyPerson model should be generating the same database queries as the 87 154 # Person model (when the same manager is used in each case). … … 119 186 >>> LowerStatusPerson.objects.all() 120 187 [<LowerStatusPerson: homer>] 121 188 189 # Correct type when querying a proxy of proxy 190 191 >>> MyPersonProxy.objects.all() 192 [<MyPersonProxy: Bazza del Frob>, <MyPersonProxy: Foo McBar>, <MyPersonProxy: homer>] 193 122 194 # And now for some things that shouldn't work... 123 195 # 124 196 # All base classes must be non-abstract … … 178 250 >>> ctype = ContentType.objects.get_for_model 179 251 >>> ctype(Person) is ctype(OtherPerson) 180 252 True 181 """}182 253 254 # We can still use `select_related()` to include related models in our querysets. 255 >>> country = Country.objects.create(name='Australia') 256 >>> state = State.objects.create(name='New South Wales', country=country) 183 257 258 >>> State.objects.select_related() 259 [<State: New South Wales>] 260 >>> StateProxy.objects.select_related() 261 [<StateProxy: New South Wales>] 262 >>> StateProxy.objects.get(name='New South Wales') 263 <StateProxy: New South Wales> 264 >>> StateProxy.objects.select_related().get(name='New South Wales') 265 <StateProxy: New South Wales> 266 267 >>> contributor = TrackerUser.objects.create(name='Contributor',status='contrib') 268 >>> someone = BaseUser.objects.create(name='Someone') 269 >>> _ = Bug.objects.create(summary='fix this', version='1.1beta', 270 ... assignee=contributor, reporter=someone) 271 >>> pcontributor = ProxyTrackerUser.objects.create(name='OtherContributor', 272 ... status='proxy') 273 >>> _ = Improvement.objects.create(summary='improve that', version='1.1beta', 274 ... assignee=contributor, reporter=pcontributor, 275 ... associated_bug=ProxyProxyBug.objects.all()[0]) 276 277 # Related field filter on proxy 278 >>> ProxyBug.objects.get(version__icontains='beta') 279 <ProxyBug: ProxyBug:fix this> 280 281 # Select related + filter on proxy 282 >>> ProxyBug.objects.select_related().get(version__icontains='beta') 283 <ProxyBug: ProxyBug:fix this> 284 285 # Proxy of proxy, select_related + filter 286 >>> ProxyProxyBug.objects.select_related().get(version__icontains='beta') 287 <ProxyProxyBug: ProxyProxyBug:fix this> 288 289 # Select related + filter on a related proxy field 290 >>> ProxyImprovement.objects.select_related().get(reporter__name__icontains='butor') 291 <ProxyImprovement: ProxyImprovement:improve that> 292 293 # Select related + filter on a related proxy of proxy field 294 >>> ProxyImprovement.objects.select_related().get(associated_bug__summary__icontains='fix') 295 <ProxyImprovement: ProxyImprovement:improve that> 296 """}