Django

Code

Ticket #7154: 0003-Now-all-managers-not-only-the-default-manager-gets.patch

File 0003-Now-all-managers-not-only-the-default-manager-gets.patch, 6.6 kB (added by sebastian_noack, 6 months ago)
  • a/django/db/models/base.py

    old new  
    6565                if not hasattr(meta, 'get_latest_by'): 
    6666                    new_class._meta.get_latest_by = base_meta.get_latest_by 
    6767 
    68         old_default_mgr = None 
    69         if getattr(new_class, '_default_manager', None): 
    70             # We have a parent who set the default manager. 
    71             if new_class._default_manager.model._meta.abstract: 
    72                 old_default_mgr = new_class._default_manager 
    73             new_class._default_manager = None 
    7468        if getattr(new_class._meta, 'app_label', None) is None: 
    7569            # Figure out the app_label by looking one level up. 
    7670            # For 'django.contrib.sites.models', this would be 'sites'. 
     
    106100                    new_class.add_to_class(attr_name, field) 
    107101                new_class._meta.parents[base] = field 
    108102            else: 
    109                 # The abstract base class case
     103                # Copy fields from the abstract base class
    110104                names = set([f.name for f in new_class._meta.local_fields + new_class._meta.many_to_many]) 
    111105                for field in base._meta.local_fields + base._meta.local_many_to_many: 
    112106                    if field.name in names: 
     
    114108                                % (field.name, name, base.__name__)) 
    115109                    new_class.add_to_class(field.name, copy.deepcopy(field)) 
    116110 
     111            # Copy managers from the base model. 
     112            for mgr_attr, mgr in base._meta.base_managers.iteritems(): 
     113                if mgr_attr in new_class.__dict__: 
     114                    continue 
     115                new_class.add_to_class(mgr_attr, copy.copy(mgr)) 
     116 
    117117        if abstract: 
    118118            # Abstract base models can't be instantiated and don't appear in 
    119119            # the list of models for an app. We do the final setup for them a 
     
    122122            new_class.Meta = attr_meta 
    123123            return new_class 
    124124 
    125         if old_default_mgr and not new_class._default_manager: 
    126             new_class._default_manager = old_default_mgr._copy_to_model(new_class) 
    127125        new_class._prepare() 
    128126        register_models(new_class._meta.app_label, new_class) 
    129127 
  • a/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         self.model = model 
    35         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 
    38  
    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 
     34        if not model._meta.abstract: 
     35            self.model = model 
     36            setattr(model, name, ManagerDescriptor(self)) 
     37            if not getattr(model, '_default_manager', None) or self.creation_counter == model._default_manager.creation_counter: 
     38                model._default_manager = self 
     39        model._meta.base_managers[name] = self 
    4940 
    5041    ####################### 
    5142    # PROXIES TO QUERYSET # 
  • a/django/db/models/options.py

    old new  
    4444        self.one_to_one_field = None 
    4545        self.abstract = False 
    4646        self.parents = SortedDict() 
     47        self.base_managers = SortedDict() 
    4748 
    4849    def contribute_to_class(self, cls, name): 
    4950        cls._meta = self 
  • a/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): 
     
    102115 
    103116>>> w = Worker(name='Fred', age=35, job='Quarry worker') 
    104117>>> w.save() 
    105 >>> w2 = Worker(name='Barney', age=34, job='Quarry worker') 
     118>>> w2 = Worker(name='Barney', age=20, job='Quarry worker') 
    106119>>> w2.save() 
    107120>>> s = Student(name='Pebbles', age=5, school_class='1B') 
    108121>>> s.save() 
     
    121134>>> Student._meta.ordering 
    122135[] 
    123136 
     137# The children inherit the custom managers from their parents, but children can 
     138# still override it. 
     139>>> Student(name='Bill', age=18, school_class='11A').save() 
     140>>> Student.adults.all() 
     141[<Student: Student Bill>] 
     142 
     143>>> Worker.adults.all() 
     144[<Worker: Worker Fred>] 
     145 
    124146# However, the CommonInfo class cannot be used as a normal model (it doesn't 
    125147# exist as a model). 
    126148>>> CommonInfo.objects.all()