diff options
| author | Marc Tamlyn <marc.tamlyn@gmail.com> | 2013-06-06 01:27:05 -0700 |
|---|---|---|
| committer | Marc Tamlyn <marc.tamlyn@gmail.com> | 2013-06-06 01:27:05 -0700 |
| commit | 9ed971f4f1d2f05ecf7e2760556259eb2dca85f8 (patch) | |
| tree | a980fbf9d9a9039c8cdce2e18fe0ddfb35585dda /django | |
| parent | 31fd64ad8a98d7de0acb9144ae6f7bd124700cb0 (diff) | |
| parent | 0fd9f7c95f748764867dc148a2bacef807466d85 (diff) | |
Merge pull request #1245 from oinopion/list_select_related
Fixed #19080 -- Fine-grained control over select_related in admin
Diffstat (limited to 'django')
| -rw-r--r-- | django/contrib/admin/validation.py | 10 | ||||
| -rw-r--r-- | django/contrib/admin/views/main.py | 44 |
2 files changed, 35 insertions, 19 deletions
diff --git a/django/contrib/admin/validation.py b/django/contrib/admin/validation.py index 59c5ad35ef..222d433e53 100644 --- a/django/contrib/admin/validation.py +++ b/django/contrib/admin/validation.py @@ -310,8 +310,14 @@ class ModelAdminValidator(BaseValidator): % (cls.__name__, idx, field)) def validate_list_select_related(self, cls, model): - " Validate that list_select_related is a boolean. " - check_type(cls, 'list_select_related', bool) + " Validate that list_select_related is a boolean, a list or a tuple. " + list_select_related = getattr(cls, 'list_select_related', None) + if list_select_related: + types = (bool, tuple, list) + if not isinstance(list_select_related, types): + raise ImproperlyConfigured("'%s.list_select_related' should be " + "either a bool, a tuple or a list" % + cls.__name__) def validate_list_per_page(self, cls, model): " Validate that list_per_page is an integer. " diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py index dbed21265c..8ea7e10fc0 100644 --- a/django/contrib/admin/views/main.py +++ b/django/contrib/admin/views/main.py @@ -356,36 +356,46 @@ class ChangeList(six.with_metaclass(RenameChangeListMethods)): # ValueError, ValidationError, or ?. raise IncorrectLookupParameters(e) - # Use select_related() if one of the list_display options is a field - # with a relationship and the provided queryset doesn't already have - # select_related defined. if not qs.query.select_related: - if self.list_select_related: - qs = qs.select_related() - else: - for field_name in self.list_display: - try: - field = self.lookup_opts.get_field(field_name) - except models.FieldDoesNotExist: - pass - else: - if isinstance(field.rel, models.ManyToOneRel): - qs = qs.select_related() - break + qs = self.apply_select_related(qs) # Set ordering. ordering = self.get_ordering(request, qs) qs = qs.order_by(*ordering) # Apply search results - qs, search_use_distinct = self.model_admin.get_search_results(request, qs, self.query) + qs, search_use_distinct = self.model_admin.get_search_results( + request, qs, self.query) - # Remove duplicates from results, if neccesary + # Remove duplicates from results, if necessary if filters_use_distinct | search_use_distinct: return qs.distinct() else: return qs + def apply_select_related(self, qs): + if self.list_select_related is True: + return qs.select_related() + + if self.list_select_related is False: + if self.has_related_field_in_list_display(): + return qs.select_related() + + if self.list_select_related: + return qs.select_related(*self.list_select_related) + return qs + + def has_related_field_in_list_display(self): + for field_name in self.list_display: + try: + field = self.lookup_opts.get_field(field_name) + except models.FieldDoesNotExist: + pass + else: + if isinstance(field.rel, models.ManyToOneRel): + return True + return False + def url_for_result(self, result): pk = getattr(result, self.pk_attname) return reverse('admin:%s_%s_change' % (self.opts.app_label, |
