Ticket #7246: 7426_inherited_models_select_related_r7722.patch

File 7426_inherited_models_select_related_r7722.patch, 4.4 KB (added by George Vilches, 16 years ago)

Patch against r7722 to make inherited models .select_related() safe, reference implementation.

  • django/db/models/query.py

    diff -r f7a90d86bf60 django/db/models/query.py
    a b  
    746746        return None
    747747
    748748    restricted = requested is not None
    749     index_end = index_start + len(klass._meta.fields)
     749    index_end = index_start + len(klass._meta.local_fields)
    750750    obj = klass(*row[index_start:index_end])
    751751    for f in klass._meta.fields:
    752         if (not f.rel or (not restricted and f.null) or
    753                 (restricted and f.name not in requested) or f.rel.parent_link):
     752        if f.rel and f.rel.parent_link:
     753            pass
     754        elif (not f.rel or (not restricted and f.null) or
     755                (restricted and f.name not in requested)):
    754756            continue
     757       
    755758        if restricted:
    756             next = requested[f.name]
     759            next = requested.get(f.name, {})
    757760        else:
    758761            next = None
    759762        cached_row = get_cached_row(f.rel.to, row, index_end, max_depth,
    760763                cur_depth+1, next)
     764        # HACK: Doing it this way means an extra Parent object is created that
     765        # shouldn't be.  It would be better to do this before running the
     766        # cached row.
     767        if f.rel and f.rel.parent_link:
     768            for parent_field in cached_row[0]._meta.fields:
     769                setattr(obj, parent_field.name, getattr(cached_row[0], parent_field.name))
    761770        if cached_row:
    762771            rel_obj, index_end = cached_row
    763772            setattr(obj, f.get_cache_name(), rel_obj)
  • django/db/models/sql/query.py

    diff -r f7a90d86bf60 django/db/models/sql/query.py
    a b  
    879879                restricted = False
    880880
    881881        for f, model in opts.get_fields_with_model():
    882             if (not f.rel or (restricted and f.name not in requested) or
    883                     (not restricted and f.null) or f.rel.parent_link):
    884                 continue
     882            # HACK: This is a touch hacky, but the logic was easiest.
     883            if f.rel and f.rel.parent_link:
     884                pass
     885            elif (not f.rel or (restricted and f.name not in requested) or
     886                        (not restricted and f.null)):
     887                    continue
    885888            table = f.rel.to._meta.db_table
    886889            if nullable or f.null:
    887890                promote = True
     
    903906                    promote=promote)
    904907            used.add(alias)
    905908            self.related_select_cols.extend([(alias, f2.column)
    906                     for f2 in f.rel.to._meta.fields])
    907             self.related_select_fields.extend(f.rel.to._meta.fields)
     909                    for f2 in f.rel.to._meta.local_fields])
     910            self.related_select_fields.extend(f.rel.to._meta.local_fields)
    908911            if restricted:
    909912                next = requested.get(f.name, {})
    910913            else:
  • new file tests/regressiontests/model_inheritance_select_related/models.py

    diff -r f7a90d86bf60 tests/regressiontests/model_inheritance_select_related/models.py
    - +  
     1"""
     2Regression tests for the interaction between model inheritance and
     3select_related().
     4"""
     5
     6from django.db import models
     7
     8class Place(models.Model):
     9    name = models.CharField(max_length=50)
     10
     11    class Meta:
     12        ordering = ('name',)
     13       
     14    def __unicode__(self):
     15        return u"%s the place" % self.name
     16
     17class Restaurant(Place):
     18    serves_suhsi = models.BooleanField()
     19    serves_steak = models.BooleanField()
     20
     21    def __unicode__(self):
     22        return u"%s the restaurant" % self.name
     23
     24class Person(models.Model):
     25    name = models.CharField(max_length=50)
     26    favorite_restaurant = models.ForeignKey(Restaurant)
     27
     28    def __unicode__(self):
     29        return self.name
     30
     31__test__ = {'API_TESTS':"""
     32# Regression for #7246
     33
     34>>> r1 = Restaurant.objects.create(name="Nobu", serves_suhsi=True, serves_steak=False)
     35>>> r2 = Restaurant.objects.create(name="Craft", serves_suhsi=False, serves_steak=True)
     36>>> p1 = Person.objects.create(name="John", favorite_restaurant=r1)
     37>>> p2 = Person.objects.create(name="Jane", favorite_restaurant=r2)
     38
     39>>> Person.objects.order_by('name').select_related()
     40[<Person: Jane>, <Person: John>]
     41
     42>>> jane = Person.objects.order_by('name').select_related('favorite_restaurant')[0]
     43>>> jane.favorite_restaurant.name
     44u'Craft'
     45"""}
     46 No newline at end of file
Back to Top