def dashboard(self, request): from itertools import chain from operator import attrgetter from queryset_sequence import QuerySetSequence from django.db.models import F, Value news_query_set = News.objects.filter( date_published__isnull=False, status='LIVE').annotate( item_type=Value("NEWS", output_field=CharField())) event_query_set = Event.objects.filter( date_published__isnull=False, status='LIVE').exclude(type__code__in=[ LKUPEventType.EVENT_TYPE_MEETING, LKUPEventType.EVENT_TYPE_ONE_ON_ONE ]).annotate(image=F('banner')).annotate( item_type=Value("EVENT", output_field=CharField())) combine_queryset = QuerySetSequence(news_query_set, event_query_set) # query_set = sorted( # chain(news_query_set, event_query_set), # key=attrgetter('date_published'), reverse=True) query_set = combine_queryset.order_by('-date_published').filter( date_published__lte=datetime.datetime.today()) # query_set = sorted( # combine_queryset, # key=attrgetter('date_published'), reverse=True) # for a in query_set: # print(str(a.date_published) + a.item_type) page = self.paginate_queryset(query_set) if page is not None: data = StorySerializer(page, many=True).data return self.get_paginated_response(data) return construct_response(CODE_SUCCESS, StorySerializer(list, many=True).data)
def test_order_by_relation_with_different_ordering(self): """ Apply order_by() with a field that returns a model with different ordering on sub-QuerySets. """ # Both of these have publishers with the same fields, but different # ordering. all = QuerySetSequence(Article.objects.all(), BlogPost.objects.all()) # Order by publisher and ensure it takes. qss = all.order_by('publisher') self.assertEqual(qss.query.order_by, ['publisher']) self.assertRaises(FieldError, list, qss)
def test_order_by_relation_with_different_ordering(self): """ Apply order_by() with a field that returns a model with different ordering on sub-QuerySets. """ # Both of these have publishers with the same fields, but different # ordering. all = QuerySetSequence(Article.objects.all(), BlogPost.objects.all()) # Order by publisher and ensure it takes. with self.assertNumQueries(0): qss = all.order_by('publisher') self.assertEqual(qss.query.order_by, ['publisher']) self.assertRaises(FieldError, list, qss)
class TestSequenceCursorPagination(TestCase): """ Unit tests for `queryset_sequence.pagination.SequenceCursorPagination`. Heavily based on `tests.test_pagination` from Django REST Framework. """ PAGE_1 = [1, 2, 3, 4, 5] PAGE_2 = [6, 7, 8, 9, 10] PAGE_3 = [11, 12, 13, 14] def setUp(self): self.author = Author.objects.create(name="Jane Doe") self.publisher = Publisher.objects.create(name="Pablo's Publishing", address="123 Publishing Street") for d in range(1, 15): Book.objects.create(title='Book %s' % (d % 2), author=self.author, publisher=self.publisher, pages=d, release=date(2018, 10, 5)) self.pagination = _TestPagination() self.queryset = QuerySetSequence(Book.objects.filter(pages__lte=7), Book.objects.filter(pages__gt=7)) def get_pages(self, url): """ Given a URL return a tuple of: (previous page, current page, next page, previous url, next url) """ request = Request(factory.get(url)) queryset = self.pagination.paginate_queryset(self.queryset, request) current = [item.pages for item in queryset] next_url = self.pagination.get_next_link() previous_url = self.pagination.get_previous_link() if next_url is not None: request = Request(factory.get(next_url)) queryset = self.pagination.paginate_queryset(self.queryset, request) next = [item.pages for item in queryset] else: next = None if previous_url is not None: request = Request(factory.get(previous_url)) queryset = self.pagination.paginate_queryset(self.queryset, request) previous = [item.pages for item in queryset] else: previous = None return (previous, current, next, previous_url, next_url) def test_ordering(self): """Ensure that the QuerySetSequence is ordered as expected.""" pages = [b.pages for b in self.queryset] self.assertEqual(pages, self.PAGE_1 + self.PAGE_2 + self.PAGE_3) # The first 7 are in the 0th list, the last 7 are in the 1st list. number = [getattr(b, '#') for b in self.queryset] self.assertEqual(number, [0] * 7 + [1] * 7) def test_invalid_cursor(self): request = Request(factory.get('/', {'cursor': '123'})) with self.assertRaises(exceptions.NotFound): self.pagination.paginate_queryset(self.queryset, request) def test_use_with_ordering_filter(self): class MockView: filter_backends = (filters.OrderingFilter,) ordering_fields = ['title', 'author'] ordering = 'title' request = Request(factory.get('/', {'ordering': 'author'})) ordering = self.pagination.get_ordering(request, [], MockView()) self.assertEqual(ordering, ('#', 'author',)) request = Request(factory.get('/', {'ordering': '-author'})) ordering = self.pagination.get_ordering(request, [], MockView()) self.assertEqual(ordering, ('#', '-author',)) request = Request(factory.get('/', {'ordering': 'invalid'})) ordering = self.pagination.get_ordering(request, [], MockView()) self.assertEqual(ordering, ('#', 'title',)) def test_cursor_pagination(self): """Ensure that the cursor properly flips through pages.""" # Check the first page. (previous, current, next, previous_url, next_url) = self.get_pages('/') self.assertIsNone(previous) self.assertEqual(current, self.PAGE_1) self.assertEqual(next, self.PAGE_2) # Check the second page. (previous, current, next, previous_url, next_url) = self.get_pages(next_url) self.assertEqual(previous, self.PAGE_1) self.assertEqual(current, self.PAGE_2) self.assertEqual(next, self.PAGE_3) # Check the third page. (previous, current, next, previous_url, next_url) = self.get_pages(next_url) self.assertEqual(previous, self.PAGE_2) self.assertEqual(current, self.PAGE_3) self.assertIsNone(next) def test_cursor_stableness(self): """ Test what happens if we remove domains after loading a page. Pages should be independent, i.e. a cursor points to a particular domain, and shouldn't affect offsets. """ (previous, current, next, previous_url, next_url) = self.get_pages('/') # The first page is as normal. self.assertIsNone(previous) self.assertEqual(current, self.PAGE_1) self.assertEqual(next, self.PAGE_2) # Delete Books, this shouldn't affect the next request. Book.objects.filter(pages__lte=3).delete() Book.objects.filter(pages__gte=13).delete() (previous, current, next, _, old_next_url) = self.get_pages(next_url) # Should be some missing items self.assertEqual(previous, [4, 5]) self.assertEqual(current, self.PAGE_2) self.assertEqual(next, [11, 12]) # Deleting some from the current page and reloading should have the page # offset. Book.objects.get(pages=7).delete() (previous, current, next, _, new_next_url) = self.get_pages(next_url) # Should be some missing items self.assertEqual(previous, [4, 5]) self.assertEqual(current, [6, 8, 9, 10, 11]) self.assertEqual(next, [12]) # The next_url returned with the different items missing will actually # be different. self.assertNotEqual(old_next_url, new_next_url) def test_multiple_ordering(self): """Test a Pagination with multiple items in the ordering attribute.""" # This will order by: # 1. Even pages # 2. Odd pages # 3. Both of the above will be done in increasing order. # 4. Ordering happens for 1 - 7, then 8 - 14. class TestPagination(_TestPagination): ordering = ['title', 'pages'] self.pagination = TestPagination() PAGE_1 = [2, 4, 6, 1, 3] PAGE_2 = [5, 7, 8, 10, 12] PAGE_3 = [14, 9, 11, 13] # Check that the ordering is as expected. pages = [b.pages for b in self.queryset.order_by('#', *self.pagination.ordering)] self.assertEqual(pages, PAGE_1 + PAGE_2 + PAGE_3) # Now perform pretty much the same test as test_cursor_pagination, but # the ordering will be different. (previous, current, next, previous_url, next_url) = self.get_pages('/') self.assertIsNone(previous) self.assertEqual(current, PAGE_1) self.assertEqual(next, PAGE_2) (previous, current, next, previous_url, next_url) = self.get_pages(next_url) self.assertEqual(previous, PAGE_1) self.assertEqual(current, PAGE_2) self.assertEqual(next, PAGE_3) (previous, current, next, previous_url, next_url) = self.get_pages(next_url) self.assertEqual(previous, PAGE_2) self.assertEqual(current, PAGE_3) self.assertIsNone(next) def test_duplicates(self): """Ensure that pagination works over an 'extreme' number of duplicates.""" PAGES = 100 # This must be unique from other fixture data. # Create a bunch of books that are the same. for i in range(15): Book.objects.create(title=str(i), author=self.author, publisher=self.publisher, pages=PAGES, release=date(2018, 10, 5)) # And use only those duplicate books. self.queryset = QuerySetSequence(Book.objects.filter(pages=PAGES)) titles = [item.title for item in self.queryset] # Look at both the pages (which should all be 1) and the IDs. next_url = '/' for i in range(3): request = Request(factory.get(next_url)) queryset = self.pagination.paginate_queryset(self.queryset, request) titles, pages = zip(*[(item.title, item.pages) for item in queryset]) self.assertEqual(titles, tuple(map(lambda d: str(d + (i * 5)), [0, 1, 2, 3, 4]))) self.assertEqual(pages, (PAGES, ) * 5) next_url = self.pagination.get_next_link() self.assertIsNone(next_url)
class TestSequenceCursorPagination(TestCase): """ Unit tests for `queryset_sequence.pagination.SequenceCursorPagination`. Heavily based on `tests.test_pagination` from Django REST Framework. """ PAGE_1 = [1, 2, 3, 4, 5] PAGE_2 = [6, 7, 8, 9, 10] PAGE_3 = [11, 12, 13, 14] def setUp(self): self.author = Author.objects.create(name="Jane Doe") self.publisher = Publisher.objects.create(name="Pablo's Publishing", address="123 Publishing Street") for d in range(1, 15): book = Book.objects.create(title='Book %s' % (d % 2), author=self.author, publisher=self.publisher, pages=d) self.pagination = _TestPagination() self.queryset = QuerySetSequence(Book.objects.filter(pages__lte=7), Book.objects.filter(pages__gt=7)) def get_pages(self, url): """ Given a URL return a tuple of: (previous page, current page, next page, previous url, next url) """ request = Request(factory.get(url)) queryset = self.pagination.paginate_queryset(self.queryset, request) current = [item.pages for item in queryset] next_url = self.pagination.get_next_link() previous_url = self.pagination.get_previous_link() if next_url is not None: request = Request(factory.get(next_url)) queryset = self.pagination.paginate_queryset(self.queryset, request) next = [item.pages for item in queryset] else: next = None if previous_url is not None: request = Request(factory.get(previous_url)) queryset = self.pagination.paginate_queryset(self.queryset, request) previous = [item.pages for item in queryset] else: previous = None return (previous, current, next, previous_url, next_url) def test_ordering(self): """Ensure that the QuerySetSequence is ordered as expected.""" pages = [b.pages for b in self.queryset] self.assertEqual(pages, self.PAGE_1 + self.PAGE_2 + self.PAGE_3) # The first 7 are in the 0th list, the last 7 are in the 1st list. number = [getattr(b, '#') for b in self.queryset] self.assertEqual(number, [0] * 7 + [1] * 7) def test_invalid_cursor(self): request = Request(factory.get('/', {'cursor': '123'})) with self.assertRaises(exceptions.NotFound): self.pagination.paginate_queryset(self.queryset, request) def test_use_with_ordering_filter(self): class MockView: filter_backends = (filters.OrderingFilter,) ordering_fields = ['title', 'author'] ordering = 'title' request = Request(factory.get('/', {'ordering': 'author'})) ordering = self.pagination.get_ordering(request, [], MockView()) self.assertEqual(ordering, ('#', 'author',)) request = Request(factory.get('/', {'ordering': '-author'})) ordering = self.pagination.get_ordering(request, [], MockView()) self.assertEqual(ordering, ('#', '-author',)) request = Request(factory.get('/', {'ordering': 'invalid'})) ordering = self.pagination.get_ordering(request, [], MockView()) self.assertEqual(ordering, ('#', 'title',)) def test_cursor_pagination(self): (previous, current, next, previous_url, next_url) = self.get_pages('/') self.assertIsNone(previous) self.assertEqual(current, self.PAGE_1) self.assertEqual(next, self.PAGE_2) (previous, current, next, previous_url, next_url) = self.get_pages(next_url) self.assertEqual(previous, self.PAGE_1) self.assertEqual(current, self.PAGE_2) self.assertEqual(next, self.PAGE_3) (previous, current, next, previous_url, next_url) = self.get_pages(next_url) self.assertEqual(previous, self.PAGE_2) self.assertEqual(current, self.PAGE_3) self.assertIsNone(next) def test_cursor_stableness(self): """ Test what happens if we remove domains after loading a page. Pages should be independent, i.e. a cursor points to a particular domain, and shouldn't affect offsets. """ (previous, current, next, previous_url, next_url) = self.get_pages('/') # The first page is as normal. self.assertIsNone(previous) self.assertEqual(current, self.PAGE_1) self.assertEqual(next, self.PAGE_2) # Delete Books, this shouldn't affect the next request. Book.objects.filter(pages__lte=3).delete() Book.objects.filter(pages__gte=13).delete() (previous, current, next, _, old_next_url) = self.get_pages(next_url) # Should be some missing items self.assertEqual(previous, [4, 5]) self.assertEqual(current, self.PAGE_2) self.assertEqual(next, [11, 12]) # Deleting some from the current page and reloading should have the page # offset. Book.objects.get(pages=7).delete() (previous, current, next, _, new_next_url) = self.get_pages(next_url) # Should be some missing items self.assertEqual(previous, [4, 5]) self.assertEqual(current, [6, 8, 9, 10, 11]) self.assertEqual(next, [12]) # The next_url returned with the different items missing will actually # be different. self.assertNotEqual(old_next_url, new_next_url) def test_multiple_ordering(self): """Test a Pagination with multiple items in the ordering attribute.""" # This will order by: # 1. Even pages # 2. Odd pages # 3. Both of the above will be done in increasing order. # 4. Ordering happens for 1 - 7, then 8 - 14. class TestPagination(_TestPagination): ordering = ['title', 'pages'] self.pagination = TestPagination() PAGE_1 = [2, 4, 6, 1, 3] PAGE_2 = [5, 7, 8, 10, 12] PAGE_3 = [14, 9, 11, 13] # Check that the ordering is as expected. pages = [b.pages for b in self.queryset.order_by('#', *self.pagination.ordering)] self.assertEqual(pages, PAGE_1 + PAGE_2 + PAGE_3) # Now perform pretty much the same test as test_cursor_pagination, but # the ordering will be different. (previous, current, next, previous_url, next_url) = self.get_pages('/') self.assertIsNone(previous) self.assertEqual(current, PAGE_1) self.assertEqual(next, PAGE_2) (previous, current, next, previous_url, next_url) = self.get_pages(next_url) self.assertEqual(previous, PAGE_1) self.assertEqual(current, PAGE_2) self.assertEqual(next, PAGE_3) (previous, current, next, previous_url, next_url) = self.get_pages(next_url) self.assertEqual(previous, PAGE_2) self.assertEqual(current, PAGE_3) self.assertIsNone(next) def test_duplicates(self): """Ensure that pagination works over an 'extreme' number of duplicates.""" PAGES = 100 # This must be unique from other fixture data. # Create a bunch of books that are the same. for i in range(15): book = Book.objects.create(title=str(i), author=self.author, publisher=self.publisher, pages=PAGES) # And use only those duplicate books. self.queryset = QuerySetSequence(Book.objects.filter(pages=PAGES)) titles = [item.title for item in self.queryset] # Look at both the pages (which should all be 1) and the IDs. next_url = '/' for i in range(3): request = Request(factory.get(next_url)) queryset = self.pagination.paginate_queryset(self.queryset, request) titles, pages = zip(*[(item.title, item.pages) for item in queryset]) self.assertEqual(titles, tuple(map(lambda d: str(d + (i * 5)), [0, 1, 2, 3, 4]))) self.assertEqual(pages, (PAGES, ) * 5) next_url = self.pagination.get_next_link() self.assertIsNone(next_url)