Beispiel #1
0
 def test_manytomany_filter_invalid_query(self):
     self.do_invalid_query_param_test(
         lambda params: ManyToManyFilter('authors', Book, params),
         MultiValueDict({'authors': ['xxx']}))
     self.do_missing_related_object_test(
         lambda params: ManyToManyFilter('authors', Book, params),
         MultiValueDict({'authors': ['10000']}))
    def test_manytomany_filter(self):
        """
        Tests for ManyToManyFilter
        """
        filter1 = ManyToManyFilter('authors', Book, MultiValueDict())
        qs = Book.objects.all()

        # ManyToMany can have 'drill down', i.e. multiple levels of filtering,
        # which can be removed individually.

        # First level:
        choices = filter1.get_choices(qs)

        # Check list is full, and in right order
        self.assertEqual([unicode(v) for v in Author.objects.all()],
                         [choice.label for choice in choices])

        for choice in choices:
            # For single choice, param will be single integer:
            param = int(choice.params[filter1.query_param])

            # Check the count
            count = Book.objects.filter(authors=int(param)).count()
            self.assertEqual(choice.count, count)

            author = Author.objects.get(id=param)

            # Check the label
            self.assertEqual(unicode(author),
                             choice.label)

            # Check the filtering
            filter2 = ManyToManyFilter('authors', Book, choice.params)
            qs_filtered = filter2.apply_filter(qs)
            self.assertEqual(len(qs_filtered), choice.count)

            for book in qs_filtered:
                self.assertTrue(author in book.authors.all())

            # Check we've got a 'remove link' on filtered.
            choices_filtered = filter2.get_choices(qs)
            self.assertEqual(choices_filtered[0].link_type, FILTER_REMOVE)
Beispiel #3
0
    def test_manytomany_filter(self):
        """
        Tests for ManyToManyFilter
        """
        filter1 = ManyToManyFilter('authors', Book, MultiValueDict())
        qs = Book.objects.all()

        # ManyToMany can have 'drill down', i.e. multiple levels of filtering,
        # which can be removed individually.

        # First level:
        choices = filter1.get_choices(qs)

        # Check list is full, and in right order
        self.assertEqual([text_type(v) for v in Author.objects.all()],
                         [choice.label for choice in choices])

        for choice in choices:
            # For single choice, param will be single integer:
            param = int(choice.params[filter1.query_param])

            # Check the count
            count = Book.objects.filter(authors=int(param)).count()
            self.assertEqual(choice.count, count)

            author = Author.objects.get(id=param)

            # Check the label
            self.assertEqual(text_type(author), choice.label)

            # Check the filtering
            filter2 = ManyToManyFilter('authors', Book, choice.params)
            qs_filtered = filter2.apply_filter(qs)
            self.assertEqual(len(qs_filtered), choice.count)

            for book in qs_filtered:
                self.assertTrue(author in book.authors.all())

            # Check we've got a 'remove link' on filtered.
            choices_filtered = filter2.get_choices(qs)
            self.assertEqual(choices_filtered[0].link_type, FILTER_REMOVE)
Beispiel #4
0
    def test_manytomany_filter_multiple(self):
        qs = Book.objects.all()

        # Specific example - multiple filtering
        emily = Author.objects.get(name='Emily Brontë')
        charlotte = Author.objects.get(name='Charlotte Brontë')
        anne = Author.objects.get(name='Anne Brontë')

        # If we select 'emily' as an author:

        data = MultiValueDict({'authors': [str(emily.pk)]})
        with self.assertNumQueries(1):
            # 1 query for all chosen objects
            filter1 = ManyToManyFilter('authors', Book, data)

        with self.assertNumQueries(0):
            # This shouldn't need to do any more queries
            qs_emily = filter1.apply_filter(qs)

        # ...we should get a qs that includes Poems and Wuthering Heights.
        self.assertTrue(qs_emily.filter(name='Poems').exists())
        self.assertTrue(qs_emily.filter(name='Wuthering Heights').exists())
        # ...and excludes Jane Eyre
        self.assertFalse(qs_emily.filter(name='Jane Eyre').exists())

        with self.assertNumQueries(2):
            # 0 query for all chosen objects (already done)
            # 1 query for available objects
            # 1 query for counts
            choices = filter1.get_choices(qs_emily)

        # We should have a 'choices' that includes charlotte and anne
        self.assertTrue(
            text_type(anne) in
            [c.label for c in choices if c.link_type is FILTER_ADD])
        self.assertTrue(
            text_type(charlotte) in
            [c.label for c in choices if c.link_type is FILTER_ADD])

        # ... but not emily, because that is obvious and boring
        self.assertTrue(
            text_type(emily) not in
            [c.label for c in choices if c.link_type is FILTER_ADD])
        # emily should be in 'remove' links, however.
        self.assertTrue(
            text_type(emily) in
            [c.label for c in choices if c.link_type is FILTER_REMOVE])

        # Select again - should have sensible params
        anne_choice = [c for c in choices if c.label.startswith('Anne')][0]
        self.assertTrue(
            text_type(emily.pk) in anne_choice.params.getlist('authors'))
        self.assertTrue(
            text_type(anne.pk) in anne_choice.params.getlist('authors'))

        # Now do the second select:
        filter2 = ManyToManyFilter('authors', Book, anne_choice.params)

        qs_emily_anne = filter2.apply_filter(qs)

        # ...we should get a qs that includes Poems
        self.assertTrue(qs_emily_anne.filter(name='Poems').exists())
        # ... but not Wuthering Heights
        self.assertFalse(
            qs_emily_anne.filter(name='Wuthering Heights').exists())

        # The choices should contain just Emily and Anne to remove, and
        # Charlotte should have 'link_type' FILTER_ADD. Even though it
        # is the only choice, adding the choice is not necessarily the same as
        # not adding it (could have books by Emily and Anne, but not Charlotte)
        choices = filter2.get_choices(qs_emily_anne)
        self.assertEqual([(c.label, c.link_type) for c in choices],
                         [(text_type(emily), FILTER_REMOVE),
                          (text_type(anne), FILTER_REMOVE),
                          (text_type(charlotte), FILTER_ADD)])
    def test_manytomany_filter_multiple(self):
        qs = Book.objects.all()

        # Specific example - multiple filtering
        emily = Author.objects.get(name='Emily Brontë')
        charlotte = Author.objects.get(name='Charlotte Brontë')
        anne = Author.objects.get(name='Anne Brontë')

        # If we select 'emily' as an author:

        data = MultiValueDict({'authors': [str(emily.pk)]})
        with self.assertNumQueries(1):
            # 1 query for all chosen objects
            filter1 = ManyToManyFilter('authors', Book, data)

        with self.assertNumQueries(0):
            # This shouldn't need to do any more queries
            qs_emily = filter1.apply_filter(qs)

        # ...we should get a qs that includes Poems and Wuthering Heights.
        self.assertTrue(qs_emily.filter(name='Poems').exists())
        self.assertTrue(qs_emily.filter(name='Wuthering Heights').exists())
        # ...and excludes Jane Eyre
        self.assertFalse(qs_emily.filter(name='Jane Eyre').exists())

        with self.assertNumQueries(2):
            # 0 query for all chosen objects (already done)
            # 1 query for available objects
            # 1 query for counts
            choices = filter1.get_choices(qs_emily)

        # We should have a 'choices' that includes charlotte and anne
        self.assertTrue(unicode(anne) in [c.label for c in choices if c.link_type is FILTER_ADD])
        self.assertTrue(unicode(charlotte) in [c.label for c in choices if c.link_type is FILTER_ADD])

        # ... but not emily, because that is obvious and boring
        self.assertTrue(unicode(emily) not in [c.label for c in choices if c.link_type is FILTER_ADD])
        # emily should be in 'remove' links, however.
        self.assertTrue(unicode(emily) in [c.label for c in choices if c.link_type is FILTER_REMOVE])

        # Select again - should have sensible params
        anne_choice = [c for c in choices if c.label.startswith('Anne')][0]
        self.assertTrue(unicode(emily.pk) in anne_choice.params.getlist('authors'))
        self.assertTrue(unicode(anne.pk) in anne_choice.params.getlist('authors'))

        # Now do the second select:
        filter2 = ManyToManyFilter('authors', Book, anne_choice.params)

        qs_emily_anne = filter2.apply_filter(qs)

        # ...we should get a qs that includes Poems
        self.assertTrue(qs_emily_anne.filter(name='Poems').exists())
        # ... but not Wuthering Heights
        self.assertFalse(qs_emily_anne.filter(name='Wuthering Heights').exists())

        # The choices should contain just Emily and Anne to remove, and
        # Charlotte should have 'link_type' FILTER_ADD. Even though it
        # is the only choice, adding the choice is not necessarily the same as
        # not adding it (could have books by Emily and Anne, but not Charlotte)
        choices = filter2.get_choices(qs_emily_anne)
        self.assertEqual([(c.label, c.link_type) for c in choices],
                         [(unicode(emily), FILTER_REMOVE),
                          (unicode(anne), FILTER_REMOVE),
                          (unicode(charlotte), FILTER_ADD)])