mirror of
https://github.com/django/django.git
synced 2025-07-06 02:39:12 +00:00
queryset-refactor: Second part of select_related() fix.
Relations on the parent model can now be specified as part of the fields list. Fixed #6761. git-svn-id: http://code.djangoproject.com/svn/django/branches/queryset-refactor@7241 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
cf2da4689a
commit
59ac04a54d
@ -769,10 +769,10 @@ class Query(object):
|
|||||||
return
|
return
|
||||||
if not opts:
|
if not opts:
|
||||||
opts = self.get_meta()
|
opts = self.get_meta()
|
||||||
root_alias = self.tables[0]
|
root_alias = self.get_initial_alias()
|
||||||
self.select.extend(self.get_default_columns())
|
self.select.extend(self.get_default_columns())
|
||||||
if not used:
|
if not used:
|
||||||
used = []
|
used = set()
|
||||||
|
|
||||||
# Setup for the case when only particular related fields should be
|
# Setup for the case when only particular related fields should be
|
||||||
# included in the related selection.
|
# included in the related selection.
|
||||||
@ -783,14 +783,24 @@ class Query(object):
|
|||||||
else:
|
else:
|
||||||
restricted = False
|
restricted = False
|
||||||
|
|
||||||
for f in opts.fields:
|
for f, model in opts.get_fields_with_model():
|
||||||
if (not f.rel or (restricted and f.name not in requested) or
|
if (not f.rel or (restricted and f.name not in requested) or
|
||||||
(not restricted and f.null) or f.rel.parent_link):
|
(not restricted and f.null) or f.rel.parent_link):
|
||||||
continue
|
continue
|
||||||
table = f.rel.to._meta.db_table
|
table = f.rel.to._meta.db_table
|
||||||
alias = self.join((root_alias, table, f.column,
|
if model:
|
||||||
|
int_opts = opts
|
||||||
|
alias = root_alias
|
||||||
|
for int_model in opts.get_base_chain(model):
|
||||||
|
lhs_col = int_opts.parents[int_model].column
|
||||||
|
int_opts = int_model._meta
|
||||||
|
alias = self.join((alias, int_opts.db_table, lhs_col,
|
||||||
|
int_opts.pk.column), exclusions=used)
|
||||||
|
else:
|
||||||
|
alias = root_alias
|
||||||
|
alias = self.join((alias, table, f.column,
|
||||||
f.rel.get_related_field().column), exclusions=used)
|
f.rel.get_related_field().column), exclusions=used)
|
||||||
used.append(alias)
|
used.add(alias)
|
||||||
self.select.extend([(alias, f2.column)
|
self.select.extend([(alias, f2.column)
|
||||||
for f2 in f.rel.to._meta.fields])
|
for f2 in f.rel.to._meta.fields])
|
||||||
if restricted:
|
if restricted:
|
||||||
|
@ -42,6 +42,12 @@ class Student(CommonInfo):
|
|||||||
# Multi-table inheritance
|
# Multi-table inheritance
|
||||||
#
|
#
|
||||||
|
|
||||||
|
class Chef(models.Model):
|
||||||
|
name = models.CharField(max_length=50)
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return u"%s the chef" % self.name
|
||||||
|
|
||||||
class Place(models.Model):
|
class Place(models.Model):
|
||||||
name = models.CharField(max_length=50)
|
name = models.CharField(max_length=50)
|
||||||
address = models.CharField(max_length=80)
|
address = models.CharField(max_length=80)
|
||||||
@ -59,6 +65,7 @@ class Rating(models.Model):
|
|||||||
class Restaurant(Place, Rating):
|
class Restaurant(Place, Rating):
|
||||||
serves_hot_dogs = models.BooleanField()
|
serves_hot_dogs = models.BooleanField()
|
||||||
serves_pizza = models.BooleanField()
|
serves_pizza = models.BooleanField()
|
||||||
|
chef = models.ForeignKey(Chef, null=True, blank=True)
|
||||||
|
|
||||||
class Meta(Rating.Meta):
|
class Meta(Rating.Meta):
|
||||||
db_table = 'my_restaurant'
|
db_table = 'my_restaurant'
|
||||||
@ -136,7 +143,9 @@ Test constructor for Restaurant.
|
|||||||
>>> r.save()
|
>>> r.save()
|
||||||
|
|
||||||
# Test the constructor for ItalianRestaurant.
|
# Test the constructor for ItalianRestaurant.
|
||||||
>>> ir = ItalianRestaurant(name='Ristorante Miron', address='1234 W. Ash', serves_hot_dogs=False, serves_pizza=False, serves_gnocchi=True, rating=4)
|
>>> c = Chef(name="Albert")
|
||||||
|
>>> c.save()
|
||||||
|
>>> ir = ItalianRestaurant(name='Ristorante Miron', address='1234 W. Ash', serves_hot_dogs=False, serves_pizza=False, serves_gnocchi=True, rating=4, chef=c)
|
||||||
>>> ir.save()
|
>>> ir.save()
|
||||||
>>> ir.address = '1234 W. Elm'
|
>>> ir.address = '1234 W. Elm'
|
||||||
>>> ir.save()
|
>>> ir.save()
|
||||||
@ -144,9 +153,9 @@ Test constructor for Restaurant.
|
|||||||
# Make sure Restaurant and ItalianRestaurant have the right fields in the right
|
# Make sure Restaurant and ItalianRestaurant have the right fields in the right
|
||||||
# order.
|
# order.
|
||||||
>>> [f.name for f in Restaurant._meta.fields]
|
>>> [f.name for f in Restaurant._meta.fields]
|
||||||
['id', 'name', 'address', 'place_ptr', 'rating', 'serves_hot_dogs', 'serves_pizza']
|
['id', 'name', 'address', 'place_ptr', 'rating', 'serves_hot_dogs', 'serves_pizza', 'chef']
|
||||||
>>> [f.name for f in ItalianRestaurant._meta.fields]
|
>>> [f.name for f in ItalianRestaurant._meta.fields]
|
||||||
['id', 'name', 'address', 'place_ptr', 'rating', 'serves_hot_dogs', 'serves_pizza', 'restaurant_ptr', 'serves_gnocchi']
|
['id', 'name', 'address', 'place_ptr', 'rating', 'serves_hot_dogs', 'serves_pizza', 'chef', 'restaurant_ptr', 'serves_gnocchi']
|
||||||
>>> Restaurant._meta.ordering
|
>>> Restaurant._meta.ordering
|
||||||
['-rating']
|
['-rating']
|
||||||
|
|
||||||
@ -158,7 +167,7 @@ Test constructor for Restaurant.
|
|||||||
>>> Restaurant.objects.filter(supplier__name='foo')
|
>>> Restaurant.objects.filter(supplier__name='foo')
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
FieldError: Cannot resolve keyword 'supplier' into field. Choices are: address, id, italianrestaurant, lot, name, place_ptr, provider, rating, serves_hot_dogs, serves_pizza
|
FieldError: Cannot resolve keyword 'supplier' into field. Choices are: address, chef, id, italianrestaurant, lot, name, place_ptr, provider, rating, serves_hot_dogs, serves_pizza
|
||||||
|
|
||||||
# Parent fields can be used directly in filters on the child model.
|
# Parent fields can be used directly in filters on the child model.
|
||||||
>>> Restaurant.objects.filter(name='Demon Dogs')
|
>>> Restaurant.objects.filter(name='Demon Dogs')
|
||||||
@ -240,4 +249,19 @@ u'Demon Puppies'
|
|||||||
>>> list(ItalianRestaurant.objects.values('name', 'rating')) == [d]
|
>>> list(ItalianRestaurant.objects.values('name', 'rating')) == [d]
|
||||||
True
|
True
|
||||||
|
|
||||||
|
# select_related works with fields from the parent object as if they were a
|
||||||
|
# normal part of the model.
|
||||||
|
>>> from django import db
|
||||||
|
>>> from django.conf import settings
|
||||||
|
>>> settings.DEBUG = True
|
||||||
|
>>> db.reset_queries()
|
||||||
|
>>> ItalianRestaurant.objects.all()[0].chef
|
||||||
|
<Chef: Albert the chef>
|
||||||
|
>>> len(db.connection.queries)
|
||||||
|
2
|
||||||
|
>>> ItalianRestaurant.objects.select_related('chef')[0].chef
|
||||||
|
<Chef: Albert the chef>
|
||||||
|
>>> len(db.connection.queries)
|
||||||
|
3
|
||||||
|
|
||||||
"""}
|
"""}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user