Ticket #7154: 7154.copy-managers.r7787.diff

File 7154.copy-managers.r7787.diff, 9.6 KB (added by Johannes Dollinger, 16 years ago)
  • django/db/models/base.py

     
    7373                if not hasattr(meta, 'get_latest_by'):
    7474                    new_class._meta.get_latest_by = base_meta.get_latest_by
    7575
    76         old_default_mgr = None
    77         if getattr(new_class, '_default_manager', None):
    78             # We have a parent who set the default manager.
    79             if new_class._default_manager.model._meta.abstract:
    80                 old_default_mgr = new_class._default_manager
    81             new_class._default_manager = None
    82 
    8376        # Bail out early if we have already created this class.
    8477        m = get_model(new_class._meta.app_label, name, False)
    8578        if m is not None:
     
    109102                    new_class.add_to_class(attr_name, field)
    110103                new_class._meta.parents[base] = field
    111104            else:
    112                 # The abstract base class case.
     105                # Copy fields from the abstract base class.
    113106                names = set([f.name for f in new_class._meta.local_fields + new_class._meta.many_to_many])
    114107                for field in base._meta.local_fields + base._meta.local_many_to_many:
    115108                    if field.name in names:
     
    117110                                % (field.name, name, base.__name__))
    118111                    new_class.add_to_class(field.name, copy.deepcopy(field))
    119112
     113            # Copy managers from the base model.
     114            for mgr_attr, mgr in base._meta.managers.iteritems():
     115                if mgr_attr in new_class.__dict__:
     116                    continue
     117                new_class.add_to_class(mgr_attr, copy.copy(mgr))
     118
    120119        if abstract:
    121120            # Abstract base models can't be instantiated and don't appear in
    122121            # the list of models for an app. We do the final setup for them a
     
    125124            new_class.Meta = attr_meta
    126125            return new_class
    127126
    128         if old_default_mgr and not new_class._default_manager:
    129             new_class._default_manager = old_default_mgr._copy_to_model(new_class)
    130127        new_class._prepare()
    131128        register_models(new_class._meta.app_label, new_class)
    132129
  • django/db/models/manager.py

     
    3131
    3232    def contribute_to_class(self, model, name):
    3333        # TODO: Use weakref because of possible memory leak / circular reference.
     34        model._meta.managers[name] = self
     35        if model._meta.abstract:
     36            return
    3437        self.model = model
    3538        setattr(model, name, ManagerDescriptor(self))
    36         if not getattr(model, '_default_manager', None) or self.creation_counter < model._default_manager.creation_counter:
    37             model._default_manager = self
     39        if not getattr(model, '_default_manager', None) or self.creation_counter <= model._default_manager.creation_counter:
     40            # If the creation_counter is less than the creation_counter of
     41            # the  default manager, it is defined before the given default
     42            # manager, so we set the default manager, that when all managers
     43            # were contributed to the model, the first defined is the
     44            # default manager.
    3845
    39     def _copy_to_model(self, model):
    40         """
    41         Makes a copy of the manager and assigns it to 'model', which should be
    42         a child of the existing model (used when inheriting a manager from an
    43         abstract base class).
    44         """
    45         assert issubclass(model, self.model)
    46         mgr = copy.copy(self)
    47         mgr.model = model
    48         return mgr
     46            # If the creation_counter is equals the creation_counter of the
     47            # default manager, it is the same manager in a derived model and
     48            # we have to update it, because of its model attribute is
     49            # incorrect now.
     50            model._default_manager = self       
    4951
    5052    #######################
    5153    # PROXIES TO QUERYSET #
  • django/db/models/options.py

     
    4545        self.abstract = False
    4646        self.parents = SortedDict()
    4747        self.duplicate_targets = {}
     48        self.managers = {}
    4849
    4950    def contribute_to_class(self, cls, name):
    5051        from django.db import connection
  • tests/modeltests/custom_managers/models.py

     
    4444
    4545# An example of providing multiple custom managers.
    4646
     47class SlowCarManager(models.Manager):
     48    def get_query_set(self):
     49        return super(SlowCarManager, self).get_query_set().filter(top_speed__lte=124)
     50
     51class MediumFastCarManager(models.Manager):
     52    def get_query_set(self):
     53        return super(MediumFastCarManager, self).get_query_set().filter(top_speed__range=(125, 149))
     54
    4755class FastCarManager(models.Manager):
    4856    def get_query_set(self):
    49         return super(FastCarManager, self).get_query_set().filter(top_speed__gt=150)
     57        return super(FastCarManager, self).get_query_set().filter(top_speed__range=(150, 174))
    5058
     59class VeryFastCarManager(models.Manager):
     60    def get_query_set(self):
     61        return super(VeryFastCarManager, self).get_query_set().filter(top_speed__range=(175, 199))
     62
     63class ReallyFastCarManager(models.Manager):
     64    def get_query_set(self):
     65        return super(ReallyFastCarManager, self).get_query_set().filter(top_speed__gte=200)
     66
    5167class Car(models.Model):
    5268    name = models.CharField(max_length=10)
    5369    mileage = models.IntegerField()
    5470    top_speed = models.IntegerField(help_text="In miles per hour.")
     71
     72    # We need a large number of managers to see whether it is really the first
     73    # defined, which becomes the default manager, due to python's dict internal.
    5574    cars = models.Manager()
     75    slow_cars = SlowCarManager()
     76    medium_fast_cars = MediumFastCarManager()
    5677    fast_cars = FastCarManager()
     78    very_fast_cars = VeryFastCarManager()
     79    really_fast_cars =  ReallyFastCarManager()
    5780
    5881    def __unicode__(self):
    5982        return self.name
     
    90113
    91114>>> Book.published_objects.all()
    92115[<Book: How to program>]
    93 
    94116>>> c1 = Car(name='Corvette', mileage=21, top_speed=180)
    95117>>> c1.save()
    96118>>> c2 = Car(name='Neon', mileage=31, top_speed=100)
    97119>>> c2.save()
    98120>>> Car.cars.order_by('name')
    99121[<Car: Corvette>, <Car: Neon>]
    100 >>> Car.fast_cars.all()
     122>>> Car.very_fast_cars.all()
    101123[<Car: Corvette>]
    102124
    103125# Each model class gets a "_default_manager" attribute, which is a reference
    104 # to the first manager defined in the class. In this case, it's "cars".
    105 >>> Car._default_manager.order_by('name')
    106 [<Car: Corvette>, <Car: Neon>]
     126# to the first manager defined in the class.
     127>>> Car._default_manager
     128<django.db.models.manager.Manager object at ...>
     129
    107130"""}
  • tests/modeltests/model_inheritance/models.py

     
    1818# Abstract base classes
    1919#
    2020
     21class AdultManager(models.Manager):
     22    def get_query_set(self):
     23        return super(AdultManager, self).get_query_set().filter(age__gte=18)
     24
     25class Adult21Manager(models.Manager):
     26    def get_query_set(self):
     27        return super(Adult21Manager, self).get_query_set().filter(age__gte=21)
     28
    2129class CommonInfo(models.Model):
    2230    name = models.CharField(max_length=50)
    2331    age = models.PositiveIntegerField()
    2432
     33    objects = models.Manager()
     34    adults = AdultManager()
     35
    2536    class Meta:
    2637        abstract = True
    2738        ordering = ['name']
     
    3041        return u'%s %s' % (self.__class__.__name__, self.name)
    3142
    3243class Worker(CommonInfo):
     44    adults = Adult21Manager()
     45
    3346    job = models.CharField(max_length=50)
    3447
    3548class Student(CommonInfo):
     
    115128
    116129    def __unicode__(self):
    117130        return u"%s the parking lot" % self.name
     131       
     132class A(models.Model):
     133    a = models.IntegerField()
    118134
     135    class Meta:
     136        abstract = True
     137
     138class PositiveBManager(models.Manager):
     139    def get_query_set(self):
     140        return super(PositiveBManager, self).get_query_set().filter(b__gte=0)
     141       
     142class B(A):
     143    b = models.IntegerField()
     144    positive = PositiveBManager()
     145
    119146__test__ = {'API_TESTS':"""
    120147# The Student and Worker models both have 'name' and 'age' fields on them and
    121148# inherit the __unicode__() method, just as with normal Python subclassing.
     
    125152
    126153>>> w = Worker(name='Fred', age=35, job='Quarry worker')
    127154>>> w.save()
    128 >>> w2 = Worker(name='Barney', age=34, job='Quarry worker')
     155>>> w2 = Worker(name='Barney', age=20, job='Quarry worker')
    129156>>> w2.save()
    130157>>> s = Student(name='Pebbles', age=5, school_class='1B')
    131158>>> s.save()
     
    144171>>> Student._meta.ordering
    145172[]
    146173
     174# The children inherit the custom managers from their parents, but children can
     175# still override it.
     176>>> Student(name='Bill', age=18, school_class='11A').save()
     177>>> Student.adults.all()
     178[<Student: Student Bill>]
     179
     180>>> Worker.adults.all()
     181[<Worker: Worker Fred>]
     182
    147183# However, the CommonInfo class cannot be used as a normal model (it doesn't
    148184# exist as a model).
    149185>>> CommonInfo.objects.all()
     
    3093453
    310346>>> settings.DEBUG = False
    311347
     348>>> isinstance(B._default_manager, PositiveBManager)
     349True
     350
    312351"""}
Back to Top