Solución:
ModelViewSet
por diseño asume que desea implementar un CRUD (crear, actualizar, eliminar)
También hay una ReadOnlyModelViewSet
que implementa solo el GET
método para leer solo puntos finales.
Para Movie
y Show
modelos, un ModelViewSet
o ReadOnlyModelViewSet
es una buena opción tanto si desea implementar CRUD como si no.
Pero una separada ViewSet
para una consulta relacionada de un TimeTable
que describe un Movie
El horario de la modelo no se ve tan bien.
Un mejor enfoque sería poner ese punto final a un MovieViewSet
directamente. DRF lo proporcionó @detail_route
y @list_route
decoradores.
from rest_framework.response import Response
from rest_framework.decorators import detail_route
class MovieViewSet(viewsets.ModelViewset):
queryset = Movie.objects.all()
serializer_class = MovieSerializer
@detail_route()
def date_list(self, request, pk=None):
movie = self.get_object() # retrieve an object by pk provided
schedule = TimeTable.objects.filter(show__movie=movie).distinct()
schedule_json = TimeTableSerializer(schedule, many=True)
return Response(schedule_json.data)
Este punto final estará disponible por un movie-list/:id/date_list
url
Documentos sobre rutas adicionales
El error
class DateListViewSet (viewsets.ModelViewSet, movie_id): NameError: el nombre ‘movie_id’ no está definido
sucede porque movie_id
se pasa como clase principal de DataListViewSet y no como parámetro como imaginó
Este ejemplo en la documentación debería ser lo que está buscando.
Ajusta tu URL:
url(r'date-list/(?P<movie_id>.+)/', views.DateListView.as_view())
Ajuste su modelo:
class Show(models.Model):
day = models.ForeignKey(TimeTable, related_name="show")
time = models.TimeField(choices=CHOICE_TIME)
movie = models.ForeignKey(Movie)
class Meta:
unique_together = ('day', 'time')
Su vista se vería así:
class DateListView(generics.ListAPIView):
serializer_class = TimeTableSerializer
def get_queryset(self):
movie = Movie.objects.get(id=self.kwargs['movie_id'])
return TimeTable.objects.filter(show__movie=movie).distinct()
Otra forma de hacerlo sería:
Ajusta tu URL:
router.register(r'date-list', views.DateListViewSet)
Ajuste su modelo:
class Show(models.Model):
day = models.ForeignKey(TimeTable, related_name="show")
time = models.TimeField(choices=CHOICE_TIME)
movie = models.ForeignKey(Movie)
class Meta:
unique_together = ('day', 'time')
Su vista se vería así:
class DateListViewSet(viewsets.ModelViewSet):
serializer_class = TimeTableSerializer
queryset = TimeTable.objects.all()
filter_backends = (filters.DjangoFilterBackend,)
filter_fields = ('show__movie_id')
Lo cual te permitirá realizar solicitudes como:
http://example.com/api/date-list?show__movie_id=1
Ver documentación
Registre su ruta como
router.register(r'date-list', views.DateListViewSet)
ahora cambie su conjunto de vistas como se muestra a continuación,
class DateListViewSet(viewsets.ModelViewSet):
queryset = TimeTable.objects.all()
serializer_class = TimeTableSerializer
lookup_field = 'movie_id'
def retrieve(self, request, *args, **kwargs):
movie_id = kwargs.get('movie_id', None)
movie = Movie.objects.get(id=movie_id)
self.queryset = TimeTable.objects.filter(show__movie=movie).distinct()
return super(DateListViewSet, self).retrieve(request, *args, **kwargs)
Utilice un método de recuperación, que hará coincidir cualquier solicitud GET con el punto final /date-list/<id>/
.
La ventaja es que no tiene que manejar explícitamente la serialización y devolver la respuesta hace que ViewSet haga esa parte difícil. Solo estamos actualizando el conjunto de consultas para ser serializado y rest framework hace el resto.
Dado que ModelViewSet se implementa como,
class ModelViewSet(mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
GenericViewSet):
"""
A viewset that provides default `create()`, `retrieve()`, `update()`,
`partial_update()`, `destroy()` and `list()` actions.
"""
pass
Su implementación incluye los siguientes métodos (verbo HTTP y punto final en corchetes)
-
list()
(OBTENER/date-list/
) -
create()
(CORREO/date-list/
) retrieve()
(OBTENERdate-list/<id>/
)update()
(PONER/date-list/<id>/
)partial_update()
(PARCHE,/date-list/<id>/
destroy()
(ELIMINAR/date-list/<id>/
)
Si solo desea implementar el retrieve()
(OBTENER solicitudes al punto final date-list/<id>/
), puede hacer esto en lugar de un `ModelViewSet),
from rest_framework import mixins, views
class DateListViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
queryset = TimeTable.objects.all()
serializer_class = TimeTableSerializer
lookup_field = 'movie_id'
def retrieve(self, request, *args, **kwargs):
movie_id = kwargs.get('movie_id', None)
movie = Movie.objects.get(id=movie_id)
self.queryset = TimeTable.objects.filter(show__movie=movie).distinct()
return super(DateListViewSet, self).retrieve(request, *args, **kwargs)