Ticket #14705: ticket14705.diff

File ticket14705.diff, 5.2 KB (added by ambv, 5 years ago)

Required functionality (sans m2m fields) + tests; based on r15176

  • django/db/models/base.py

     
    100100                     new_class._meta.virtual_fields
    101101        field_names = set([f.name for f in new_fields])
    102102
     103        # Things without _meta aren't functional models, so they're
     104        # uninteresting parents.
     105        parents = [cls for cls in parents if hasattr(cls, '_meta')]
     106        new_class._meta.bases = parents
     107
    103108        # Basic setup for proxy models.
    104109        if is_proxy:
    105110            base = None
    106             for parent in [cls for cls in parents if hasattr(cls, '_meta')]:
     111            for parent in parents:
    107112                if parent._meta.abstract:
    108113                    if parent._meta.fields:
    109114                        raise TypeError("Abstract base class containing model fields not permitted for proxy model '%s'." % name)
     
    128133
    129134        for base in parents:
    130135            original_base = base
    131             if not hasattr(base, '_meta'):
    132                 # Things without _meta aren't functional models, so they're
    133                 # uninteresting parents.
    134                 continue
    135 
    136136            parent_fields = base._meta.local_fields + base._meta.local_many_to_many
    137137            # Check for clashes between locally declared fields and those
    138138            # on the base classes (we cannot handle shadowed fields at the
  • django/db/models/options.py

     
    4747        self.proxy = False
    4848        self.proxy_for_model = None
    4949        self.parents = SortedDict()
     50        self.bases = []
    5051        self.duplicate_targets = {}
    5152        self.auto_created = False
    5253
     
    228229
    229230    def _fill_fields_cache(self):
    230231        cache = []
    231         for parent in self.parents:
    232             for field, model in parent._meta.get_fields_with_model():
    233                 if model:
     232        local_fields = list(self.local_fields)
     233        for field in self.local_fields:
     234            if isinstance(field, AutoField):
     235                cache.append((field, None))
     236                local_fields.remove(field)
     237                break
     238        for base in self.bases:
     239            for field, model in base._meta.get_fields_with_model():
     240                if not model:
     241                    model = base
     242                if model._meta.abstract:
     243                    field_index = local_fields.index(field)
     244                    cache.append((local_fields[field_index], None))
     245                    del local_fields[field_index]
     246                else:
    234247                    cache.append((field, model))
    235                 else:
    236                     cache.append((field, parent))
    237         cache.extend([(f, None) for f in self.local_fields])
     248            if base in self.parents:
     249                field = self.parents[base]
     250                if field:
     251                    cache.append((field, None))
     252                    local_fields.remove(field)
     253        cache.extend([(f, None) for f in local_fields])
    238254        self._field_cache = tuple(cache)
    239255        self._field_name_cache = [x for x, _ in cache]
    240256
  • tests/modeltests/model_inheritance/tests.py

     
    44from django.test import TestCase
    55
    66from models import (Chef, CommonInfo, ItalianRestaurant, ParkingLot, Place,
    7     Post, Restaurant, Student, StudentWorker, Supplier, Worker)
     7    Post, Restaurant, Student, StudentWorker, Supplier, Worker, OneTwo, TwoOne)
    88
    99
    1010class ModelInheritanceTests(TestCase):
     
    269269        self.assertNumQueries(1,
    270270            lambda: ItalianRestaurant.objects.select_related("chef")[0].chef
    271271        )
     272
     273        names = [field.name for field in OneTwo._meta.fields]
     274        self.assertEqual(["id", "field_one", "field_two", "field_three",
     275            "field_four"], names)
     276
     277        names = [field.name for field in TwoOne._meta.fields]
     278        self.assertEqual(["id", "field_three", "field_four", "field_one",
     279            "field_two"], names)
     280
  • tests/modeltests/model_inheritance/models.py

     
    119119    def __unicode__(self):
    120120        return u"%s the parking lot" % self.name
    121121
     122class AbstractModelOne(models.Model):
     123    field_one = models.BooleanField()
     124    field_two = models.TextField()
     125
     126    class Meta:
     127        abstract = True
     128
     129class AbstractModelTwo(models.Model):
     130    field_three = models.BooleanField()
     131    field_four = models.TextField()
     132
     133    class Meta:
     134        abstract = True
     135
     136class OneTwo(AbstractModelOne, AbstractModelTwo):
     137    pass
     138
     139class TwoOne(AbstractModelTwo, AbstractModelOne):
     140    pass
     141
    122142#
    123143# Abstract base classes with related models where the sub-class has the
    124144# same name in a different app and inherits from the same abstract base
Back to Top