449 | | # Add additional tables and WHERE clauses based on select_related. |
450 | | if self._select_related: |
451 | | fill_table_cache(opts, select, tables, where, opts.db_table, [opts.db_table]) |
452 | | |
453 | | # Add any additional SELECTs. |
454 | | if self._select: |
455 | | select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), backend.quote_name(s[0])) for s in self._select.items()]) |
456 | | |
457 | | # Start composing the body of the SQL statement. |
458 | | sql = [" FROM", backend.quote_name(opts.db_table)] |
459 | | |
460 | | # Compose the join dictionary into SQL describing the joins. |
461 | | if joins: |
462 | | sql.append(" ".join(["%s %s AS %s ON %s" % (join_type, table, alias, condition) |
463 | | for (alias, (table, join_type, condition)) in joins.items()])) |
464 | | |
465 | | # Compose the tables clause into SQL. |
466 | | if tables: |
467 | | sql.append(", " + ", ".join(tables)) |
468 | | |
469 | | # Compose the where clause into SQL. |
470 | | if where: |
471 | | sql.append(where and "WHERE " + " AND ".join(where)) |
472 | | |
473 | | # ORDER BY clause |
| 449 | # ORDER BY clause (this done before the other clauses since it is needed by follow_foreignkeys) |
| 478 | |
| 479 | # Add additional tables and WHERE clauses based on select_related. |
| 480 | if self._select_related: |
| 481 | more_select, more_tables, more_where = follow_foreignkeys(opts, [opts.db_table], ordering_tables) |
| 482 | select.extend(more_select) |
| 483 | tables.extend(more_tables) |
| 484 | where.extend(more_where) |
| 485 | |
| 486 | # Add any additional SELECTs. |
| 487 | if self._select: |
| 488 | select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), backend.quote_name(s[0])) for s in self._select.items()]) |
| 489 | |
| 490 | # Start composing the body of the SQL statement. |
| 491 | sql = [" FROM", backend.quote_name(opts.db_table)] |
| 492 | |
| 493 | # Compose the join dictionary into SQL describing the joins. |
| 494 | if joins: |
| 495 | sql.append(" ".join(["%s %s AS %s ON %s" % (join_type, table, alias, condition) |
| 496 | for (alias, (table, join_type, condition)) in joins.items()])) |
| 497 | |
| 498 | # Compose the tables clause into SQL. |
| 499 | if tables: |
| 500 | sql.append(", " + ", ".join(tables)) |
| 501 | |
| 502 | # Compose the where clause into SQL. |
| 503 | if where: |
| 504 | sql.append(where and "WHERE " + " AND ".join(where)) |
| 505 | |
| 506 | # finish up ORDER BY clause |
665 | | def fill_table_cache(opts, select, tables, where, old_prefix, cache_tables_seen): |
666 | | """ |
667 | | Helper function that recursively populates the select, tables and where (in |
668 | | place) for select_related queries. |
669 | | """ |
| 672 | def follow_foreignkeys(object_to_follow, tables_seen, ordering_tables, recursion_level=None): |
| 673 | """Helper function that recursively follows ForeignKey fields in object_to_follow and returns |
| 674 | the approriate select, tables, and where lists for select_related_queries""" |
| 675 | if recursion_level is None: |
| 676 | recursion_level = 0 |
| 677 | select = [] |
| 678 | tables = [] |
| 679 | where = [] |
671 | | for f in opts.fields: |
672 | | if f.rel and not f.null: |
673 | | db_table = f.rel.to._meta.db_table |
674 | | if db_table not in cache_tables_seen: |
675 | | tables.append(qn(db_table)) |
676 | | else: # The table was already seen, so give it a table alias. |
677 | | new_prefix = '%s%s' % (db_table, len(cache_tables_seen)) |
678 | | tables.append('%s %s' % (qn(db_table), qn(new_prefix))) |
679 | | db_table = new_prefix |
680 | | cache_tables_seen.append(db_table) |
| 681 | for field in object_to_follow.fields: |
| 682 | if field.rel and not field.null: |
| 683 | related_table = field.rel.to._meta.db_table |
| 684 | if related_table == tables_seen[0]: |
| 685 | #stop if we follow a circular foreignkey relationship chain |
| 686 | return select, tables, where |
| 687 | if (related_table not in tables_seen) and ((related_table not in ordering_tables) or (recursion_level == 0)): |
| 688 | tables.append(qn(related_table)) |
| 689 | else: |
| 690 | table_alias = '%s%s' % (related_table, len(tables_seen)) |
| 691 | tables.append('%s %s' % (qn(related_table), qn(table_alias))) |
| 692 | related_table = table_alias |
| 693 | tables_seen.append(related_table) |
682 | | (qn(old_prefix), qn(f.column), qn(db_table), qn(f.rel.get_related_field().column))) |
683 | | select.extend(['%s.%s' % (qn(db_table), qn(f2.column)) for f2 in f.rel.to._meta.fields]) |
684 | | fill_table_cache(f.rel.to._meta, select, tables, where, db_table, cache_tables_seen) |
| 695 | (qn(object_to_follow.db_table), qn(field.column), qn(related_table), qn(field.rel.get_related_field().column))) |
| 696 | select.extend(['%s.%s' % (qn(related_table), qn(f2.column)) for f2 in field.rel.to._meta.fields]) |
| 697 | more_select, more_tables, more_where = follow_foreignkeys(field.rel.to._meta, tables_seen, ordering_tables, recursion_level + 1) |
| 698 | select.extend(more_select) |
| 699 | tables.extend(more_tables) |
| 700 | where.extend(more_where) |
| 701 | return select, tables, where |