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:
parent
9460c54e22
commit
a5bd0543f1
@ -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):
|
||||||
|
@ -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]
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -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')
|
||||||
|
@ -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]
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
Loading…
x
Reference in New Issue
Block a user