Ticket #14396: 14396_list_select_related2.patch

File 14396_list_select_related2.patch, 6.7 KB (added by danielr, 4 years ago)
  • docs/ref/contrib/admin/index.txt

     
    657657.. attribute:: ModelAdmin.list_select_related
    658658
    659659    Set ``list_select_related`` to tell Django to use
    660     :meth:`~django.db.models.QuerySet.select_related` in retrieving the list of
    661     objects on the admin change list page. This can save you a bunch of
     660    :meth:`~django.db.models.query.QuerySet.select_related` in retrieving the
     661    list of objects on the admin change list page. This can save you a bunch of
    662662    database queries.
    663663
    664     The value should be either ``True`` or ``False``. Default is ``False``.
     664    The value should be one of:
    665665
    666     Note that Django will use :meth:`~django.db.models.QuerySet.select_related`,
    667     regardless of this setting if one of the ``list_display`` fields is a
    668     ``ForeignKey``.
     666    * ``True`` or ``False``. If ``True``, the standard
     667      :meth:`~django.db.models.query.QuerySet.select_related` call will be used.
    669668
     669    * A list or tuple of field names. In this case, the value is used as the
     670      argument to :meth:`~django.db.models.query.QuerySet.select_related` which
     671      determines which relations should be followed.
     672
     673    The default is ``False``.
     674
     675    Note that Django will use
     676    :meth:`~django.db.models.query.QuerySet.select_related`, regardless of this
     677    setting, if one of the :attr:`~ModelAdmin.list_display` fields is a
     678    :class:`~django.db.models.ForeignKey` or
     679    :class:`~django.db.models.OneToOneField`.
     680
    670681.. attribute:: ModelAdmin.ordering
    671682
    672683    Set ``ordering`` to specify how lists of objects should be ordered in the
  • django/contrib/admin/validation.py

     
    160160    if hasattr(cls, "readonly_fields"):
    161161        check_readonly_fields(cls, model, opts)
    162162
    163     # list_select_related = False
    164163    # save_as = False
    165164    # save_on_top = False
    166     for attr in ('list_select_related', 'save_as', 'save_on_top'):
     165    for attr in ('save_as', 'save_on_top'):
    167166        if not isinstance(getattr(cls, attr), bool):
    168167            raise ImproperlyConfigured("'%s.%s' should be a boolean."
    169168                    % (cls.__name__, attr))
    170169
     170    # list_select_related = False
     171    if not isinstance(cls.list_select_related, (bool, list, tuple)):
     172        raise ImproperlyConfigured("'%s.list_select_related' should be a boolean, a list or a tuple."
     173                                   % cls.__name__)
    171174
    172175    # inlines = []
    173176    if hasattr(cls, 'inlines'):
     
    197200    fk = _get_foreign_key(parent_model, cls.model, fk_name=cls.fk_name, can_fail=True)
    198201
    199202    # extra = 3
    200     if not isinstance(cls.extra, int):
     203    if not isinstance(getattr(cls, 'extra'), int):
    201204        raise ImproperlyConfigured("'%s.extra' should be a integer."
    202205                % cls.__name__)
    203206
  • django/contrib/admin/views/main.py

     
    33from django.core.exceptions import SuspiciousOperation
    44from django.core.paginator import InvalidPage
    55from django.db import models
     6from django.db.models.query import QuerySet
    67from django.utils.encoding import force_unicode, smart_str
    78from django.utils.translation import ugettext, ugettext_lazy
    89from django.utils.http import urlencode
     
    276277        # with a relationship and the provided queryset doesn't already have
    277278        # select_related defined.
    278279        if not qs.query.select_related:
    279             if self.list_select_related:
     280            if isinstance(self.list_select_related, (list, tuple)):
     281                qs = qs.select_related(*self.list_select_related)
     282            elif self.list_select_related:
    280283                qs = qs.select_related()
    281284            else:
    282285                for field_name in self.list_display:
     
    285288                    except models.FieldDoesNotExist:
    286289                        pass
    287290                    else:
    288                         if isinstance(field.rel, models.ManyToOneRel):
     291                        if isinstance(field.rel, (models.ManyToOneRel, models.OneToOneRel)):
    289292                            qs = qs.select_related()
    290293                            break
    291294
  • tests/regressiontests/admin_changelist/tests.py

     
    4141            'Failed to find expected row element: %s' % table_output)
    4242
    4343
     44    def test_select_related_nullable(self):
     45        """
     46        Regression test for #14396: allow list_select_related to explicitly
     47        specify relations to follow.
     48        """
     49        m = NullableChildAdmin(Child, admin.site)
     50        cl = ChangeList(MockRequest(), Child, m.list_display,
     51                        m.list_display_links, m.list_filter, m.date_hierarchy,
     52                        m.search_fields, m.list_select_related, m.list_per_page,
     53                        m.list_editable, m)
     54        self.assertEqual(cl.query_set.query.select_related, {'parent': {}})
     55
    4456    def test_result_list_html(self):
    4557        """
    4658        Verifies that inclusion tag result_list generates a table when with
     
    321333        return super(FilteredChildAdmin, self).queryset(request).filter(
    322334            name__contains='filtered')
    323335
     336class NullableChildAdmin(admin.ModelAdmin):
     337    list_select_related = ('parent',)
     338
    324339class MockRequest(object):
    325340    GET = {}
    326341
  • tests/regressiontests/modeladmin/tests.py

     
    10321032
    10331033        self.assertRaisesRegexp(
    10341034            ImproperlyConfigured,
    1035             "'ValidationTestModelAdmin.list_select_related' should be a boolean.",
     1035            "'ValidationTestModelAdmin.list_select_related' should be a boolean, a list or a tuple.",
    10361036            validate,
    10371037            ValidationTestModelAdmin,
    10381038            ValidationTestModel,
     
    10431043
    10441044        validate(ValidationTestModelAdmin, ValidationTestModel)
    10451045
     1046        class ValidationTestModelAdmin(ModelAdmin):
     1047            list_select_related = ('field1', 'field2')
     1048
     1049        validate(ValidationTestModelAdmin, ValidationTestModel)
     1050
    10461051    def test_save_as_validation(self):
    10471052
    10481053        class ValidationTestModelAdmin(ModelAdmin):
Back to Top