Ticket #7154: 7154.copy-managers.r7818.diff
File 7154.copy-managers.r7818.diff, 9.6 KB (added by , 16 years ago) |
---|
-
django/db/models/base.py
75 75 if not hasattr(meta, 'get_latest_by'): 76 76 new_class._meta.get_latest_by = base_meta.get_latest_by 77 77 78 old_default_mgr = None79 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_manager83 new_class._default_manager = None84 85 78 # Bail out early if we have already created this class. 86 79 m = get_model(new_class._meta.app_label, name, False) 87 80 if m is not None: … … 111 104 new_class.add_to_class(attr_name, field) 112 105 new_class._meta.parents[base] = field 113 106 else: 114 # The abstract base class case.107 # Copy fields from the abstract base class. 115 108 names = set([f.name for f in new_class._meta.local_fields + new_class._meta.many_to_many]) 116 109 for field in base._meta.local_fields + base._meta.local_many_to_many: 117 110 if field.name in names: … … 119 112 % (field.name, name, base.__name__)) 120 113 new_class.add_to_class(field.name, copy.deepcopy(field)) 121 114 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 122 121 if abstract: 123 122 # Abstract base models can't be instantiated and don't appear in 124 123 # the list of models for an app. We do the final setup for them a … … 127 126 new_class.Meta = attr_meta 128 127 return new_class 129 128 130 if old_default_mgr and not new_class._default_manager:131 new_class._default_manager = old_default_mgr._copy_to_model(new_class)132 129 new_class._prepare() 133 130 register_models(new_class._meta.app_label, new_class) 134 131 -
django/db/models/manager.py
31 31 32 32 def contribute_to_class(self, model, name): 33 33 # TODO: Use weakref because of possible memory leak / circular reference. 34 model._meta.managers[name] = self 35 if model._meta.abstract: 36 return 34 37 self.model = model 35 38 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. 38 45 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 49 51 50 52 ####################### 51 53 # PROXIES TO QUERYSET # -
django/db/models/options.py
45 45 self.abstract = False 46 46 self.parents = SortedDict() 47 47 self.duplicate_targets = {} 48 self.managers = {} 48 49 49 50 def contribute_to_class(self, cls, name): 50 51 from django.db import connection -
tests/modeltests/custom_managers/models.py
44 44 45 45 # An example of providing multiple custom managers. 46 46 47 class SlowCarManager(models.Manager): 48 def get_query_set(self): 49 return super(SlowCarManager, self).get_query_set().filter(top_speed__lte=124) 50 51 class MediumFastCarManager(models.Manager): 52 def get_query_set(self): 53 return super(MediumFastCarManager, self).get_query_set().filter(top_speed__range=(125, 149)) 54 47 55 class FastCarManager(models.Manager): 48 56 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)) 50 58 59 class VeryFastCarManager(models.Manager): 60 def get_query_set(self): 61 return super(VeryFastCarManager, self).get_query_set().filter(top_speed__range=(175, 199)) 62 63 class ReallyFastCarManager(models.Manager): 64 def get_query_set(self): 65 return super(ReallyFastCarManager, self).get_query_set().filter(top_speed__gte=200) 66 51 67 class Car(models.Model): 52 68 name = models.CharField(max_length=10) 53 69 mileage = models.IntegerField() 54 70 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. 55 74 cars = models.Manager() 75 slow_cars = SlowCarManager() 76 medium_fast_cars = MediumFastCarManager() 56 77 fast_cars = FastCarManager() 78 very_fast_cars = VeryFastCarManager() 79 really_fast_cars = ReallyFastCarManager() 57 80 58 81 def __unicode__(self): 59 82 return self.name … … 90 113 91 114 >>> Book.published_objects.all() 92 115 [<Book: How to program>] 93 94 116 >>> c1 = Car(name='Corvette', mileage=21, top_speed=180) 95 117 >>> c1.save() 96 118 >>> c2 = Car(name='Neon', mileage=31, top_speed=100) 97 119 >>> c2.save() 98 120 >>> Car.cars.order_by('name') 99 121 [<Car: Corvette>, <Car: Neon>] 100 >>> Car. fast_cars.all()122 >>> Car.very_fast_cars.all() 101 123 [<Car: Corvette>] 102 124 103 125 # 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 107 130 """} -
tests/modeltests/model_inheritance/models.py
18 18 # Abstract base classes 19 19 # 20 20 21 class AdultManager(models.Manager): 22 def get_query_set(self): 23 return super(AdultManager, self).get_query_set().filter(age__gte=18) 24 25 class Adult21Manager(models.Manager): 26 def get_query_set(self): 27 return super(Adult21Manager, self).get_query_set().filter(age__gte=21) 28 21 29 class CommonInfo(models.Model): 22 30 name = models.CharField(max_length=50) 23 31 age = models.PositiveIntegerField() 24 32 33 objects = models.Manager() 34 adults = AdultManager() 35 25 36 class Meta: 26 37 abstract = True 27 38 ordering = ['name'] … … 30 41 return u'%s %s' % (self.__class__.__name__, self.name) 31 42 32 43 class Worker(CommonInfo): 44 adults = Adult21Manager() 45 33 46 job = models.CharField(max_length=50) 34 47 35 48 class Student(CommonInfo): … … 115 128 116 129 def __unicode__(self): 117 130 return u"%s the parking lot" % self.name 131 132 class A(models.Model): 133 a = models.IntegerField() 118 134 135 class Meta: 136 abstract = True 137 138 class PositiveBManager(models.Manager): 139 def get_query_set(self): 140 return super(PositiveBManager, self).get_query_set().filter(b__gte=0) 141 142 class B(A): 143 b = models.IntegerField() 144 positive = PositiveBManager() 145 119 146 __test__ = {'API_TESTS':""" 120 147 # The Student and Worker models both have 'name' and 'age' fields on them and 121 148 # inherit the __unicode__() method, just as with normal Python subclassing. … … 125 152 126 153 >>> w = Worker(name='Fred', age=35, job='Quarry worker') 127 154 >>> w.save() 128 >>> w2 = Worker(name='Barney', age= 34, job='Quarry worker')155 >>> w2 = Worker(name='Barney', age=20, job='Quarry worker') 129 156 >>> w2.save() 130 157 >>> s = Student(name='Pebbles', age=5, school_class='1B') 131 158 >>> s.save() … … 144 171 >>> Student._meta.ordering 145 172 [] 146 173 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 147 183 # However, the CommonInfo class cannot be used as a normal model (it doesn't 148 184 # exist as a model). 149 185 >>> CommonInfo.objects.all() … … 309 345 3 310 346 >>> settings.DEBUG = False 311 347 348 >>> isinstance(B._default_manager, PositiveBManager) 349 True 350 312 351 """}