Example #1
0
    def test_fetch_related(self):
        with custom_query_counter() as q:
            objs = list(self.B.objects.all())
            fetch_related(objs, {
                'ref': True
            })

            # make sure A objs are fetched
            for obj in objs:
                self.assertTrue(obj.ref.txt in ('a1', 'a2'))

            # one query for B, one query for A
            self.assertEqual(q, 2)
Example #2
0
    def test_batch_size_2(self):
        """
        Ensure we batch requests properly, if a batch size is given.
        """
        objs = list(self.B.objects.all())

        with custom_query_counter() as q:
            fetch_related(objs, {
                'ref': True,
            }, batch_size=3)

            # make sure A objs are fetched
            for obj in objs:
                self.assertTrue(obj.ref.txt in ('a1', 'a2', 'a3'))

            # All 3 objects are fetched in one query.
            self.assertEqual(q, 1)
Example #3
0
    def test_fetch_related_multiple_objs(self):
        with custom_query_counter() as q:
            objs = list(self.B.objects.all()) + list(self.C.objects.all())
            fetch_related(objs, {
                'ref': True,
                'ref_a': True
            })

            # make sure A objs are fetched
            for obj in objs:
                if isinstance(obj, self.B):
                    self.assertTrue(obj.ref.txt in ('a1', 'a2'))
                else:
                    self.assertEqual(obj.ref_a.txt, 'a3')

            # one query for B, one for C, one for A
            self.assertEqual(q, 3)
Example #4
0
    def test_extra_filters(self):
        """
        Ensure we apply extra filters by collection.
        """
        objs = list(self.E.objects.all())

        with custom_query_counter() as q:
            fetch_related(objs, {
                'refs_a': True,
                'ref_b': True,
            }, extra_filters={
                self.A: {'shard_a': self.shard},
                self.B: {'shard_b': self.shard},
            })
        ops = list(q.db.system.profile.find({'op': 'query'}))
        assert len(ops) == 2
        filters = {op['query']['find']: op['query']['filter'] for op in ops}
        assert filters['a']['shard_a'] == self.shard.pk
        assert filters['b']['shard_b'] == self.shard.pk
Example #5
0
    def test_fetch_related_subdict(self):
        """
        Make sure fetching related references works with subfields and that
        it uses caching properly.
        """
        with custom_query_counter() as q:
            objs = list(self.D.objects.all())
            fetch_related(objs, {
                'ref_a': True,
                'ref_c': {
                    'ref_a': True
                }
            })

            # make sure A objs are fetched
            for obj in objs:
                self.assertEqual(obj.ref_a.txt, 'a3')
                self.assertEqual(obj.ref_c.ref_a.txt, 'a3')

            # one query for D, one query for C, one query for A
            self.assertEqual(q, 3)
Example #6
0
    def test_safe_reference_fields(self):
        """
        Make sure SafeReferenceField and SafeReferenceListField don't fetch
        the entire objects if we use a partial fetch_related on them.
        """
        objs = list(self.E.objects.all())

        with custom_query_counter() as q:
            fetch_related(objs, {
                'refs_a': ["id"],
                'ref_b': ["id"]
            })

        # make sure the IDs match
        self.assertEqual(
            [a.pk for a in objs[0].refs_a],
            [self.a1.pk, self.a2.pk, self.a3.pk]
        )
        self.assertEqual(objs[0].ref_b.pk, self.b1.pk)

        # make sure other fields are empty
        self.assertEqual(set([a.txt for a in objs[0].refs_a]), set([None]))
        self.assertEqual(objs[0].ref_b.ref, None)

        # make sure the queries to MongoDB only fetched the IDs
        queries = list(q.db.system.profile.find({ 'op': 'query' }, { 'ns': 1, 'execStats': 1 }))
        self.assertEqual(
            set([ q['ns'].split('.')[1] for q in queries ]),
            set([ 'a', 'b' ])
        )
        self.assertEqual(
            set([ q['execStats']['stage'] for q in queries ]),
            set([ 'PROJECTION' ]),
        )
        self.assertEqual(
            set([ tuple(q['execStats']['transformBy'].keys()) for q in queries ]),
            set([ ('_id',) ]),
        )
Example #7
0
    def test_fetch_same_doc_class_multiple_times_with_cache_map(self):
        """
        Make sure that the right documents are fetched when we reuse a cache
        map for the same document type and the second fetch_related is a
        partial fetch.
        """
        self.b1.reload()
        self.c1.reload()
        cache_map = {}
        objs = [self.b1, self.c1]
        with custom_query_counter() as q:
            fetch_related(objs, {
                'ref': True
            }, cache_map=cache_map)
            fetch_related(objs, {
                'ref_a': ['id']
            }, cache_map=cache_map)

            self.assertEqual(q, 2)
            self.assertEqual(
                [op['query']['_id']['$in'][0] for op in q.db.system.profile.find({ 'op': 'query' })],
                [self.a1.pk, self.a3.pk]
            )