Ticket #14270: 14270-m2m-cleanup-r16522.diff
File 14270-m2m-cleanup-r16522.diff, 9.9 KB (added by , 13 years ago) |
---|
-
tests/regressiontests/m2m_regress/tests.py
73 73 74 74 self.assertQuerysetEqual(c1.tags.all(), ["<Tag: t1>", "<Tag: t2>"]) 75 75 self.assertQuerysetEqual(t1.tag_collections.all(), ["<TagCollection: c1>"]) 76 77 def test_manager_class(self): 78 e1 = Entry.objects.create() 79 e2 = Entry.objects.create() 80 t1 = Tag.objects.create() 81 t2 = Tag.objects.create() 82 self.assertTrue(e1.topics.__class__ is e1.topics.__class__) 83 self.assertTrue(e2.topics.__class__ is e2.topics.__class__) 84 85 self.assertTrue(t1.entry_set.__class__ is t1.entry_set.__class__) 86 self.assertTrue(t1.entry_set.__class__ is t2.entry_set.__class__) -
django/db/models/fields/related.py
11 11 from django.utils.encoding import smart_unicode 12 12 from django.utils.translation import (ugettext_lazy as _, string_concat, 13 13 ungettext, ugettext) 14 from django.utils.functional import curry 14 from django.utils.functional import curry, cached_property, memoize 15 15 from django.core import exceptions 16 16 from django import forms 17 17 … … 387 387 def __get__(self, instance, instance_type=None): 388 388 if instance is None: 389 389 return self 390 manager = self.create_manager( 391 self.related.model._default_manager.__class__ 392 ) 393 return manager(instance) 390 394 391 return self.create_manager(instance,392 self.related.model._default_manager.__class__)393 394 395 def __set__(self, instance, value): 395 396 if instance is None: 396 397 raise AttributeError("Manager must be accessed via instance") … … 408 409 than the default manager, as returned by __get__). Used by 409 410 Model.delete(). 410 411 """ 411 return self.create_manager(instance,412 self.related.model._base_manager.__class__)412 manager = self.create_manager(self.related.model._base_manager.__class__) 413 return manager(instance) 413 414 414 def create_manager(self, instance,superclass):415 def create_manager(self, superclass): 415 416 """ 416 417 Creates the managers used by other methods (__get__() and delete()). 417 418 """ … … 419 420 rel_model = self.related.model 420 421 421 422 class RelatedManager(superclass): 423 def __init__(self, instance): 424 super(RelatedManager, self).__init__() 425 attname = rel_field.rel.get_related_field().name 426 self.instance = instance 427 self.core_filters = { 428 '%s__%s' % (rel_field.name, attname): getattr(instance, attname) 429 } 430 self.model = rel_model 431 422 432 def get_query_set(self): 423 db = self._db or router.db_for_read(rel_model, instance=instance) 424 return superclass.get_query_set(self).using(db).filter(**(self.core_filters)) 433 db = self._db or router.db_for_read( 434 rel_model, instance=self.instance 435 ) 436 return superclass.get_query_set(self).using(db).filter(**self.core_filters) 425 437 426 438 def add(self, *objs): 427 439 for obj in objs: 428 440 if not isinstance(obj, self.model): 429 441 raise TypeError("'%s' instance expected" % self.model._meta.object_name) 430 setattr(obj, rel_field.name, instance)442 setattr(obj, rel_field.name, self.instance) 431 443 obj.save() 432 444 add.alters_data = True 433 445 434 446 def create(self, **kwargs): 435 kwargs.update({rel_field.name: instance})436 db = router.db_for_write(rel_model, instance= instance)447 kwargs.update({rel_field.name: self.instance}) 448 db = router.db_for_write(rel_model, instance=self.instance) 437 449 return super(RelatedManager, self.db_manager(db)).create(**kwargs) 438 450 create.alters_data = True 439 451 440 452 def get_or_create(self, **kwargs): 441 453 # Update kwargs with the related object that this 442 454 # ForeignRelatedObjectsDescriptor knows about. 443 kwargs.update({rel_field.name: instance})444 db = router.db_for_write(rel_model, instance= instance)455 kwargs.update({rel_field.name: self.instance}) 456 db = router.db_for_write(rel_model, instance=self.instance) 445 457 return super(RelatedManager, self.db_manager(db)).get_or_create(**kwargs) 446 458 get_or_create.alters_data = True 447 459 448 # remove() and clear() are only provided if the ForeignKey can have a value of null. 460 # remove() and clear() are only provided if the ForeignKey can have 461 # a value of null. 449 462 if rel_field.null: 450 463 def remove(self, *objs): 451 val = getattr( instance, rel_field.rel.get_related_field().attname)464 val = getattr(self.instance, rel_field.rel.get_related_field().attname) 452 465 for obj in objs: 453 466 # Is obj actually part of this descriptor set? 454 467 if getattr(obj, rel_field.attname) == val: 455 468 setattr(obj, rel_field.name, None) 456 469 obj.save() 457 470 else: 458 raise rel_field.rel.to.DoesNotExist("%r is not related to %r." % (obj, instance))471 raise rel_field.rel.to.DoesNotExist("%r is not related to %r." % (obj, self.instance)) 459 472 remove.alters_data = True 460 473 461 474 def clear(self): 462 475 self.update(**{rel_field.name: None}) 463 476 clear.alters_data = True 464 477 465 manager = RelatedManager() 466 attname = rel_field.rel.get_related_field().name 467 manager.core_filters = {'%s__%s' % (rel_field.name, attname): 468 getattr(instance, attname)} 469 manager.model = self.related.model 478 return RelatedManager 479 create_manager = memoize(create_manager, {}, 2) 470 480 471 return manager472 473 481 def create_many_related_manager(superclass, rel=False): 474 482 """Creates a manager that subclasses 'superclass' (which is a Manager) 475 483 and adds behavior for many-to-many related objects.""" … … 657 665 # ManyRelatedObjectsDescriptor instance. 658 666 def __init__(self, related): 659 667 self.related = related # RelatedObject instance 668 669 @cached_property 670 def related_manager_cls(self): 671 # Dynamically create a class that subclasses the related 672 # model's default manager. 673 return create_many_related_manager( 674 self.related.model._default_manager.__class__, 675 self.related.field.rel 676 ) 660 677 661 678 def __get__(self, instance, instance_type=None): 662 679 if instance is None: 663 680 return self 664 681 665 # Dynamically create a class that subclasses the related666 # model's default manager.667 682 rel_model = self.related.model 668 superclass = rel_model._default_manager.__class__ 669 RelatedManager = create_many_related_manager(superclass, self.related.field.rel) 670 671 manager = RelatedManager( 683 manager = self.related_manager_cls( 672 684 model=rel_model, 673 685 core_filters={'%s__pk' % self.related.field.name: instance._get_pk_val()}, 674 686 instance=instance, … … 702 714 # ReverseManyRelatedObjectsDescriptor instance. 703 715 def __init__(self, m2m_field): 704 716 self.field = m2m_field 717 718 @cached_property 719 def related_manager_cls(self): 720 # Dynamically create a class that subclasses the related model's 721 # default manager. 722 return create_many_related_manager( 723 self.field.rel.to._default_manager.__class__, 724 self.field.rel 725 ) 705 726 706 727 def _through(self): 707 728 # through is provided so that you have easy access to the through … … 713 734 def __get__(self, instance, instance_type=None): 714 735 if instance is None: 715 736 return self 716 717 # Dynamically create a class that subclasses the related 718 # model's default manager. 719 rel_model=self.field.rel.to 720 superclass = rel_model._default_manager.__class__ 721 RelatedManager = create_many_related_manager(superclass, self.field.rel) 722 723 manager = RelatedManager( 724 model=rel_model, 737 738 manager = self.related_manager_cls( 739 model=self.field.rel.to, 725 740 core_filters={'%s__pk' % self.field.related_query_name(): instance._get_pk_val()}, 726 741 instance=instance, 727 742 symmetrical=self.field.rel.symmetrical, … … 1041 1056 if hasattr(self, cache_attr): 1042 1057 return getattr(self, cache_attr) 1043 1058 for f in self.rel.through._meta.fields: 1044 if hasattr(f, 'rel') and f.rel and f.rel.to == related.model:1059 if hasattr(f, 'rel') and f.rel and f.rel.to == related.model: 1045 1060 setattr(self, cache_attr, getattr(f, attr)) 1046 1061 return getattr(self, cache_attr) 1047 1062 -
django/utils/functional.py
28 28 return result 29 29 return wrapper 30 30 31 class cached_property(object): 32 def __init__(self, func): 33 self.func = func 34 35 def __get__(self, instance, type): 36 res = instance.__dict__[self.func.__name__] = self.func(instance) 37 return res 38 31 39 class Promise(object): 32 40 """ 33 41 This is just a base class for the proxy class created in