Commit 7ab8ff9b by Dave St.Germain

lookup subtitles by language rather than id

parent 982a21df
...@@ -129,13 +129,13 @@ class Subtitle(models.Model): ...@@ -129,13 +129,13 @@ class Subtitle(models.Model):
video = models.ForeignKey(Video, related_name="subtitles") video = models.ForeignKey(Video, related_name="subtitles")
fmt = models.CharField(max_length=20, db_index=True, choices=SUBTITLE_FORMATS) fmt = models.CharField(max_length=20, db_index=True, choices=SUBTITLE_FORMATS)
language = models.CharField(max_length=8, db_index=True) language = models.CharField(max_length=8, db_index=True)
content = models.TextField() content = models.TextField(default='')
def __str__(self): def __str__(self):
return '%s Subtitle for %s' % (self.language, self.video) return '%s Subtitle for %s' % (self.language, self.video)
def get_absolute_url(self): def get_absolute_url(self):
return reverse('subtitle-content', args=[str(self.id)]) return reverse('subtitle-content', args=[self.video.edx_video_id, self.language])
@property @property
def content_type(self): def content_type(self):
......
...@@ -51,7 +51,7 @@ class EncodedVideoSerializer(serializers.ModelSerializer): ...@@ -51,7 +51,7 @@ class EncodedVideoSerializer(serializers.ModelSerializer):
return data.get('profile', None) return data.get('profile', None)
class SubtitleSerializer(serializers.HyperlinkedModelSerializer): class SubtitleSerializer(serializers.ModelSerializer):
""" """
Serializer for Subtitle objects Serializer for Subtitle objects
""" """
...@@ -79,10 +79,8 @@ class SubtitleSerializer(serializers.HyperlinkedModelSerializer): ...@@ -79,10 +79,8 @@ class SubtitleSerializer(serializers.HyperlinkedModelSerializer):
fields = ( fields = (
"fmt", "fmt",
"language", "language",
"id",
"content_url", "content_url",
"url", "content",
"content"
) )
...@@ -93,7 +91,7 @@ class VideoSerializer(serializers.HyperlinkedModelSerializer): ...@@ -93,7 +91,7 @@ class VideoSerializer(serializers.HyperlinkedModelSerializer):
encoded_videos takes a list of dicts EncodedVideo data. encoded_videos takes a list of dicts EncodedVideo data.
""" """
encoded_videos = EncodedVideoSerializer(many=True, allow_add_remove=True) encoded_videos = EncodedVideoSerializer(many=True, allow_add_remove=True)
subtitles = SubtitleSerializer(many=True, allow_add_remove=True) subtitles = SubtitleSerializer(many=True, allow_add_remove=True, required=False)
class Meta: # pylint: disable=C0111 class Meta: # pylint: disable=C0111
model = Video model = Video
......
...@@ -200,7 +200,7 @@ COMPLETE_SET_DIFFERENT_ID_UPDATE_FISH = dict( ...@@ -200,7 +200,7 @@ COMPLETE_SET_DIFFERENT_ID_UPDATE_FISH = dict(
ENCODED_VIDEO_DICT_UPDATE_FISH_MOBILE, ENCODED_VIDEO_DICT_UPDATE_FISH_MOBILE,
ENCODED_VIDEO_DICT_UPDATE_FISH_DESKTOP ENCODED_VIDEO_DICT_UPDATE_FISH_DESKTOP
], ],
subtitles=[SUBTITLE_DICT_SRT], subtitles=[SUBTITLE_DICT_SRT, SUBTITLE_DICT_SJSON],
**VIDEO_DICT_DIFFERENT_ID_FISH **VIDEO_DICT_DIFFERENT_ID_FISH
) )
COMPLETE_SET_FIRST_HALF_UPDATE_FISH = dict( COMPLETE_SET_FIRST_HALF_UPDATE_FISH = dict(
...@@ -208,7 +208,7 @@ COMPLETE_SET_FIRST_HALF_UPDATE_FISH = dict( ...@@ -208,7 +208,7 @@ COMPLETE_SET_FIRST_HALF_UPDATE_FISH = dict(
ENCODED_VIDEO_DICT_UPDATE_FISH_MOBILE, ENCODED_VIDEO_DICT_UPDATE_FISH_MOBILE,
ENCODED_VIDEO_DICT_FISH_DESKTOP ENCODED_VIDEO_DICT_FISH_DESKTOP
], ],
subtitles=[SUBTITLE_DICT_SRT], subtitles=[SUBTITLE_DICT_SRT, SUBTITLE_DICT_SJSON],
**VIDEO_DICT_FISH **VIDEO_DICT_FISH
) )
COMPLETE_SET_UPDATE_ONLY_DESKTOP_FISH = dict( COMPLETE_SET_UPDATE_ONLY_DESKTOP_FISH = dict(
......
...@@ -225,7 +225,7 @@ class GetVideoInfoTestWithHttpCalls(APITestCase): ...@@ -225,7 +225,7 @@ class GetVideoInfoTestWithHttpCalls(APITestCase):
""" """
Tests number of queries for a Video/EncodedVideo(1) pair Tests number of queries for a Video/EncodedVideo(1) pair
""" """
with self.assertNumQueries(5): with self.assertNumQueries(7):
api.get_video_info(constants.COMPLETE_SET_FISH.get("edx_video_id")) api.get_video_info(constants.COMPLETE_SET_FISH.get("edx_video_id"))
def test_get_info_queries_for_one_encoded_video(self): def test_get_info_queries_for_one_encoded_video(self):
...@@ -237,7 +237,7 @@ class GetVideoInfoTestWithHttpCalls(APITestCase): ...@@ -237,7 +237,7 @@ class GetVideoInfoTestWithHttpCalls(APITestCase):
url, constants.COMPLETE_SET_STAR, format='json' url, constants.COMPLETE_SET_STAR, format='json'
) )
self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(response.status_code, status.HTTP_201_CREATED)
with self.assertNumQueries(4): with self.assertNumQueries(5):
api.get_video_info(constants.COMPLETE_SET_STAR.get("edx_video_id")) api.get_video_info(constants.COMPLETE_SET_STAR.get("edx_video_id"))
def test_get_info_queries_for_only_video(self): def test_get_info_queries_for_only_video(self):
......
...@@ -140,6 +140,7 @@ class VideoDetail(APITestCase): ...@@ -140,6 +140,7 @@ class VideoDetail(APITestCase):
Tests PUTting one of two EncodedVideo(s) and then a single EncodedVideo PUT back. Tests PUTting one of two EncodedVideo(s) and then a single EncodedVideo PUT back.
""" """
url = reverse('video-list') url = reverse('video-list')
response = self.client.post(url, constants.COMPLETE_SET_FISH, format='json') response = self.client.post(url, constants.COMPLETE_SET_FISH, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(response.status_code, status.HTTP_201_CREATED)
url = reverse( url = reverse(
...@@ -442,7 +443,7 @@ class VideoListTest(APITestCase): ...@@ -442,7 +443,7 @@ class VideoListTest(APITestCase):
Tests number of queries for a Video/EncodedVideo(2) pair Tests number of queries for a Video/EncodedVideo(2) pair
""" """
url = reverse('video-list') url = reverse('video-list')
with self.assertNumQueries(14): with self.assertNumQueries(16):
self.client.post(url, constants.COMPLETE_SET_FISH, format='json') self.client.post(url, constants.COMPLETE_SET_FISH, format='json')
def test_queries_for_single_encoded_videos(self): def test_queries_for_single_encoded_videos(self):
...@@ -450,7 +451,7 @@ class VideoListTest(APITestCase): ...@@ -450,7 +451,7 @@ class VideoListTest(APITestCase):
Tests number of queries for a Video/EncodedVideo(1) pair Tests number of queries for a Video/EncodedVideo(1) pair
""" """
url = reverse('video-list') url = reverse('video-list')
with self.assertNumQueries(9): with self.assertNumQueries(10):
self.client.post(url, constants.COMPLETE_SET_STAR, format='json') self.client.post(url, constants.COMPLETE_SET_STAR, format='json')
...@@ -490,11 +491,11 @@ class VideoDetailTest(APITestCase): ...@@ -490,11 +491,11 @@ class VideoDetailTest(APITestCase):
self.client.get("/edxval/video/").data self.client.get("/edxval/video/").data
response = self.client.post(url, constants.COMPLETE_SET_FISH, format='json') response = self.client.post(url, constants.COMPLETE_SET_FISH, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(response.status_code, status.HTTP_201_CREATED)
with self.assertNumQueries(7): with self.assertNumQueries(9):
self.client.get("/edxval/video/").data self.client.get("/edxval/video/").data
response = self.client.post(url, constants.COMPLETE_SET_STAR, format='json') response = self.client.post(url, constants.COMPLETE_SET_STAR, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(response.status_code, status.HTTP_201_CREATED)
with self.assertNumQueries(9): with self.assertNumQueries(12):
self.client.get("/edxval/video/").data self.client.get("/edxval/video/").data
...@@ -540,7 +541,7 @@ class SubtitleDetailTest(APITestCase): ...@@ -540,7 +541,7 @@ class SubtitleDetailTest(APITestCase):
self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(response.status_code, status.HTTP_201_CREATED)
video = response.data video = response.data
st = video['subtitles'][0] st = video['subtitles'][0]
url = reverse('subtitle-detail', kwargs={'id': st['id']}) url = reverse('subtitle-detail', kwargs={'video__edx_video_id': video['edx_video_id'], 'language': st['language']})
st['content'] = 'testing 123' st['content'] = 'testing 123'
response = self.client.put( response = self.client.put(
...@@ -561,7 +562,7 @@ class SubtitleDetailTest(APITestCase): ...@@ -561,7 +562,7 @@ class SubtitleDetailTest(APITestCase):
self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(response.status_code, status.HTTP_201_CREATED)
video = response.data video = response.data
st = video['subtitles'][1] st = video['subtitles'][1]
url = reverse('subtitle-detail', kwargs={'id': st['id']}) url = reverse('subtitle-detail', kwargs={'video__edx_video_id': video['edx_video_id'], 'language': st['language']})
st['content'] = 'testing 123' st['content'] = 'testing 123'
response = self.client.put( response = self.client.put(
......
...@@ -14,16 +14,17 @@ urlpatterns = patterns( ...@@ -14,16 +14,17 @@ urlpatterns = patterns(
name="video-list" name="video-list"
), ),
url( url(
r'^edxval/video/(?P<edx_video_id>[-\w]+)', r'^edxval/video/(?P<edx_video_id>[-\w]+)$',
views.VideoDetail.as_view(), views.VideoDetail.as_view(),
name="video-detail" name="video-detail"
), ),
url( url(
r'^edxval/subtitle/(?P<id>[\d]+)$', r'^edxval/video/(?P<video__edx_video_id>[-\w]+)/(?P<language>[-_\w]+)$',
views.SubtitleDetail.as_view(), views.SubtitleDetail.as_view(),
name="subtitle-detail" name="subtitle-detail"
), ),
url(r'^edxval/subtitle/(?P<subtitle_id>[\d]+)/content$', url(
r'^edxval/video/(?P<edx_video_id>[-\w]+)/(?P<language>[-_\w]+)/subtitle$',
views.get_subtitle, views.get_subtitle,
name="subtitle-content" name="subtitle-content"
), ),
......
...@@ -4,6 +4,7 @@ Views file for django app edxval. ...@@ -4,6 +4,7 @@ Views file for django app edxval.
from rest_framework import generics from rest_framework import generics
from django.http import HttpResponse from django.http import HttpResponse
from django.shortcuts import get_object_or_404
from django.views.decorators.http import last_modified from django.views.decorators.http import last_modified
from edxval.models import Video, Profile, Subtitle from edxval.models import Video, Profile, Subtitle
...@@ -13,6 +14,19 @@ from edxval.serializers import ( ...@@ -13,6 +14,19 @@ from edxval.serializers import (
SubtitleSerializer SubtitleSerializer
) )
class MultipleFieldLookupMixin(object):
"""
Apply this mixin to any view or viewset to get multiple field filtering
based on a `lookup_fields` attribute, instead of the default single field filtering.
"""
def get_object(self):
queryset = self.get_queryset() # Get the base queryset
queryset = self.filter_queryset(queryset) # Apply any filter backends
filter = {}
for field in self.lookup_fields:
filter[field] = self.kwargs[field]
return get_object_or_404(queryset, **filter) # Lookup the object
class VideoList(generics.ListCreateAPIView): class VideoList(generics.ListCreateAPIView):
""" """
...@@ -41,20 +55,23 @@ class VideoDetail(generics.RetrieveUpdateDestroyAPIView): ...@@ -41,20 +55,23 @@ class VideoDetail(generics.RetrieveUpdateDestroyAPIView):
serializer_class = VideoSerializer serializer_class = VideoSerializer
class SubtitleDetail(generics.RetrieveUpdateDestroyAPIView): class SubtitleDetail(MultipleFieldLookupMixin, generics.RetrieveUpdateDestroyAPIView):
""" """
Gets a subtitle instance given its id Gets a subtitle instance given its id
""" """
lookup_field = "id" lookup_fields = ("video__edx_video_id", "language")
queryset = Subtitle.objects.all() queryset = Subtitle.objects.all()
serializer_class = SubtitleSerializer serializer_class = SubtitleSerializer
@last_modified(last_modified_func=lambda request, subtitle_id: Subtitle.objects.get(pk=subtitle_id).modified) def _last_modified_subtitle(request, edx_video_id, language):
def get_subtitle(request, subtitle_id): return Subtitle.objects.get(video__edx_video_id=edx_video_id, language=language).modified
@last_modified(last_modified_func=_last_modified_subtitle)
def get_subtitle(request, edx_video_id, language):
""" """
Return content of subtitle by id Return content of subtitle by id
""" """
sub = Subtitle.objects.get(pk=subtitle_id) sub = Subtitle.objects.get(video__edx_video_id=edx_video_id, language=language)
response = HttpResponse(sub.content, content_type=sub.content_type) response = HttpResponse(sub.content, content_type=sub.content_type)
return response return response
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment