Code

Ticket #14396: 14396_list_select_related2.patch

File 14396_list_select_related2.patch, 6.7 KB (added by danielr, 3 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):