=== modified file 'django/contrib/admin/views/main.py'
|
|
|
|
| 8 | 8 | from django.core.paginator import ObjectPaginator, InvalidPage |
| 9 | 9 | from django.shortcuts import get_object_or_404, render_to_response |
| 10 | 10 | from django.db import models |
| 11 | | from django.db.models.query import handle_legacy_orderlist, QuerySet |
| | 11 | from django.db.models.query import handle_legacy_orderlist, QuerySet, LOOKUP_SEPARATOR |
| 12 | 12 | from django.http import Http404, HttpResponse, HttpResponseRedirect |
| 13 | 13 | from django.utils.html import escape |
| 14 | 14 | from django.utils.text import capfirst, get_text_list |
| … |
… |
|
| 543 | 543 | "admin/object_history.html"], extra_context, context_instance=template.RequestContext(request)) |
| 544 | 544 | history = staff_member_required(never_cache(history)) |
| 545 | 545 | |
| | 546 | class FollowForeignKey(object): |
| | 547 | """ |
| | 548 | A class to represent a ForeignKey that spans multiple foreign keys |
| | 549 | over multiple model classes. |
| | 550 | """ |
| | 551 | def __init__(self, field, lookups): |
| | 552 | # Traverse the relationships to reach the final model class. |
| | 553 | for field_name in lookups[1:]: |
| | 554 | model = field.rel.to |
| | 555 | new_field = model._meta.get_field(field_name) |
| | 556 | if not new_field.rel: break |
| | 557 | field = new_field |
| | 558 | self.verbose_name = field.verbose_name |
| | 559 | self.rel = field.rel |
| | 560 | # Rejoin the lookups using the separator so that the |
| | 561 | # RelatedFilterSpec uses the correct lookup_kwarg. |
| | 562 | self.name = LOOKUP_SEPARATOR.join(lookups) |
| | 563 | |
| 546 | 564 | class ChangeList(object): |
| 547 | 565 | def __init__(self, request, model): |
| 548 | 566 | self.model = model |
| … |
… |
|
| 574 | 592 | def get_filters(self, request): |
| 575 | 593 | filter_specs = [] |
| 576 | 594 | if self.lookup_opts.admin.list_filter and not self.opts.one_to_one_field: |
| 577 | | filter_fields = [self.lookup_opts.get_field(field_name) \ |
| 578 | | for field_name in self.lookup_opts.admin.list_filter] |
| 579 | | for f in filter_fields: |
| | 595 | for field_name in self.lookup_opts.admin.list_filter: |
| | 596 | field_lookups = field_name.split(LOOKUP_SEPARATOR) |
| | 597 | f = self.lookup_opts.get_field(field_lookups[0]) |
| | 598 | # If the field name spans multiple models, wrap the field in a |
| | 599 | # FollowForeignKey. |
| | 600 | if len(field_lookups) > 1 and f.rel: |
| | 601 | f = FollowForeignKey(f, field_lookups) |
| 580 | 602 | spec = FilterSpec.create(f, request, self.params, self.model) |
| 581 | 603 | if spec and spec.has_output(): |
| 582 | 604 | filter_specs.append(spec) |
=== modified file 'django/core/management.py'
|
|
|
|
| 864 | 864 | from django.db import models, connection |
| 865 | 865 | from django.db.models.loading import get_app_errors |
| 866 | 866 | from django.db.models.fields.related import RelatedObject |
| | 867 | from django.db.models.query import LOOKUP_SEPARATOR |
| 867 | 868 | |
| 868 | 869 | e = ModelErrorCollection(outfile) |
| 869 | 870 | |
| … |
… |
|
| 1014 | 1015 | e.add(opts, '"admin.list_filter", if given, must be set to a list or tuple.') |
| 1015 | 1016 | else: |
| 1016 | 1017 | for fn in opts.admin.list_filter: |
| | 1018 | # Break the entry up using the lookup separator, and |
| | 1019 | # make sure each one points to a valid field. |
| | 1020 | field_lookups = fn.split(LOOKUP_SEPARATOR) |
| 1017 | 1021 | try: |
| 1018 | | f = opts.get_field(fn) |
| | 1022 | f = opts.get_field(field_lookups[0]) |
| | 1023 | if len(field_lookups) > 1: |
| | 1024 | if not f.rel: |
| | 1025 | e.add(opts, '"admin.list_filter" refers to %r, which contains a non-related field.' % fn) |
| | 1026 | for field_name in field_lookups[1:]: |
| | 1027 | model = f.rel.to |
| | 1028 | f = model._meta.get_field(field_name) |
| | 1029 | if not f.rel: |
| | 1030 | e.add(opts, '"admin.list_filter" refers to %r, which contains a non-related field.' % fn) |
| 1019 | 1031 | except models.FieldDoesNotExist: |
| 1020 | 1032 | e.add(opts, '"admin.list_filter" refers to %r, which isn\'t a field.' % fn) |
| 1021 | 1033 | # date_hierarchy |