From d36366c0b889fcd8cbeb2a6545ffc690dcd56ed2 Mon Sep 17 00:00:00 2001 From: Hardik Shah Date: Mon, 29 May 2017 22:33:40 +1000 Subject: [PATCH 1/2] Challenge 1, 2 & 3 and test cases added. --- db.sqlite3 | Bin 1011712 -> 1011712 bytes movies/tests.py | 180 ++++++++++++++++++++++++++++++++++++++++++++- movies/urls.py | 9 +++ movies/views.py | 26 ++++++- movietimes/urls.py | 20 +---- 5 files changed, 211 insertions(+), 24 deletions(-) create mode 100644 movies/urls.py diff --git a/db.sqlite3 b/db.sqlite3 index 701d35827f6d0bb8ab41f9fb44b304861ca4ddbd..b18f12aa80d35946b724ad1656afd81892075a18 100644 GIT binary patch delta 2252 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 bB7HEbTp~IV`mv#p^kr~S`BLWUa>?;Ow)>gr diff --git a/movies/tests.py b/movies/tests.py index cb094b4..f51765f 100644 --- a/movies/tests.py +++ b/movies/tests.py @@ -22,11 +22,185 @@ def test_movie_with_actors(self): self.assertEqual(actor.movies.all()[0], movie) +class PaginatedMovieTestCase(TestCase): + + def test_url_without_page_returns_most_recent(self): + + [MovieFactory() for _ in range(140)] + movies = Movie.objects.all().order_by('-release_date', 'title')[:5] + movie_titles = [m.title for m in movies] + + response_page1 = self.client.get('/movies/recent/?page=').json() + self.assertListEqual(response_page1, movie_titles) + + response_page2 = self.client.get('/movies/recent/').json() + self.assertListEqual(response_page2, movie_titles) + + def test_url_with_page_offsets_to_correct_page(self): + + [MovieFactory() for _ in range(140)] + movies = Movie.objects.all().order_by('-release_date', 'title')[20:25] + movie_titles = [m.title for m in movies] + + response_page = self.client.get('/movies/recent/?page=5').json() + self.assertListEqual(response_page, movie_titles) + + def test_url_with_page_out_of_range_display_404(self): + + [MovieFactory() for _ in range(100)] + + response = self.client.get('/movies/recent/?page=21') + self.assertEqual(response.status_code, 404) + + +class RecentMoviesTestCase(TestCase): + + def test_max_number_of_movies_returned_are_5(self): + + [MovieFactory() for _ in range(10)] + response = self.client.get('/movies/recent/') + response_json = response.json() + self.assertLessEqual(len(response_json), 5) + + [MovieFactory() for _ in range(3)] + response = self.client.get('/movies/recent/') + response_json = response.json() + self.assertLessEqual(len(response_json), 5) + + def test_recent_movies_returned_having_same_ratings_are_sorted_by_title(self): + + movies = [ + MovieFactory(release_date='2013-01-05'), + MovieFactory(release_date='2014-02-27', title='Spiderman'), + MovieFactory(release_date='2014-03-15', title='Superman'), + MovieFactory(release_date='2015-08-23'), + MovieFactory(release_date='2017-02-05'), + ] + movie_titles = [m.title for m in reversed(movies)] + + response = self.client.get('/movies/recent/') + response_json = response.json() + + self.assertListEqual(movie_titles, response_json) + + def test_recent_movies_returned_are_sorted_by_ratings(self): + + movies = [ + MovieFactory(release_date='2013-01-05'), + MovieFactory(release_date='2014-02-27'), + MovieFactory(release_date='2014-03-15'), + MovieFactory(release_date='2015-08-23'), + MovieFactory(release_date='2017-02-05'), + ] + movie_titles = [m.title for m in reversed(movies)] + + response = self.client.get('/movies/recent/') + response_json = response.json() + + self.assertListEqual(movie_titles, response_json) + + def test_recent_movies_returns_a_list_of_movie_titles(self): + + movies = [MovieFactory() for _ in range(5)] + movie_titles = [m.title for m in movies] + + response = self.client.get('/movies/recent/') + response_json = response.json() + + for movie_title in movie_titles: + self.assertIn(movie_title, response_json) + + for movie_title in response_json: + self.assertIn(movie_title, movie_titles) + + def test_recent_movies_returns_a_list(self): + response = self.client.get('/movies/recent/') + response_json = response.json() + self.assertIsInstance(response_json, list) + + def test_recent_movies_returns_json(self): + response = self.client.get('/movies/recent/') + self.assertEqual(response['content-type'], 'application/json') + + def test_non_get_requests_return_400(self): + response = self.client.post('/movies/recent/') + self.assertEqual(response.status_code, 400) + + response = self.client.put('/movies/recent/') + self.assertEqual(response.status_code, 400) + + response = self.client.delete('/movies/recent/') + self.assertEqual(response.status_code, 400) + + response = self.client.patch('/movies/recent/') + self.assertEqual(response.status_code, 400) + + response = self.client.head('/movies/recent/') + self.assertEqual(response.status_code, 400) + + def test_get_best_movies_url(self): + response = self.client.get('/movies/recent/') + self.assertEqual(response.status_code, 200) + + class BestMoviesTestCase(TestCase): + def test_no_pagination(self): + + [MovieFactory() for _ in range(140)] + + response_page1 = self.client.get('/movies/best/?page=1').json() + response_page2 = self.client.get('/movies/best/?page=2').json() + + self.assertListEqual(response_page1, response_page2) + + def test_max_number_of_movies_returned_are_5(self): + + [MovieFactory() for _ in range(10)] + response = self.client.get('/movies/best/') + response_json = response.json() + self.assertLessEqual(len(response_json), 5) + + [MovieFactory() for _ in range(3)] + response = self.client.get('/movies/best/') + response_json = response.json() + self.assertLessEqual(len(response_json), 5) + + def test_best_movies_returned_having_same_ratings_are_sorted_by_title(self): + + movies = [ + MovieFactory(rating=5), + MovieFactory(rating=6), + MovieFactory(rating=7, title='Superman'), + MovieFactory(rating=7, title='Spiderman'), + MovieFactory(rating=9), + ] + movie_titles = [m.title for m in reversed(movies)] + + response = self.client.get('/movies/best/') + response_json = response.json() + + self.assertListEqual(movie_titles, response_json) + + def test_best_movies_returned_are_sorted_by_ratings(self): + + movies = [ + MovieFactory(rating=5), + MovieFactory(rating=6), + MovieFactory(rating=7), + MovieFactory(rating=8), + MovieFactory(rating=9), + ] + movie_titles = [m.title for m in reversed(movies)] + + response = self.client.get('/movies/best/') + response_json = response.json() + + self.assertListEqual(movie_titles, response_json) + def test_best_movies_returns_a_list_of_movie_titles(self): - # create 5 random movies - movies = [MovieFactory() for _ in range(140)] + + movies = [MovieFactory() for _ in range(5)] movie_titles = [m.title for m in movies] response = self.client.get('/movies/best/') @@ -38,8 +212,6 @@ def test_best_movies_returns_a_list_of_movie_titles(self): for movie_title in response_json: self.assertIn(movie_title, movie_titles) - self.assertEqual(len(movies), len(response_json)) - def test_best_movies_returns_a_list(self): response = self.client.get('/movies/best/') response_json = response.json() diff --git a/movies/urls.py b/movies/urls.py new file mode 100644 index 0000000..32a2802 --- /dev/null +++ b/movies/urls.py @@ -0,0 +1,9 @@ +from django.conf.urls import url + +from .views import best_movies, recent_movies + +app_name = 'movies' +urlpatterns = [ + url(r'^best/', best_movies, name="best-movies"), + url(r'^recent/', recent_movies, name="recent-movies"), +] diff --git a/movies/views.py b/movies/views.py index 133c7b8..d3094af 100644 --- a/movies/views.py +++ b/movies/views.py @@ -1,4 +1,5 @@ -from django.http import JsonResponse, HttpResponseBadRequest +from django.http import JsonResponse, HttpResponseBadRequest, HttpResponseNotFound +from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage from .models import Movie @@ -8,7 +9,28 @@ def best_movies(request): return HttpResponseBadRequest() movie_titles_list = [] - for movie in Movie.objects.all(): + for movie in Movie.objects.all().order_by('-rating', 'title')[:5]: + movie_titles_list.append(movie.title) + + return JsonResponse(movie_titles_list, safe=False) + + +def recent_movies(request): + if request.method.upper() != 'GET': + return HttpResponseBadRequest() + + paginator = Paginator(Movie.objects.all().order_by('-release_date', 'title'), 5) + page = request.GET.get('page') + + try: + movies = paginator.page(page) + except PageNotAnInteger: + movies = paginator.page(1) + except EmptyPage: + return HttpResponseNotFound() + + movie_titles_list = [] + for movie in movies: movie_titles_list.append(movie.title) return JsonResponse(movie_titles_list, safe=False) diff --git a/movietimes/urls.py b/movietimes/urls.py index e104254..a0cde59 100644 --- a/movietimes/urls.py +++ b/movietimes/urls.py @@ -1,24 +1,8 @@ -"""movietimes URL Configuration - -The `urlpatterns` list routes URLs to views. For more information please see: - https://docs.djangoproject.com/en/1.11/topics/http/urls/ -Examples: -Function views - 1. Add an import: from my_app import views - 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') -Class-based views - 1. Add an import: from other_app.views import Home - 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') -Including another URLconf - 1. Import the include() function: from django.conf.urls import url, include - 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) -""" -from django.conf.urls import url +from django.conf.urls import url, include from django.contrib import admin -from movies.views import best_movies urlpatterns = [ url(r'^admin/', admin.site.urls), - url(r'^movies/best/', best_movies, name="best-movies"), + url(r'^movies/', include('movies.urls')), ] From 02168696c0fdfb1247207054618e309020ddeb00 Mon Sep 17 00:00:00 2001 From: Hardik Shah Date: Mon, 29 May 2017 23:03:39 +1000 Subject: [PATCH 2/2] Added reverse function to remove URL hardcoding --- movies/tests.py | 65 +++++++++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/movies/tests.py b/movies/tests.py index f51765f..423910e 100644 --- a/movies/tests.py +++ b/movies/tests.py @@ -1,4 +1,5 @@ from django.test import TestCase +from django.core.urlresolvers import reverse from .factories import ActorFactory, MovieFactory from .models import Movie @@ -30,10 +31,10 @@ def test_url_without_page_returns_most_recent(self): movies = Movie.objects.all().order_by('-release_date', 'title')[:5] movie_titles = [m.title for m in movies] - response_page1 = self.client.get('/movies/recent/?page=').json() + response_page1 = self.client.get(reverse('movies:recent-movies')+'?page=').json() self.assertListEqual(response_page1, movie_titles) - response_page2 = self.client.get('/movies/recent/').json() + response_page2 = self.client.get(reverse('movies:recent-movies')).json() self.assertListEqual(response_page2, movie_titles) def test_url_with_page_offsets_to_correct_page(self): @@ -42,14 +43,14 @@ def test_url_with_page_offsets_to_correct_page(self): movies = Movie.objects.all().order_by('-release_date', 'title')[20:25] movie_titles = [m.title for m in movies] - response_page = self.client.get('/movies/recent/?page=5').json() + response_page = self.client.get(reverse('movies:recent-movies')+'?page=5').json() self.assertListEqual(response_page, movie_titles) def test_url_with_page_out_of_range_display_404(self): [MovieFactory() for _ in range(100)] - response = self.client.get('/movies/recent/?page=21') + response = self.client.get(reverse('movies:recent-movies')+'?page=21') self.assertEqual(response.status_code, 404) @@ -58,12 +59,12 @@ class RecentMoviesTestCase(TestCase): def test_max_number_of_movies_returned_are_5(self): [MovieFactory() for _ in range(10)] - response = self.client.get('/movies/recent/') + response = self.client.get(reverse('movies:recent-movies')) response_json = response.json() self.assertLessEqual(len(response_json), 5) [MovieFactory() for _ in range(3)] - response = self.client.get('/movies/recent/') + response = self.client.get(reverse('movies:recent-movies')) response_json = response.json() self.assertLessEqual(len(response_json), 5) @@ -78,7 +79,7 @@ def test_recent_movies_returned_having_same_ratings_are_sorted_by_title(self): ] movie_titles = [m.title for m in reversed(movies)] - response = self.client.get('/movies/recent/') + response = self.client.get(reverse('movies:recent-movies')) response_json = response.json() self.assertListEqual(movie_titles, response_json) @@ -94,7 +95,7 @@ def test_recent_movies_returned_are_sorted_by_ratings(self): ] movie_titles = [m.title for m in reversed(movies)] - response = self.client.get('/movies/recent/') + response = self.client.get(reverse('movies:recent-movies')) response_json = response.json() self.assertListEqual(movie_titles, response_json) @@ -104,7 +105,7 @@ def test_recent_movies_returns_a_list_of_movie_titles(self): movies = [MovieFactory() for _ in range(5)] movie_titles = [m.title for m in movies] - response = self.client.get('/movies/recent/') + response = self.client.get(reverse('movies:recent-movies')) response_json = response.json() for movie_title in movie_titles: @@ -114,32 +115,32 @@ def test_recent_movies_returns_a_list_of_movie_titles(self): self.assertIn(movie_title, movie_titles) def test_recent_movies_returns_a_list(self): - response = self.client.get('/movies/recent/') + response = self.client.get(reverse('movies:recent-movies')) response_json = response.json() self.assertIsInstance(response_json, list) def test_recent_movies_returns_json(self): - response = self.client.get('/movies/recent/') + response = self.client.get(reverse('movies:recent-movies')) self.assertEqual(response['content-type'], 'application/json') def test_non_get_requests_return_400(self): - response = self.client.post('/movies/recent/') + response = self.client.post(reverse('movies:recent-movies')) self.assertEqual(response.status_code, 400) - response = self.client.put('/movies/recent/') + response = self.client.put(reverse('movies:recent-movies')) self.assertEqual(response.status_code, 400) - response = self.client.delete('/movies/recent/') + response = self.client.delete(reverse('movies:recent-movies')) self.assertEqual(response.status_code, 400) - response = self.client.patch('/movies/recent/') + response = self.client.patch(reverse('movies:recent-movies')) self.assertEqual(response.status_code, 400) - response = self.client.head('/movies/recent/') + response = self.client.head(reverse('movies:recent-movies')) self.assertEqual(response.status_code, 400) def test_get_best_movies_url(self): - response = self.client.get('/movies/recent/') + response = self.client.get(reverse('movies:recent-movies')) self.assertEqual(response.status_code, 200) @@ -149,20 +150,20 @@ def test_no_pagination(self): [MovieFactory() for _ in range(140)] - response_page1 = self.client.get('/movies/best/?page=1').json() - response_page2 = self.client.get('/movies/best/?page=2').json() + response_page1 = self.client.get(reverse('movies:best-movies')+'?page=1').json() + response_page2 = self.client.get(reverse('movies:best-movies')+'?page=2').json() self.assertListEqual(response_page1, response_page2) def test_max_number_of_movies_returned_are_5(self): [MovieFactory() for _ in range(10)] - response = self.client.get('/movies/best/') + response = self.client.get(reverse('movies:best-movies')) response_json = response.json() self.assertLessEqual(len(response_json), 5) [MovieFactory() for _ in range(3)] - response = self.client.get('/movies/best/') + response = self.client.get(reverse('movies:best-movies')) response_json = response.json() self.assertLessEqual(len(response_json), 5) @@ -177,7 +178,7 @@ def test_best_movies_returned_having_same_ratings_are_sorted_by_title(self): ] movie_titles = [m.title for m in reversed(movies)] - response = self.client.get('/movies/best/') + response = self.client.get(reverse('movies:best-movies')) response_json = response.json() self.assertListEqual(movie_titles, response_json) @@ -193,7 +194,7 @@ def test_best_movies_returned_are_sorted_by_ratings(self): ] movie_titles = [m.title for m in reversed(movies)] - response = self.client.get('/movies/best/') + response = self.client.get(reverse('movies:best-movies')) response_json = response.json() self.assertListEqual(movie_titles, response_json) @@ -203,7 +204,7 @@ def test_best_movies_returns_a_list_of_movie_titles(self): movies = [MovieFactory() for _ in range(5)] movie_titles = [m.title for m in movies] - response = self.client.get('/movies/best/') + response = self.client.get(reverse('movies:best-movies')) response_json = response.json() for movie_title in movie_titles: @@ -213,30 +214,30 @@ def test_best_movies_returns_a_list_of_movie_titles(self): self.assertIn(movie_title, movie_titles) def test_best_movies_returns_a_list(self): - response = self.client.get('/movies/best/') + response = self.client.get(reverse('movies:best-movies')) response_json = response.json() self.assertIsInstance(response_json, list) def test_get_best_movies_url(self): - response = self.client.get('/movies/best/') + response = self.client.get(reverse('movies:best-movies')) self.assertEqual(response.status_code, 200) def test_best_movies_returns_json(self): - response = self.client.get('/movies/best/') + response = self.client.get(reverse('movies:best-movies')) self.assertEqual(response['content-type'], 'application/json') def test_non_get_requests_return_400(self): - response = self.client.post('/movies/best/') + response = self.client.post(reverse('movies:best-movies')) self.assertEqual(response.status_code, 400) - response = self.client.put('/movies/best/') + response = self.client.put(reverse('movies:best-movies')) self.assertEqual(response.status_code, 400) - response = self.client.delete('/movies/best/') + response = self.client.delete(reverse('movies:best-movies')) self.assertEqual(response.status_code, 400) - response = self.client.patch('/movies/best/') + response = self.client.patch(reverse('movies:best-movies')) self.assertEqual(response.status_code, 400) - response = self.client.head('/movies/best/') + response = self.client.head(reverse('movies:best-movies')) self.assertEqual(response.status_code, 400)