[英]Filtering by Foreign Key in ViewSet, django-rest-framework
I want my api to return certain objects from a database based on the foreign key retrieved from the url path.我希望我的 api 根据从 url 路径检索到的外键从数据库中返回某些对象。 If my url looks like api/get-club-players/1
I want every player object with matching club id (in this case club.id == 1
).如果我的 url 看起来像api/get-club-players/1
我希望每个玩家 object 都具有匹配的俱乐部 ID(在本例中club.id == 1
)。 I'm pasting my code down below:我在下面粘贴我的代码:
models.py模型.py
class Club(models.Model):
name = models.CharField(max_length=25)
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True)
def __str__(self):
return self.name
class Player(models.Model):
name = models.CharField(max_length=30)
club = models.ForeignKey(Club, on_delete=models.SET_NULL, blank=True, null=True)
def __str__(self):
return self.name
serialziers.py序列化器.py
class ClubSerializer(serializers.ModelSerializer):
class Meta:
model = Club
fields = 'id', 'owner', 'name'
class PlayerSerializer(serializers.ModelSerializer):
class Meta:
model = Player
fields = 'id', 'name', 'offense', 'defence', 'club', 'position'
views.py, This is the part where I get the most trouble with: views.py,这是我最麻烦的部分:
class ClubViewSet(viewsets.ModelViewSet):
queryset = Club.objects.all()
serializer_class = ClubSerializer
class PlayerViewSet(viewsets.ModelViewSet):
queryset = Player.objects.all()
serializer_class = PlayerSerializer
class GetClubPlayersViewSet(viewsets.ViewSet):
def list(self, request):
queryset = Player.objects.all()
serializer = PlayerSerializer(queryset, many=True)
def retrieve(self,request, clubId):
players = Player.objects.filter(club=clubId, many=True)
if not players:
return JsonResponse({'error': "No query found!"})
else:
serializer = PlayerSerializer(players)
return Response(serializer.data)
urls.py网址.py
from rest_framework import routers
from django.urls import path, include
from .views import (GameViewSet, PlayerViewSet, ClubViewSet,
GetClubPlayersViewSet, create_club, set_roster)
router = routers.DefaultRouter()
router.register(r'clubs', ClubViewSet, basename="clubs")
router.register(r'players', PlayerViewSet, basename="players")
router.register(r'get-club-players', GetClubPlayersViewSet, basename="club-players")
urlpatterns = [
path('', include(router.urls)),
]
EDIT: Now views.py looks like that:编辑:现在 views.py 看起来像这样:
class GetClubPlayersViewSet(viewsets.ViewSet):
queryset = Player.objects.all()
def list(self, request):
serializer = PlayerSerializer(self.queryset, many=True)
return Response(serializer.data)
def retrieve(self, request, *args, **kwargs):
clubId = kwargs['get-club-players']
players = Player.objects.filter(club=clubId, many=True)
if not players:
return JsonResponse({'error': "No query found!"})
else:
serializer = PlayerSerializer(players)
return Response(serializer.data)
http://127.0.0.1:8000/api/get-club-players/
returns all of the player objects, but when I ad a clubId into url I get this error: http://127.0.0.1:8000/api/get-club-players/
返回所有玩家对象,但是当我将 clubId 广告到 url 中时,我收到此错误:
EDIT 2 :编辑 2 :
class GetClubPlayersViewSet(viewsets.ViewSet):
queryset = Player.objects.all()
def retrieve(self, request, *args, **kwargs):
queryParams = self.request.GET.get('abc')
if queryParams is None:
queryset = Player.objects.none()
else:
queryset = Player.objects.filter(club = queryParams)
serializer = PlayerSerializer(queryset)
return Response(serializer.data)
def list(self, request):
serializer = PlayerSerializer(self.queryset, many=True)
return Response(serializer.data)
You can get url parameters using kwargs attribute.您可以使用 kwargs 属性获取 url 参数。 You will need to modify the signature of your retrieve method for it.您将需要为它修改您的检索方法的签名。
def retrieve(self, request, *args, **kwargs):
clubId = self.kwargs['get-club-players']
players = Player.objects.filter(club=clubId, many=True)
....
EDIT编辑
For the queryset error, it is due to DRF requiring either the queryset
class attribute or implementation of get_queryset()
function.对于查询集错误,这是由于 DRF 需要查询集 class 属性或queryset
get_queryset()
function 的实现。 In your case, you can get around it like this:在您的情况下,您可以像这样解决它:
class GetClubPlayersViewSet(viewsets.ViewSet):
queryset = Player.objects.all()
def list(self, request):
serializer = PlayerSerializer(self.queryset, many=True)
So you can define your queryset like -所以你可以定义你的查询集 -
def get_queryset(self):
queryParams == self.request.GET.get('abc') # get queryparameter from url
if queryParams is None:
#queryset = anyModel.objects.all()
queryset = anyModel.objects.none()
else:
queryset = anyModel.objects.filter(anyProperty = queryParams)
return queryset
and your url will be like -你的 url 会像 -
api/get-club-players/?abc=1
this abc can be id or any other property from the model.此abc可以是id或来自 model 的任何其他属性。
Use this get_queryset logic in your retrieve method.在您的检索方法中使用此 get_queryset 逻辑。
rest_framework.viewsets.ViewSet
has an attribute named lookup_field
which you can override. rest_framework.viewsets.ViewSet
有一个名为lookup_field
的属性,您可以覆盖它。 By default the value of lookup_field
is id
.默认情况下, lookup_field
的值为id
。
When adding the viewset in router, the lookup_field
is added as the argument name in the url (eg /api/get-club-players/:id/
).在路由器中添加视图集时, lookup_field
作为参数名称添加到 url 中(例如/api/get-club-players/:id/
)。
You can either override the lookup_field
of GetClubPlayersViewSet
or access the correct kwargs key by changing clubId = kwargs['get-club-players']
to clubId = kwargs['id']
您可以覆盖lookup_field
的GetClubPlayersViewSet
或通过将clubId = kwargs['get-club-players']
更改为clubId = kwargs['id']
来访问正确的 kwargs 键
Or a bit of both:或两者兼而有之:
class GetClubPlayersViewSet(viewsets.ViewSet):
lookup_field = "clubId"
queryset = Player.objects.all()
# ....
def retrieve(self, request, *args, **kwargs):
clubId = kwargs[self.lookup_field]
players = Player.objects.filter(club=clubId, many=True)
if not players:
return JsonResponse({'error': "No query found!"})
else:
serializer = PlayerSerializer(players)
return Response(serializer.data)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.