Kaydet (Commit) df5fef33 authored tarafından Jacob Kaplan-Moss's avatar Jacob Kaplan-Moss

Beefed up support for "lazy" related objects. Now, in addition to…

Beefed up support for "lazy" related objects. Now, in addition to ForeignKey("Model") you can also say ForeignKey("app.Model"). This means that cross-app recursive relations now work.


git-svn-id: http://code.djangoproject.com/svn/django/trunk@7158 bcc190cf-cafb-0310-a4f2-bffc1f526a37
üst 297a12c2
......@@ -23,26 +23,64 @@ RECURSIVE_RELATIONSHIP_CONSTANT = 'self'
pending_lookups = {}
def add_lookup(rel_cls, field):
name = field.rel.to
module = rel_cls.__module__
key = (module, name)
# Has the model already been loaded?
# If so, resolve the string reference right away
model = get_model(rel_cls._meta.app_label, field.rel.to, False)
def add_lazy_relation(cls, field, relation):
"""
Adds a lookup on ``cls`` when a related field is defined using a string,
i.e.::
class MyModel(Model):
fk = ForeignKey("AnotherModel")
This string can be:
* RECURSIVE_RELATIONSHIP_CONSTANT (i.e. "self") to indicate a recursive
relation.
* The name of a model (i.e "AnotherModel") to indicate another model in
the same app.
* An app-label and model name (i.e. "someapp.AnotherModel") to indicate
another model in a different app.
If the other model hasn't yet been loaded -- almost a given if you're using
lazy relationships -- then the relation won't be set up until the
class_prepared signal fires at the end of model initialization.
"""
# Check for recursive relations
if relation == RECURSIVE_RELATIONSHIP_CONSTANT:
app_label = cls._meta.app_label
model_name = cls.__name__
else:
# Look for an "app.Model" relation
try:
app_label, model_name = relation.split(".")
except ValueError:
# If we can't split, assume a model in current app
app_label = cls._meta.app_label
model_name = relation
# Try to look up the related model, and if it's already loaded resolve the
# string right away. If get_model returns None, it means that the related
# model isn't loaded yet, so we need to pend the relation until the class
# is prepared.
model = get_model(app_label, model_name, False)
if model:
field.rel.to = model
field.do_related_class(model, rel_cls)
field.do_related_class(model, cls)
else:
# Mark the related field for later lookup
pending_lookups.setdefault(key, []).append((rel_cls, field))
key = (app_label, model_name)
value = (cls, field)
pending_lookups.setdefault(key, []).append(value)
def do_pending_lookups(sender):
other_cls = sender
key = (other_cls.__module__, other_cls.__name__)
for rel_cls, field in pending_lookups.setdefault(key, []):
field.rel.to = other_cls
field.do_related_class(other_cls, rel_cls)
"""
Handle any pending relations to the sending model. Sent from class_prepared.
"""
key = (sender._meta.app_label, sender.__name__)
for cls, field in pending_lookups.pop(key, []):
field.rel.to = sender
field.do_related_class(sender, cls)
dispatcher.connect(do_pending_lookups, signal=signals.class_prepared)
......@@ -66,9 +104,7 @@ class RelatedField(object):
sup.contribute_to_class(cls, name)
other = self.rel.to
if isinstance(other, basestring):
if other == RECURSIVE_RELATIONSHIP_CONSTANT:
self.rel.to = cls.__name__
add_lookup(cls, self)
add_lazy_relation(cls, self, other)
else:
self.do_related_class(other, cls)
......
"""
24. Mutually referential many-to-one relationships
To define a many-to-one relationship, use ``ForeignKey()`` .
Strings can be used instead of model literals to set up "lazy" relations.
"""
from django.db.models import *
class Parent(Model):
name = CharField(max_length=100, core=True)
# Use a simple string for forward declarations.
bestchild = ForeignKey("Child", null=True, related_name="favoured_by")
class Child(Model):
name = CharField(max_length=100)
parent = ForeignKey(Parent)
# You can also explicitally specify the related app.
parent = ForeignKey("mutually_referential.Parent")
__test__ = {'API_TESTS':"""
# Create a Parent
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment