A route explicitly defines a join path between two models. Each route is made up of four components. For example, given a model hierarchy:

     ModelA
    /      \
ModelB    ModelC
   |        |
   \      ModelD
     \     /
      ModelE

..the traversal path from ModelA to ModelE is ambiguous. It could go from ABE or ACDE. However, by default modeltree will choose the shortest path to reduce the number of joins necessary since this is generally what is preferred.

What if ModelD did not exist..

    ModelA
     /  \
ModelB  ModelC
     \  /
    ModelE

..both paths only require two joins, thus the path that gets traversed first will be the choosen one. To explicitly choose a path, a route can be defined. Taking the form::

{
    'source': 'app1.model1',
    'target': 'app1.model2',
    'field': None,
    'symmetrical': None,
}

The source model defines the model where the join is being created from (the left side of the join). The target model defines the right side of the join.

field is optional, but explicitly defines the model field that will be used for the join. This is useful if there are more than one foreign key relationships on between the target and source models.

Finally, symmetrical is an optional boolean that ensures when the target and source models switch sides, the same join occurs on the same field.

Routes are typically used for defining explicit join paths, but sometimes it is necessary to exclude join paths. For example if there are three possible paths and one should never occur.

A modeltree takes the required_routes and excluded_routes which each are a list of routes in the above format.