Fixed #7215 -- Create correct reverse-relation accessors when using abstract base classes. Patch from Joel Watts.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7762 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
ba015e0a79
commit
d2ce1df08f
1
AUTHORS
1
AUTHORS
|
@ -376,6 +376,7 @@ answer newbie questions, and generally made Django that much better:
|
||||||
Wang Chun <wangchun@exoweb.net>
|
Wang Chun <wangchun@exoweb.net>
|
||||||
Filip Wasilewski <filip.wasilewski@gmail.com>
|
Filip Wasilewski <filip.wasilewski@gmail.com>
|
||||||
Dan Watson <http://theidioteque.net/>
|
Dan Watson <http://theidioteque.net/>
|
||||||
|
Joel Watts <joel@joelwatts.com>
|
||||||
Chris Wesseling <Chris.Wesseling@cwi.nl>
|
Chris Wesseling <Chris.Wesseling@cwi.nl>
|
||||||
James Wheare <django@sparemint.com>
|
James Wheare <django@sparemint.com>
|
||||||
charly.wilhelm@gmail.com
|
charly.wilhelm@gmail.com
|
||||||
|
|
|
@ -103,13 +103,15 @@ class RelatedField(object):
|
||||||
|
|
||||||
if hasattr(sup, 'contribute_to_class'):
|
if hasattr(sup, 'contribute_to_class'):
|
||||||
sup.contribute_to_class(cls, name)
|
sup.contribute_to_class(cls, name)
|
||||||
|
|
||||||
|
if not cls._meta.abstract and self.rel.related_name:
|
||||||
|
self.rel.related_name = self.rel.related_name % {'class': cls.__name__.lower()}
|
||||||
|
|
||||||
other = self.rel.to
|
other = self.rel.to
|
||||||
if isinstance(other, basestring):
|
if isinstance(other, basestring):
|
||||||
add_lazy_relation(cls, self, other)
|
add_lazy_relation(cls, self, other)
|
||||||
else:
|
else:
|
||||||
self.do_related_class(other, cls)
|
self.do_related_class(other, cls)
|
||||||
if not cls._meta.abstract and self.rel.related_name:
|
|
||||||
self.rel.related_name = self.rel.related_name % {'class': cls.__name__.lower()}
|
|
||||||
|
|
||||||
def set_attributes_from_rel(self):
|
def set_attributes_from_rel(self):
|
||||||
self.name = self.name or (self.rel.to._meta.object_name.lower() + '_' + self.rel.to._meta.pk.name)
|
self.name = self.name or (self.rel.to._meta.object_name.lower() + '_' + self.rel.to._meta.pk.name)
|
||||||
|
@ -119,6 +121,7 @@ class RelatedField(object):
|
||||||
def do_related_class(self, other, cls):
|
def do_related_class(self, other, cls):
|
||||||
self.set_attributes_from_rel()
|
self.set_attributes_from_rel()
|
||||||
related = RelatedObject(other, cls, self)
|
related = RelatedObject(other, cls, self)
|
||||||
|
if not cls._meta.abstract:
|
||||||
self.contribute_to_related_class(other, related)
|
self.contribute_to_related_class(other, related)
|
||||||
|
|
||||||
def get_db_prep_lookup(self, lookup_type, value):
|
def get_db_prep_lookup(self, lookup_type, value):
|
||||||
|
|
|
@ -38,6 +38,29 @@ class Student(CommonInfo):
|
||||||
class Meta:
|
class Meta:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
#
|
||||||
|
# Abstract base classes with related models
|
||||||
|
#
|
||||||
|
|
||||||
|
class Post(models.Model):
|
||||||
|
title = models.CharField(max_length=50)
|
||||||
|
|
||||||
|
class Attachment(models.Model):
|
||||||
|
post = models.ForeignKey(Post, related_name='attached_%(class)s_set')
|
||||||
|
content = models.TextField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return self.content
|
||||||
|
|
||||||
|
class Comment(Attachment):
|
||||||
|
is_spam = models.BooleanField()
|
||||||
|
|
||||||
|
class Link(Attachment):
|
||||||
|
url = models.URLField()
|
||||||
|
|
||||||
#
|
#
|
||||||
# Multi-table inheritance
|
# Multi-table inheritance
|
||||||
#
|
#
|
||||||
|
@ -128,9 +151,25 @@ Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
AttributeError: type object 'CommonInfo' has no attribute 'objects'
|
AttributeError: type object 'CommonInfo' has no attribute 'objects'
|
||||||
|
|
||||||
# The Place/Restaurant/ItalianRestaurant models, on the other hand, all exist
|
# Create a Post
|
||||||
# as independent models. However, the subclasses also have transparent access
|
>>> post = Post(title='Lorem Ipsum')
|
||||||
# to the fields of their ancestors.
|
>>> post.save()
|
||||||
|
|
||||||
|
# The Post model has distinct accessors for the Comment and Link models.
|
||||||
|
>>> post.attached_comment_set.create(content='Save $ on V1agr@', is_spam=True)
|
||||||
|
<Comment: Save $ on V1agr@>
|
||||||
|
>>> post.attached_link_set.create(content='The Web framework for perfectionists with deadlines.', url='http://www.djangoproject.com/')
|
||||||
|
<Link: The Web framework for perfectionists with deadlines.>
|
||||||
|
|
||||||
|
# The Post model doesn't have an attribute called 'attached_%(class)s_set'.
|
||||||
|
>>> getattr(post, 'attached_%(class)s_set')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
AttributeError: 'Post' object has no attribute 'attached_%(class)s_set'
|
||||||
|
|
||||||
|
# The Place/Restaurant/ItalianRestaurant models all exist as independent
|
||||||
|
# models. However, the subclasses also have transparent access to the fields of
|
||||||
|
# their ancestors.
|
||||||
|
|
||||||
# Create a couple of Places.
|
# Create a couple of Places.
|
||||||
>>> p1 = Place(name='Master Shakes', address='666 W. Jersey')
|
>>> p1 = Place(name='Master Shakes', address='666 W. Jersey')
|
||||||
|
|
Loading…
Reference in New Issue