Django

Code

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

File 7154.copy-managers.r7818.diff, 9.6 kB (added by emulbreh, 5 months ago)
  • django/db/models/base.py

    old new  
    7575                if not hasattr(meta, 'get_latest_by'): 
    7676                    new_class._meta.get_latest_by = base_meta.get_latest_by 
    7777 
    78         old_default_mgr = None 
    79         if getattr(new_class, '_default_manager', None): 
    80             # We have a parent who set the default manager. 
    81             if new_class._default_manager.model._meta.abstract: 
    82                 old_default_mgr = new_class._default_manager 
    83             new_class._default_manager = None 
    84  
    8578        # Bail out early if we have already created this class. 
    8679        m = get_model(new_class._meta.app_label, name, False) 
    8780        if m is not None: 
     
    111104                    new_class.add_to_class(attr_name, field) 
    112105                new_class._meta.parents[base] = field 
    113106            else: 
    114                 # The abstract base class case
     107                # Copy fields from the abstract base class
    115108                names = set([f.name for f in new_class._meta.local_fields + new_class._meta.many_to_many]) 
    116109                for field in base._meta.local_fields + base._meta.local_many_to_many: 
    117110                    if field.name in names: 
     
    119112                                % (field.name, name, base.__name__)) 
    120113                    new_class.add_to_class(field.name, copy.deepcopy(field)) 
    121114 
     115            # Copy managers from the base model. 
     116            for mgr_attr, mgr in base._meta.managers.iteritems(): 
     117                if mgr_attr in new_class.__dict__: 
     118                    continue 
     119                new_class.add_to_class(mgr_attr, copy.copy(mgr)) 
     120 
    122121        if abstract: 
    123122            # Abstract base models can't be instantiated and don't appear in 
    124123            # the list of models for an app. We do the final setup for them a 
     
    127126            new_class.Meta = attr_meta 
    128127            return new_class 
    129128 
    130         if old_default_mgr and not new_class._default_manager: 
    131             new_class._default_manager = old_default_mgr._copy_to_model(new_class) 
    132129        new_class._prepare() 
    133130        register_models(new_class._meta.app_label, new_class) 
    134131 
  • django/db/models/manager.py

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

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

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

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