Ticket #17439: 17439.patch

File 17439.patch, 2.9 KB (added by aaugustin, 3 years ago)
  • tests/modeltests/prefetch_related/tests.py

     
    6868
    6969        self.assertQuerysetEqual(self.book2.authors.all(), [u"<Author: Charlotte>"])
    7070
     71    def test_onetoone_reverse_no_match(self):
     72        # Regression for #17439
     73        with self.assertNumQueries(2):
     74            book = Book.objects.prefetch_related('bookwithyear').all()[0]
     75        with self.assertNumQueries(0):
     76            with self.assertRaises(BookWithYear.DoesNotExist):
     77                book.bookwithyear
     78
    7179    def test_survives_clone(self):
    7280        with self.assertNumQueries(2):
    7381            lists = [list(b.first_time_authors.all())
  • django/db/models/query.py

     
    66import itertools
    77import sys
    88
     9from django.core import exceptions
    910from django.db import connections, router, transaction, IntegrityError
    1011from django.db.models.fields import AutoField
    1112from django.db.models.query_utils import (Q, select_related_descend,
     
    16771678                # (e.g. via select_related), or hopefully some other property
    16781679                # that doesn't support prefetching but needs to be traversed.
    16791680
    1680                 # We replace the current list of parent objects with that list.
    1681                 obj_list = [getattr(obj, attr) for obj in obj_list]
     1681                # We replace the current list of parent objects with that list,
     1682                # filtering out empty or missing values so that we can continue
     1683                # with nullable or reverse relations.
     1684                new_obj_list = []
     1685                for obj in obj_list:
     1686                    try:
     1687                        new_obj = getattr(obj, attr)
     1688                    except exceptions.ObjectDoesNotExist:
     1689                        continue
     1690                    if new_obj is None:
     1691                        continue
     1692                    new_obj_list.append(new_obj)
     1693                obj_list = new_obj_list
    16821694
    1683                 # Filter out 'None' so that we can continue with nullable
    1684                 # relations.
    1685                 obj_list = [obj for obj in obj_list if obj is not None]
    16861695
    1687 
    16881696def get_prefetcher(instance, attr):
    16891697    """
    16901698    For the attribute 'attr' on the given instance, finds
     
    17781786        vals = rel_obj_cache.get(instance_attr_val, [])
    17791787        if single:
    17801788            # Need to assign to single cache on instance
    1781             if vals:
    1782                 setattr(obj, cache_name, vals[0])
     1789            setattr(obj, cache_name, vals[0] if vals else None)
    17831790        else:
    17841791            # Multi, attribute represents a manager with an .all() method that
    17851792            # returns a QuerySet
Back to Top