Skip to content

Commit 3064b74

Browse files
committed
Added listing views and tests
1 parent 2150c21 commit 3064b74

8 files changed

Lines changed: 232 additions & 74 deletions

File tree

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# -*- coding: utf-8 -*-
2+
# Generated by Django 1.11.13 on 2018-05-19 15:34
3+
from __future__ import unicode_literals
4+
5+
from django.db import migrations, models
6+
7+
8+
class Migration(migrations.Migration):
9+
10+
dependencies = [
11+
('shiptrader', '0002_auto_20180519_1004'),
12+
]
13+
14+
operations = [
15+
migrations.AddField(
16+
model_name='listing',
17+
name='active',
18+
field=models.BooleanField(default=True),
19+
),
20+
]

shiptrader/models.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,15 @@ class Starship(models.Model):
1515
crew = models.IntegerField()
1616
passengers = models.IntegerField()
1717

18+
def __str__(self):
19+
return self.name
20+
1821

1922
class Listing(models.Model):
2023
name = models.CharField(max_length=255)
2124
ship_type = models.ForeignKey(Starship, related_name='listings')
2225
price = models.IntegerField()
2326

27+
active = models.BooleanField(default=True)
28+
2429
created = models.DateTimeField(auto_now_add=True)

shiptrader/serializers.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from shiptrader.models import Starship, Listing
2+
from rest_framework import serializers
3+
4+
5+
class StarshipSerializer(serializers.ModelSerializer):
6+
class Meta:
7+
model = Starship
8+
fields = '__all__'
9+
10+
11+
class ListingSerializer(serializers.ModelSerializer):
12+
class Meta:
13+
model = Listing
14+
fields = '__all__'
15+
16+
17+
class ListingUpdateSerializer(serializers.ModelSerializer):
18+
class Meta:
19+
model = Listing
20+
fields = ('active',)

shiptrader/tests/test_starships.py

Lines changed: 0 additions & 58 deletions
This file was deleted.

shiptrader/tests/test_views.py

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
import json
2+
from urllib.parse import urlencode
3+
4+
from django.test import TestCase
5+
from rest_framework.reverse import reverse
6+
7+
from shiptrader.models import Starship, Listing
8+
9+
10+
class TestStarshipView(TestCase):
11+
12+
@classmethod
13+
def setUpTestData(cls):
14+
ships = get_ship_test_data()
15+
16+
for ship in ships:
17+
Starship.objects.create(**ship)
18+
19+
def tearDown(self):
20+
Listing.objects.all().delete()
21+
22+
def test_can_get_starships(self):
23+
response = self.client.get(reverse('starship-list'))
24+
self.assertEqual(response.status_code, 200)
25+
26+
starships = response.data
27+
expected_data = get_ship_test_data()
28+
29+
self.assertEqual(len(starships), len(expected_data))
30+
31+
for i in range(len(expected_data)):
32+
self.assertGreater(starships[i].pop('id'), 0)
33+
self.assertDictEqual(starships[i], expected_data[i])
34+
35+
def test_can_get_listings(self):
36+
ship = Starship.objects.get(name='Ship 1')
37+
38+
self.client.post(reverse('listing-list'), {'name':'New Listing 1', 'price': 5,
39+
'ship_type': ship.id, 'active': False})
40+
41+
listing = Listing.objects.all().first()
42+
43+
self.assertEqual(listing.name, 'New Listing 1')
44+
self.assertEqual(listing.price, 5)
45+
self.assertEqual(listing.ship_type, ship)
46+
self.assertEqual(listing.active, False)
47+
48+
def test_can_create_listings(self):
49+
50+
ship = Starship.objects.get(name='Ship 1')
51+
Listing.objects.create(name='Another New Listing', price=10, ship_type=ship)
52+
53+
response = self.client.get(reverse('listing-list'))
54+
55+
self.assertEqual(response.status_code, 200)
56+
57+
self.assertEqual(len(response.data), 1)
58+
self.assertEqual(response.data[0]['name'], 'Another New Listing')
59+
self.assertEqual(response.data[0]['ship_type'], ship.id)
60+
self.assertEqual(response.data[0]['price'], 10)
61+
self.assertEqual(response.data[0]['active'], True)
62+
63+
def test_can_filter_by_class(self):
64+
for ship in Starship.objects.all():
65+
Listing.objects.create(name='Listing', price=10, ship_type=ship)
66+
67+
url = '{0}?{1}'.format(reverse('listing-list'),
68+
urlencode({'ship_type__starship_class': 'Class 2'}))
69+
response = self.client.get(url)
70+
71+
self.assertEqual(response.status_code, 200)
72+
self.assertEqual(len(response.data), 2)
73+
74+
ship_ids = [s.id for s in Starship.objects.filter(starship_class='Class 2')]
75+
self.assertTrue(response.data[0]['ship_type'] in ship_ids)
76+
self.assertTrue(response.data[1]['ship_type'] in ship_ids)
77+
78+
def test_can_sort_by_price(self):
79+
ships = Starship.objects.all()
80+
Listing.objects.create(name='Listing', price=10, ship_type=ships[0])
81+
Listing.objects.create(name='Listing', price=20, ship_type=ships[1])
82+
Listing.objects.create(name='Listing', price=15, ship_type=ships[2])
83+
84+
response = self.client.get('{0}?{1}'.format(reverse('listing-list'), urlencode({'ordering': '-price'})))
85+
self.assertEqual(response.data[0]['price'], 20)
86+
self.assertEqual(response.data[1]['price'], 15)
87+
self.assertEqual(response.data[2]['price'], 10)
88+
89+
response = self.client.get('{0}?{1}'.format(reverse('listing-list'), urlencode({'ordering': 'price'})))
90+
self.assertEqual(response.data[0]['price'], 10)
91+
self.assertEqual(response.data[1]['price'], 15)
92+
self.assertEqual(response.data[2]['price'], 20)
93+
94+
def test_can_sort_by_created(self):
95+
ships = Starship.objects.all()
96+
Listing.objects.create(name='Listing A', price=1, ship_type=ships[0])
97+
Listing.objects.create(name='Listing B', price=1, ship_type=ships[1])
98+
Listing.objects.create(name='Listing C', price=1, ship_type=ships[2])
99+
100+
response = self.client.get('{0}?{1}'.format(reverse('listing-list'), urlencode({'ordering': '-created'})))
101+
self.assertEqual(response.data[0]['name'], 'Listing C')
102+
self.assertEqual(response.data[1]['name'], 'Listing B')
103+
self.assertEqual(response.data[2]['name'], 'Listing A')
104+
105+
response = self.client.get('{0}?{1}'.format(reverse('listing-list'), urlencode({'ordering': 'created'})))
106+
self.assertEqual(response.data[0]['name'], 'Listing A')
107+
self.assertEqual(response.data[1]['name'], 'Listing B')
108+
self.assertEqual(response.data[2]['name'], 'Listing C')
109+
110+
def test_can_toggle_active(self):
111+
112+
listing = Listing.objects.create(name='Listing', price=10, ship_type=Starship.objects.first(), active=False)
113+
114+
print(reverse('listing-detail', args=[listing.id]))
115+
116+
response = self.client.patch(reverse('listing-detail', args=[listing.id]), json.dumps({'active': True}),
117+
content_type='application/json')
118+
listing = Listing.objects.get(id=listing.id)
119+
120+
self.assertEqual(response.status_code, 200)
121+
self.assertTrue(listing.active)
122+
123+
124+
def get_ship_test_data():
125+
return [
126+
{
127+
'name': 'Ship 1',
128+
'model': 'Model 1',
129+
'starship_class': 'Class 1',
130+
'manufacturer': 'Manufacturer 1',
131+
'length': 11.0,
132+
'hyperdrive_rating': 12.0,
133+
'cargo_capacity': 13,
134+
'crew': 14,
135+
'passengers': 15
136+
},
137+
{
138+
'name': 'Ship 2a',
139+
'model': 'Model 2a',
140+
'starship_class': 'Class 2',
141+
'manufacturer': 'Manufacturer 2',
142+
'length': 21.0,
143+
'hyperdrive_rating': 22.0,
144+
'cargo_capacity': 23,
145+
'crew': 24,
146+
'passengers': 25
147+
},
148+
{
149+
'name': 'Ship 2b',
150+
'model': 'Model 2b',
151+
'starship_class': 'Class 2',
152+
'manufacturer': 'Manufacturer 2',
153+
'length': 21.0,
154+
'hyperdrive_rating': 22.0,
155+
'cargo_capacity': 23,
156+
'crew': 24,
157+
'passengers': 25
158+
}
159+
160+
]

shiptrader/views.py

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,31 @@
1-
from rest_framework import serializers, viewsets
1+
from django_filters.rest_framework import DjangoFilterBackend
2+
from rest_framework import mixins
3+
from rest_framework.viewsets import GenericViewSet
4+
from rest_framework.filters import OrderingFilter
25

3-
from shiptrader.models import Starship
6+
from shiptrader.models import Starship, Listing
7+
from shiptrader.serializers import StarshipSerializer, ListingSerializer, ListingUpdateSerializer
48

59

6-
class StarshipSerializer(serializers.ModelSerializer):
7-
class Meta:
8-
model = Starship
9-
fields = '__all__'
10-
11-
12-
class StarshipViewSet(viewsets.ReadOnlyModelViewSet):
10+
class StarshipViewSet(mixins.ListModelMixin, GenericViewSet):
1311
"""View that allows all starships to be listed"""
1412

1513
queryset = Starship.objects.all()
1614
serializer_class = StarshipSerializer
15+
16+
17+
class ListingViewSet(mixins.CreateModelMixin, mixins.ListModelMixin, GenericViewSet):
18+
"""View to create and list ship listings"""
19+
20+
queryset = Listing.objects.all()
21+
serializer_class = ListingSerializer
22+
filter_backends = (DjangoFilterBackend, OrderingFilter)
23+
filter_fields = ('ship_type__starship_class',)
24+
ordering_fields = ('price', 'created')
25+
26+
27+
class ListingActiveViewSet(mixins.UpdateModelMixin, GenericViewSet):
28+
"""View to update listing to active / inactive"""
29+
30+
queryset = Listing.objects.all()
31+
serializer_class = ListingUpdateSerializer

testsite/settings.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,3 @@
130130
# https://docs.djangoproject.com/en/1.11/howto/static-files/
131131

132132
STATIC_URL = '/static/'
133-
134-
135-
REST_FRAMEWORK = {
136-
'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
137-
}

testsite/urls.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@
1717
from django.contrib import admin
1818
from rest_framework import routers
1919

20-
from shiptrader.views import StarshipViewSet
20+
from shiptrader.views import StarshipViewSet, ListingViewSet, ListingActiveViewSet
2121

2222
router = routers.DefaultRouter()
2323
router.register(r'starships', StarshipViewSet)
24-
24+
router.register(r'listings', ListingViewSet)
25+
router.register(r'listings', ListingActiveViewSet)
2526

2627
urlpatterns = [
2728
url(r'^admin/', admin.site.urls),

0 commit comments

Comments
 (0)