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

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

Patch described above.

  • 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 `recursive relationships`_, see below.
    687686
    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 
    702687Behind the scenes, Django appends ``"_id"`` to the field name to create its
    703688database column name. In the above example, the database table for the ``Car``
    704689model will have a ``manufacturer_id`` column. (You can change this explicitly
     
    817802        # ...
    818803        toppings = models.ManyToManyField(Topping)
    819804
    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.
     805For information on `recursive relationships`_, see below.
    826806
    827807It's suggested, but not required, that the name of a ``ManyToManyField``
    828808(``toppings`` in the example above) be a plural describing the set of related
     
    910890could make ``Restaurant`` have a ``OneToOneField`` to ``Place`` (because a
    911891restaurant "is-a" place).
    912892
    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.
     893For information on `recursive relationships`_, see below.
    916894
    917895This ``OneToOneField`` will actually replace the primary key ``id`` field
    918896(since one-to-one relations share the same primary key), and will be displayed
     
    922900
    923901.. _One-to-one relationship model example: http://www.djangoproject.com/documentation/models/one_to_one/
    924902
     903Recursive relationships
     904~~~~~~~~~~~~~~~~~~~~~~~
     905To create a recursive relationship -- an object that has a many-to-one
     906relationship with itself -- use ``models.ForeignKey('self')``.
     907
     908If you need to create a relationship on a model that has not yet been defined,
     909you can use the name of the model, rather than the model object itself::
     910
     911    class Car(models.Model):
     912        manufacturer = models.ForeignKey('Manufacturer')
     913        # ...
     914
     915    class Manufacturer(models.Model):
     916        # ...
     917
     918Note, however, that you can only use strings to refer to models in the same
     919models.py file -- you cannot use a string to reference a model in a different
     920application, or to reference a model that has been imported from elsewhere.
     921
     922**New in Django development version:** String-based references have been
     923expanded to allow reference to models in other models.py files.  This usage
     924provides a mechanism for enabling recursive relationships between
     925tightly-coupled objects that logically reside in different applications.
     926
     927For example, consider a user class and a series of articles:
     928
     929        class User(models.Model):
     930                saved_articles = models.ManyToManyField('Article')
     931                # ...
     932
     933        class Article(models.Model):
     934                author = models.ForeignKey(User)
     935                # ...
     936
     937It doesn't make much sense for users and articles to be stored in the same
     938models.py file.  By using dotted-notation (``app_name.model_name``), it is
     939possible to reference across models.py files when recursive ``import``
     940statements would otherwise cause problems.
     941
     942my_project/accounts/models.py:
     943
     944        class User(models.Model):
     945                saved_articles = models.ManyToManyField('articles.Article')
     946                # ...
     947
     948my_project/articles/models.py:
     949
     950        class Article(models.Model):
     951                author = models.ForeignKey('accounts.User')
     952                # ...
     953
    925954Meta options
    926955============
    927956
Back to Top