1
0
mirror of https://github.com/django/django.git synced 2025-07-05 02:09:13 +00:00

magic-removal: Added descriptor code for assignment of related object sets (Reporter.article_set = [a,b,c]).

git-svn-id: http://code.djangoproject.com/svn/django/branches/magic-removal@2510 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Russell Keith-Magee 2006-03-12 03:58:11 +00:00
parent 9460c54e22
commit a5bd0543f1
4 changed files with 68 additions and 11 deletions

View File

@ -94,6 +94,8 @@ class SingleRelatedObjectDescriptor(object):
return rel_obj return rel_obj
def __set__(self, instance, value): def __set__(self, instance, value):
if instance is None:
raise AttributeError, "%s must be accessed via instance" % self.related.opts.object_name
# Set the value of the related field # Set the value of the related field
setattr(value, self.related.field.attname, instance) setattr(value, self.related.field.attname, instance)
@ -126,6 +128,8 @@ class ReverseSingleRelatedObjectDescriptor(object):
return rel_obj return rel_obj
def __set__(self, instance, value): def __set__(self, instance, value):
if instance is None:
raise AttributeError, "%s must be accessed via instance" % self._field.name
# Set the value of the related field # Set the value of the related field
try: try:
val = getattr(value, self.field.rel.get_related_field().attname) val = getattr(value, self.field.rel.get_related_field().attname)
@ -197,6 +201,18 @@ class ForeignRelatedObjectsDescriptor(object):
return manager return manager
def __set__(self, instance, value):
if instance is None:
raise AttributeError, "Manager must be accessed via instance"
manager = self.__get__(instance)
# If the foreign key can support nulls, then completely clear the related set.
# Otherwise, just move the named objects into the set.
if self.related.field.null:
manager.clear()
for obj in value:
manager.add(obj)
def _add_m2m_items(rel_manager_inst, managerclass, rel_model, join_table, source_col_name, def _add_m2m_items(rel_manager_inst, managerclass, rel_model, join_table, source_col_name,
target_col_name, source_pk_val, *objs): target_col_name, source_pk_val, *objs):
# Utility function used by the ManyRelatedObjectsDescriptors # Utility function used by the ManyRelatedObjectsDescriptors
@ -329,6 +345,15 @@ class ManyRelatedObjectsDescriptor(object):
return manager return manager
def __set__(self, instance, value):
if instance is None:
raise AttributeError, "Manager must be accessed via instance"
manager = self.__get__(instance)
manager.clear()
for obj in value:
manager.add(obj)
class ReverseManyRelatedObjectsDescriptor(object): class ReverseManyRelatedObjectsDescriptor(object):
# This class provides the functionality that makes the related-object # This class provides the functionality that makes the related-object
# managers available as attributes on a model class, for fields that have # managers available as attributes on a model class, for fields that have
@ -401,6 +426,15 @@ class ReverseManyRelatedObjectsDescriptor(object):
return manager return manager
def __set__(self, instance, value):
if instance is None:
raise AttributeError, "Manager must be accessed via instance"
manager = self.__get__(instance)
manager.clear()
for obj in value:
manager.add(obj)
class ForeignKey(RelatedField, Field): class ForeignKey(RelatedField, Field):
empty_strings_allowed = False empty_strings_allowed = False
def __init__(self, to, to_field=None, **kwargs): def __init__(self, to, to_field=None, **kwargs):

View File

@ -144,12 +144,19 @@ API_TESTS = """
>>> a5.publications.all() >>> a5.publications.all()
[] []
# You can clear the whole lot: # Relation sets can be assigned. Assignment clears any existing set members
# (put some back first) >>> p2.article_set = [a4, a5]
>>> p2.article_set.add(a4, a5) >>> p2.article_set.all()
>>> a4.publications.add(p3) [NASA finds intelligent life on Earth, Oxygen-free diet works wonders]
>>> a4.publications.all() >>> a4.publications.all()
[Science News, Science Weekly] [Science News]
>>> a4.publications = [p3]
>>> p2.article_set.all()
[Oxygen-free diet works wonders]
>>> a4.publications.all()
[Science Weekly]
# Relation sets can be cleared:
>>> p2.article_set.clear() >>> p2.article_set.clear()
>>> p2.article_set.all() >>> p2.article_set.all()
[] []
@ -196,5 +203,4 @@ API_TESTS = """
>>> p1.article_set.all() >>> p1.article_set.all()
[NASA uses Python] [NASA uses Python]
""" """

View File

@ -83,9 +83,20 @@ John Smith
>>> r2.article_set.all() >>> r2.article_set.all()
[] []
# Set the article back again. # Set the article back again using set descriptor.
>>> new_article2.reporter = r2 >>> r2.article_set = [new_article, new_article2]
>>> new_article2.save() >>> r.article_set.all()
[This is a test]
>>> r2.article_set.all()
[John's second story, Paul's story]
# Funny case - assignment notation can only go so far; because the
# ForeignKey cannot be null, existing members of the set must remain
>>> r.article_set = [new_article]
>>> r.article_set.all()
[This is a test, John's second story]
>>> r2.article_set.all()
[Paul's story]
# Reporter cannot be null - there should not be a clear or remove method # Reporter cannot be null - there should not be a clear or remove method
>>> hasattr(r2.article_set, 'remove') >>> hasattr(r2.article_set, 'remove')

View File

@ -49,7 +49,7 @@ Second
1 1
# Reporter objects have access to their related Article objects. # Reporter objects have access to their related Article objects.
>>> r.article_set.order_by('headline') >>> r.article_set.all()
[First, Second] [First, Second]
>>> r.article_set.filter(headline__startswith='Fir') >>> r.article_set.filter(headline__startswith='Fir')
[First] [First]
@ -111,11 +111,17 @@ DoesNotExist: 'Fourth' is not related to 'John Smith'.
>>> r2.article_set.all() >>> r2.article_set.all()
[Fourth] [Fourth]
# Use descriptor assignment to allocate ForeignKey. Null is legal, so
# existing members of set that are not in the assignment set are set null
>>> r2.article_set = [a2, a3]
>>> r2.article_set.all()
[Second, Third]
# Clear the rest of the set # Clear the rest of the set
>>> r.article_set.clear() >>> r.article_set.clear()
>>> r.article_set.all() >>> r.article_set.all()
[] []
>>> Article.objects.filter(reporter__isnull=True) >>> Article.objects.filter(reporter__isnull=True)
[First, Second, Third] [First, Fourth]
""" """