Ticket #3688: recursive-related-fields-4692v2.diff

File recursive-related-fields-4692v2.diff, 6.5 KB (added by Ben Slavin <benjamin.slavin@…>, 8 years ago)

Modification based on Ramiro's suggestion. Also fixed a slight typo in the docs (use of : instead of ::)

  • django/db/models/fields/related.py

     
    66from django.utils.translation import gettext_lazy, string_concat, ngettext
    77from django.utils.functional import curry
    88from django.core import validators
     9from django.core.exceptions import ImproperlyConfigured
    910from django import oldforms
    1011from django import newforms as forms
    1112from django.dispatch import dispatcher
     
    2324
    2425def add_lookup(rel_cls, field):
    2526    name = field.rel.to
    26     module = rel_cls.__module__
    27     key = (module, name)
     27    # name should be either the name of a model in the same application or the
     28    # name of a model in another application referenced with standard Django
     29    # dotted notation ('appname.modelname')
     30    if name.find('.') is -1:
     31        app_name = rel_cls._meta.app_label
     32        model_name = name
     33    else:
     34        try:
     35            app_name, model_name = name.split('.')
     36        except ValueError:
     37            raise ImproperlyConfigured, "Invalid definition for field %s (%s). Please use app_name.model_name notation." % (field.name, name)
     38    key = (app_name, model_name)
    2839    # Has the model already been loaded?
    2940    # If so, resolve the string reference right away
    30     model = get_model(rel_cls._meta.app_label, field.rel.to, False)
     41    model = get_model(app_name, model_name, False)
    3142    if model:
    3243        field.rel.to = model
    3344        field.do_related_class(model, rel_cls)
     
    3748
    3849def do_pending_lookups(sender):
    3950    other_cls = sender
    40     key = (other_cls.__module__, other_cls.__name__)
     51    key = (other_cls._meta.app_label, other_cls.__name__)
    4152    for rel_cls, field in pending_lookups.setdefault(key, []):
    4253        field.rel.to = other_cls
    4354        field.do_related_class(other_cls, rel_cls)
  • docs/model-api.txt

     
    682682        manufacturer = models.ForeignKey(Manufacturer)
    683683        # ...
    684684
    685 To create a recursive relationship -- an object that has a many-to-one
    686 relationship with itself -- use ``models.ForeignKey('self')``.
     685For information on establishing relationships to ``self``, and as-of-yet
     686undefined models, see `recursive relationships`_ below.
    687687
    688 If you need to create a relationship on a model that has not yet been defined,
    689 you can use the name of the model, rather than the model object itself::
    690 
    691     class Car(models.Model):
    692         manufacturer = models.ForeignKey('Manufacturer')
    693         # ...
    694 
    695     class Manufacturer(models.Model):
    696         # ...
    697 
    698 Note, however, that you can only use strings to refer to models in the same
    699 models.py file -- you cannot use a string to reference a model in a different
    700 application, or to reference a model that has been imported from elsewhere.
    701 
    702688Behind the scenes, Django appends ``"_id"`` to the field name to create its
    703689database column name. In the above example, the database table for the ``Car``
    704690model will have a ``manufacturer_id`` column. (You can change this explicitly
     
    817803        # ...
    818804        toppings = models.ManyToManyField(Topping)
    819805
    820 As with ``ForeignKey``, a relationship to self can be defined by using the
    821 string ``'self'`` instead of the model name, and you can refer to as-yet
    822 undefined models by using a string containing the model name. However, you
    823 can only use strings to refer to models in the same models.py file -- you
    824 cannot use a string to reference a model in a different application, or to
    825 reference a model that has been imported from elsewhere.
    826 
     806For information on establishing relationships to ``self``, and as-of-yet
     807undefined models, see `recursive relationships`_ below.
     808               
    827809It's suggested, but not required, that the name of a ``ManyToManyField``
    828810(``toppings`` in the example above) be a plural describing the set of related
    829811model objects.
     
    910892could make ``Restaurant`` have a ``OneToOneField`` to ``Place`` (because a
    911893restaurant "is-a" place).
    912894
    913 As with ``ForeignKey``, a relationship to self can be defined by using the
    914 string ``"self"`` instead of the model name; references to as-yet undefined
    915 models can be made by using a string containing the model name.
     895For information on establishing relationships to as-of-yet undefined models,
     896see `recursive relationships`_ below.
    916897
    917898This ``OneToOneField`` will actually replace the primary key ``id`` field
    918899(since one-to-one relations share the same primary key), and will be displayed
     
    922903
    923904.. _One-to-one relationship model example: http://www.djangoproject.com/documentation/models/one_to_one/
    924905
     906Recursive relationships
     907~~~~~~~~~~~~~~~~~~~~~~~
     908To create a recursive relationship -- an object that has a many-to-one
     909relationship with itself -- use ``models.ForeignKey('self')`` or
     910``models.ManyToMany('self')``
     911
     912If you need to create a relationship on a model that has not yet been defined,
     913you can use the name of the model, rather than the model object itself::
     914
     915    class Car(models.Model):
     916        manufacturer = models.ForeignKey('Manufacturer')
     917        # ...
     918
     919    class Manufacturer(models.Model):
     920        # ...
     921
     922Note, however, that you can only use strings to refer to models in the same
     923models.py file -- you cannot use a string to reference a model in a different
     924application, or to reference a model that has been imported from elsewhere.
     925
     926**New in Django development version:** String-based references have been
     927expanded to allow reference to models in other models.py files.  This usage
     928provides a mechanism for enabling recursive relationships between
     929tightly-coupled objects that logically reside in different applications.
     930
     931For example, consider a user class and a series of articles::
     932
     933        class User(models.Model):
     934                saved_articles = models.ManyToManyField('Article')
     935                # ...
     936
     937        class Article(models.Model):
     938                author = models.ForeignKey(User)
     939                # ...
     940
     941It doesn't make much sense for users and articles to be stored in the same
     942models.py file.  By using dotted-notation (``app_name.model_name``), it is
     943possible to reference across models.py files when recursive ``import``
     944statements would otherwise cause problems.
     945
     946my_project/accounts/models.py::
     947
     948        class User(models.Model):
     949                saved_articles = models.ManyToManyField('articles.Article')
     950                # ...
     951
     952my_project/articles/models.py::
     953
     954        class Article(models.Model):
     955                author = models.ForeignKey('accounts.User')
     956                # ...
     957
    925958Meta options
    926959============
    927960
Back to Top