Django

Code

Ticket #7246: 7426_inherited_models_select_related_r7722.patch

File 7426_inherited_models_select_related_r7722.patch, 4.4 kB (added by gav, 3 months ago)

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

  • a/django/db/models/query.py

    old new  
    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) 
  • a/django/db/models/sql/query.py

    old new  
    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: 
  • /dev/null

    old new  
     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"""}