过滤使用viewsets Django的REST框架
请考虑以下三种模式:过滤使用viewsets Django的REST框架
class Movie(models.Model):
name = models.CharField(max_length=254, unique=True)
language = models.CharField(max_length=14)
synopsis = models.TextField()
class TimeTable(models.Model):
date = models.DateField()
class Show(models.Model):
day = models.ForeignKey(TimeTable)
time = models.TimeField(choices=CHOICE_TIME)
movie = models.ForeignKey(Movie)
class Meta:
unique_together = ('day', 'time')
而且他们每个人都有自己的序列化:
class MovieSerializer(serializers.HyperlinkedModelSerializer):
movie_id = serializers.IntegerField(read_only=True, source="id")
class Meta:
model = Movie
fields = '__all__'
class TimeTableSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = TimeTable
fields = '__all__'
class ShowSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Show
fields = '__all__'
而且他们的路由器
router.register(r'movie-list', views.MovieViewSet)
router.register(r'time-table', views.TimeTableViewSet)
router.register(r'show-list', views.ShowViewSet)
现在我想通过特定的mov过滤所有的Show对象来获得所有的TimeTable对象(即日期列表)即对象。此代码似乎是工作,并得到像我想要的名单
m = Movie.objects.get(id=request_id)
TimeTable.objects.filter(show__movie=m).distinct()
但我不知道如何在django rest框架中使用这个?我试图做这样(我敢肯定它的错),和我得到的错误:
views.py:
class DateListViewSet(viewsets.ModelViewSet, movie_id):
movie = Movie.objects.get(id=movie_id)
queryset = TimeTable.objects.filter(show__movie=movie).distinct()
serializer_class = TimeTableSerializer
urls.py:
router.register(r'date-list/(?P<movie_id>.+)/', views.DateListViewSet)
错误:
class DateListViewSet(viewsets.ModelViewSet, movie_id): NameError: name 'movie_id' is not defined
如何使用django rest框架中的viewsets进行过滤?或者如果有其他任何优先方式,请将其列出。谢谢。
ModelViewSet
设计假设你想实现一个CRUD(创建,更新,删除)
还有一个ReadOnlyModelViewSet
其仅实现GET
方法只读端点。
对于Movie
和Show
型号,ModelViewSet
或ReadOnlyModelViewSet
是一个不错的选择,无论您是否要实施CRUD。
但是对于描述Movie
模型的日程安排的TimeTable
的相关询问的单独的ViewSet
看起来并不太好。
更好的方法是直接将该端点置于MovieViewSet
。 DRF提供了@detail_route
和@list_route
修饰器。
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)
该终端将可通过movie-list/:id/date_list
网址
Docs about extra routes
错误
class DateListViewSet(viewsets.ModelViewSet, movie_id): NameError: name 'movie_id' is not defined
是因为movie_id
被作为父类DataListViewSet的传递,而不是作为参数,你在documentation想象
这个例子应该是你在找什么。
调整你的网址:
url(r'date-list/(?P<movie_id>.+)/', views.DateListView.as_view())
调整型号:
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')
您的看法是这样的:
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()
另一种方式来做到这一点是:
调整你的网址:
router.register(r'date-list', views.DateListViewSet)
调整模型:
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')
您的看法是这样的:
class DateListViewSet(viewsets.ModelViewSet):
serializer_class = TimeTableSerializer
queryset = TimeTable.objects.all()
filter_backends = (filters.DjangoFilterBackend,)
filter_fields = ('show__movie_id')
,这将使你提出要求,如:
http://example.com/api/date-list?show__movie_id=1
这似乎并不奏效。 –
我认为现在更有意义。 –
注册您的路线
router.register(r'date-list', views.DateListViewSet)
现在改变你的视图集,如下图所示,
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)
使用一个retr ieve方法,它将匹配任何GET请求到端点/date-list/<id>/
。
优点是您不必显式处理序列化并返回响应您使ViewSet能够完成这一难题。我们只是将queryset更新为序列化,其余部分完成。
由于ModelViewSet作为实现,
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
它的实现包括以下方法(HTTP动词和端点上支架)
list()
(GET/date-list/
)create()
( POST/date-list/
)retrieve()
(GETdate-list/<id>/
)update()
(PUT/date-list/<id>/
)partial_update()
(PATCH,/date-list/<id>/
destroy()
(DELETE/date-list/<id>/
)
如果你想只实现retrieve()
(GET请求到端点date-list/<id>/
),你可以做到这一点,而不是一个'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)
为了提高@全是 - 虚荣的回答,您可以明确使用movie_id
作为参数在retrieve
功能,因为你正在重写lookup_field
类属性:
def retrieve(self, request, 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)
您也可以拨打self.get_object()
获取对象:
def retrieve(self, request, movie_id=None):
movie = self.get_object()
self.queryset = TimeTable.objects.filter(show__movie=movie).distinct()
return super(DateListViewSet, self).retrieve(request, *args, **kwargs)
@一切都是空虚对不起,这是一个错字。正确更新。 –