添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

如何用django rest框架从一个GET请求的查询参数中过滤出多个id?

13 人关注

我正在尝试制作一个网络应用程序的API。 我想做一个API请求,可以提交多个ID。

The django rest框架教程 展示了如何从一个模型中获取所有记录。 比如说 http://127.0.0.1:8000/snippets/ 将返回所有片段记录。 该教程还展示了如何从一个模型中检索一个单项。 http://127.0.0.1:8000/snippets/2/ will return only snippet record with pk=2.

我希望能够申请多个记录,但不是所有记录。

我怎样才能改变这段代码,以便我可以请求多个片段?

snippets/urls.py

from django.conf.urls import url
from snippets import views
urlpatterns = [
    url(r'^snippets/$', views.snippet_list),
    url(r'^snippets/(?P<pk>[0-9]+)/$', views.snippet_detail),

snippets/views.py

def snippet_detail(request, *pk):
        snippet = Snippet.objects.filter(pk__in=pk)
    except Snippet.DoesNotExist:
        return HttpResponse(status=404)
    if request.method == 'GET':
        serializer = SnippetSerializer(snippet)
        return JSONResponse(serializer.data)
    
2 个评论
多个片段基于什么?你拉或不拉一个片段的标准是什么?
@Gocht So like... 127.0.0.1:8000/snippets/2;3;4 如果我想要ID为2、3和4的片段
python
django
django-models
django-rest-framework
cameron-f
cameron-f
发布于 2015-10-01
7 个回答
Gocht
Gocht
发布于 2021-07-26
已采纳
0 人赞同

根据你的评论,你可以通过URL发送ID。

127.0.0.1:8000/snippets/?ids=2,3,4

而在你看来

ids = request.GET.get('ids') # u'2,3,4' <- this is unicode ids = ids.split(',') # [u'2',u'3',u'4'] <- this is a list of unicodes with ids values

然后你可以查询到Snippet模型。

Snippet.objects.filter(pk__in=ids)

如果url中的id之间有空格,这可能会给你带来一些问题。

127.0.0.1:8000/snippets/?ids=2, 3 , 4

你可能需要在执行查询之前处理每个值

harringr
harringr
发布于 2021-07-26
0 人赞同

我发现这个方法是可行的,按照Django REST框架的主要教程,然后是关于Django REST框架的文档。 根据查询参数进行过滤 ,稍作调整。 这允许一个网址从两个GET请求中返回数据:一个返回id与参数相符的对象,另一个返回所有对象,当没有提供参数时。

  • http://127.0.0.1:8000/snippets/ returns all snippets
  • http://127.0.0.1:8000/snippets/?ids=2,3,7 returns only snippets with id 2, 3 and 7
  • snippets/urls.py

    from django.conf.urls import url
    from snippets import views
    urlpatterns = [
       .... (code for other urls here)
       url(r'^snippets/$', views.SnippetList.as_view(), name='snippet-list'),
    

    snippets/views.py

    from snippet.serializers import SnippetSerializer class SnippetList(generics.ListCreateAPIView): serializer_class = SnippetSerializer def get_queryset(self): # Get URL parameter as a string, if exists ids = self.request.query_params.get('ids', None) # Get snippets for ids if they exist if ids is not None: # Convert parameter string to list of integers ids = [ int(x) for x in ids.split(',') ] # Get objects for all parameter ids queryset = Product.objects.filter(pk__in=ids) else: # Else no parameters, return all objects queryset = Product.objects.all() return queryset

    片段/序列化器.py

    class SnippetSerializer(serializers.ModelSerializer): class Meta: model = Snippet fields = ('url', 'id', 'title', 'code', 'linenos', 'language', 'style')
    谢谢!这也适用于viewsets.ModelViewSet类,你只需要在注册路由器时加入参数'base_name',像这样:router.register(question', views.QuestionViewSet, base_name=question')
    Dap
    Dap
    发布于 2021-07-26
    0 人赞同

    你可以使用 django-filter 并将其设置为一个过滤器,避免在viewset上的get_queryset方法上过度使用。

    Given this request

    /api/snippets/?ids=1,2,3,4
    

    然后写一个django过滤器集和方法

    import django_filters
    def filter_by_ids(queryset, name, value):
        values = value.split(',')
        return queryset.filter(id__in=values)
    class SnippetFilterSet(django_filters.FilterSet):
       ids = django_filters.CharFilter(method=filter_by_ids)
       class Meta:
          model = Snippet
          fields = ['ids']
    

    然后在你的ModelViewSet中

    from rest_framework.viewsets import ModelViewSet
    from app.snippets.models import Snippet
    from app.snippets.filters import SnippetFilterSet # path to filterset
    class SnippetView(ModelViewSet):
        queryset = Snippet.objects.all()
        serializer_class = SnippetSerializer
        filterset_class = SnippetFilterSet
        
    我已经有了其他的 fields ,是用字典语法指定的。例如: fields = { 'foo': ('lt', 'lte', 'exact', 'gt', 'gte') } 。如何将 ids 整合到该词典中?
    Yahya Yahyaoui
    Yahya Yahyaoui
    发布于 2021-07-26
    0 人赞同

    一个可能的方法是将pk(s)的清单作为GET请求数据发送,类似这样。

  • GET request to "/snippets"

  • Request body: {"list_of_pk": [1,2,3...]}

  • snippets/urls.py

    from django.conf.urls import url
    from snippets import views
    urlpatterns = [
        url(r'^snippets/$', views.snippet_list),
        url(r'^snippets/(?P<pk>[0-9]+)/$', views.snippet_detail),
    

    snippets/views.py

    def snippet_list(request):
        if request.method == 'GET':
            pk_list = request.GET.get('list_of_pk')
            if pk_list:
                snippets = Snippet.objects.filter(pk__in=pk_list)
            else:
                snippets = Snippet.objects.all()
            #the serialization...
        
    cameron-f
    cameron-f
    发布于 2021-07-26
    0 人赞同

    这就是我最后的选择。

    snippet/urls.py

    from django.conf.urls import url
    from snippets import views
    urlpatterns = [
        url(r'^snippets/$', views.snippet_list),
        url(r'^snippets/(?P<pk>[0-9]+)/$', views.snippet_detail),
    

    http://127.0.0.1:8000/snippets/?ids=2,3,4 is received by

    snippet/views.py

    from rest_framework.decorators import api_view
    @api_view(['GET', 'POST'])    
    def snippet_list(request):
        if request.method == 'GET':
            ids = request.query_params.get('ids')  # u'2,3,4' <- this is unicode
            ids = ids.split(',')
            snippets = Snippet.objects.filter(pk__in=ids)
            serializer = SnippetSerializer(snippet, many=True)
            return JSONResponse(serializer.data)
        
    ambi
    ambi
    发布于 2021-07-26
    0 人赞同

    While there is no definitive standard, most web frameworks allow multiple values to be associated with a single field (e.g. field1=value1&field1=value2&field2=value3).

    Django也支持这一点。 要获得数值的列表,你可以使用。 ids = request.GET.getlist('ids') 。 更多的例子来自 MultiValueDict 文档。

        >>> d = MultiValueDict({'name': ['Adrian', 'Simon'], 'position': ['Developer']})
        >>> d['name']
        'Simon'
        >>> d.getlist('name')
        ['Adrian', 'Simon']
        >>> d.getlist('doesnotexist')
        >>> d.getlist('doesnotexist', ['Adrian', 'Simon'])
        ['Adrian', 'Simon']
        >>> d.get('lastname', 'nonexistent')
        'nonexistent'
        >>> d.setlist('lastname', ['Holovaty', 'Willison'])
        
    Slava
    Slava
    发布于 2021-07-26
    0 人赞同

    django-filter文档给出了一个很好的例子,如何做到这一点。 https://django-filter.readthedocs.io/en/stable/ref/filters.html?highlight=ids#baseinfilter

    对于你的情况。

    class SnippetFilterSet(BaseInFilter, NumberFilter):
    class F(FilterSet):