mirror of
				https://github.com/django/django.git
				synced 2025-10-31 01:25:32 +00:00 
			
		
		
		
	Fixed #8279 -- Multiple many-to-many relations to "self" are now possible.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@8721 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
		| @@ -716,7 +716,7 @@ class OneToOneField(ForeignKey): | ||||
|                 SingleRelatedObjectDescriptor(related)) | ||||
|         if not cls._meta.one_to_one_field: | ||||
|             cls._meta.one_to_one_field = self | ||||
|      | ||||
|  | ||||
|     def formfield(self, **kwargs): | ||||
|         if self.rel.parent_link: | ||||
|             return None | ||||
| @@ -844,6 +844,15 @@ class ManyToManyField(RelatedField, Field): | ||||
|         return smart_unicode(data) | ||||
|  | ||||
|     def contribute_to_class(self, cls, name): | ||||
|         # To support multiple relations to self, it's useful to have a non-None | ||||
|         # related name on symmetrical relations for internal reasons. The | ||||
|         # concept doesn't make a lot of sense externally ("you want me to | ||||
|         # specify *what* on my non-reversible relation?!"), so we set it up | ||||
|         # automatically. The funky name reduces the chance of an accidental | ||||
|         # clash. | ||||
|         if self.rel.symmetrical and self.rel.related_name is None: | ||||
|             self.rel.related_name = "%s_rel_+" % name | ||||
|  | ||||
|         super(ManyToManyField, self).contribute_to_class(cls, name) | ||||
|         # Add the descriptor for the m2m relation | ||||
|         setattr(cls, self.name, ReverseManyRelatedObjectsDescriptor(self)) | ||||
|   | ||||
							
								
								
									
										0
									
								
								tests/regressiontests/m2m_regress/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								tests/regressiontests/m2m_regress/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										56
									
								
								tests/regressiontests/m2m_regress/models.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								tests/regressiontests/m2m_regress/models.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| from django.db import models | ||||
|  | ||||
| # No related name is needed here, since symmetrical relations are not | ||||
| # explicitly reversible. | ||||
| class SelfRefer(models.Model): | ||||
|     name = models.CharField(max_length=10) | ||||
|     references = models.ManyToManyField('self') | ||||
|     related = models.ManyToManyField('self') | ||||
|  | ||||
|     def __unicode__(self): | ||||
|         return self.name | ||||
|  | ||||
| class Tag(models.Model): | ||||
|     name = models.CharField(max_length=10) | ||||
|  | ||||
|     def __unicode__(self): | ||||
|         return self.name | ||||
|  | ||||
| # A related_name is required on one of the ManyToManyField entries here because | ||||
| # they are both addressable as reverse relations from Tag. | ||||
| class Entry(models.Model): | ||||
|     name = models.CharField(max_length=10) | ||||
|     topics = models.ManyToManyField(Tag) | ||||
|     related = models.ManyToManyField(Tag, related_name="similar") | ||||
|  | ||||
|     def __unicode__(self): | ||||
|         return self.name | ||||
|  | ||||
| __test__ = {"regressions": """ | ||||
| # Multiple m2m references to the same model or a different model must be | ||||
| # distinguished when accessing the relations through an instance attribute. | ||||
|  | ||||
| >>> s1 = SelfRefer.objects.create(name='s1') | ||||
| >>> s2 = SelfRefer.objects.create(name='s2') | ||||
| >>> s3 = SelfRefer.objects.create(name='s3') | ||||
| >>> s1.references.add(s2) | ||||
| >>> s1.related.add(s3) | ||||
|  | ||||
| >>> e1 = Entry.objects.create(name='e1') | ||||
| >>> t1 = Tag.objects.create(name='t1') | ||||
| >>> t2 = Tag.objects.create(name='t2') | ||||
| >>> e1.topics.add(t1) | ||||
| >>> e1.related.add(t2) | ||||
|  | ||||
| >>> s1.references.all() | ||||
| [<SelfRefer: s2>] | ||||
| >>> s1.related.all() | ||||
| [<SelfRefer: s3>] | ||||
|  | ||||
| >>> e1.topics.all() | ||||
| [<Tag: t1>] | ||||
| >>> e1.related.all() | ||||
| [<Tag: t2>] | ||||
|  | ||||
| """ | ||||
| } | ||||
		Reference in New Issue
	
	Block a user