Ticket #7154: 7154.copy-managers.r7884.diff
File 7154.copy-managers.r7884.diff, 9.3 KB (added by , 16 years ago) |
---|
-
django/db/models/base.py
109 109 new_class.add_to_class(attr_name, field) 110 110 new_class._meta.parents[base] = field 111 111 else: 112 # The abstract base class case.112 # Copy fields from the abstract base class. 113 113 names = set([f.name for f in new_class._meta.local_fields + new_class._meta.many_to_many]) 114 114 for field in base._meta.local_fields + base._meta.local_many_to_many: 115 115 if field.name in names: … … 117 117 % (field.name, name, base.__name__)) 118 118 new_class.add_to_class(field.name, copy.deepcopy(field)) 119 119 120 # Copy managers from the base model. 121 for mgr_attr, mgr in base._meta.managers.iteritems(): 122 if mgr_attr in new_class.__dict__: 123 continue 124 new_class.add_to_class(mgr_attr, copy.copy(mgr)) 125 120 126 if abstract: 121 127 # Abstract base models can't be instantiated and don't appear in 122 128 # the list of models for an app. We do the final setup for them a … … 126 132 return new_class 127 133 128 134 if old_default_mgr and not new_class._default_manager: 129 new_class._default_manager = old_default_mgr._copy_to_model(new_class) 135 new_class.add_to_class('_default_manager', copy.copy(old_default_mgr)) 136 130 137 new_class._prepare() 131 138 register_models(new_class._meta.app_label, new_class) 132 139 -
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 146 class C(models.Model): 147 pass 148 149 class DManager(models.Manager): 150 pass 151 152 class D(C): 153 objects = DManager() 154 119 155 __test__ = {'API_TESTS':""" 120 156 # The Student and Worker models both have 'name' and 'age' fields on them and 121 157 # inherit the __unicode__() method, just as with normal Python subclassing. … … 125 161 126 162 >>> w = Worker(name='Fred', age=35, job='Quarry worker') 127 163 >>> w.save() 128 >>> w2 = Worker(name='Barney', age= 34, job='Quarry worker')164 >>> w2 = Worker(name='Barney', age=20, job='Quarry worker') 129 165 >>> w2.save() 130 166 >>> s = Student(name='Pebbles', age=5, school_class='1B') 131 167 >>> s.save() … … 144 180 >>> Student._meta.ordering 145 181 [] 146 182 183 # The children inherit the custom managers from their parents, but children can 184 # still override it. 185 >>> Student(name='Bill', age=18, school_class='11A').save() 186 >>> Student.adults.all() 187 [<Student: Student Bill>] 188 189 >>> Worker.adults.all() 190 [<Worker: Worker Fred>] 191 147 192 # However, the CommonInfo class cannot be used as a normal model (it doesn't 148 193 # exist as a model). 149 194 >>> CommonInfo.objects.all() … … 309 354 3 310 355 >>> settings.DEBUG = False 311 356 357 >>> isinstance(B._default_manager, PositiveBManager) 358 True 359 360 >>> isinstance(D._default_manager, DManager) 361 True 362 363 >>> D._default_manager.model 364 <class 'modeltests.model_inheritance.models.D'> 365 312 366 """}