使用两个或多个不同的键查找Django模型

2024-03-29 14:54:28 发布

您现在位置:Python中文网/ 问答频道 /正文

第一次开发django应用程序,我尝试做一些非标准的事情。。。在

有没有一种方法可以配置一个视图,允许用户通过两个唯一的模型属性中的一个来查找某个模型。在

理想情况下,这两种URL方案都是可能的

urlpatterns = [
   path('api/somemodel/<int:model_id>/', views.SomeModelDetailView.as_view())
   path('api/somemodel/<str:model_name>/', views.SomeModelDetailView.as_view())
]

一个简化的示例模型。。。id和名称都保证是唯一的。另外,按照惯例,我的数据是以这样一种方式输入的:名称永远是字符串,而不是整数

^{pr2}$

目前,我有这个工作与以下观点。。。在

from rest_framework import generics
from rest_framework import status           
from rest_framework.response import Response

from . import models

class SomeModelDetailView(generics.RetrieveAPIView):                                                                                                                                                                       
    queryset = models.SomeModel.objects.all()                                                                             
    serializer_class = serializers.SomeModelSerializer                                                                    

    def get(self, request, model_name=None, model_id=None, format=None):                                            

        field = None                                                                                                    
        key = None                                                                                                      
        try:                                                                                                            
            if model_id:                                                                                              
                field = "model_id"                                                                                    
                key = model_id
                m = models.SomeModel.objects.get(id=model_id)                                                     
            elif model_name:                                                                                          
                field = "model_name"                                                                                  
                key = model_name
                m = models.SomeModel.objects.get(name=model_name)                                                 
            else:                                                                                                       
                return Response("Neither model_id nor model_name were provided", status=status.HTTP_400_BAD_REQUEST)
        except models.SomeModel.DoesNotExist:                                                                             
            return Response("Unknown {field}: {key}".format(field=field, key=key), status=status.HTTP_400_BAD_REQUEST)  

        serializer_class = self.get_serializer_class()                                                                  
        serializer = serializer_class(m)                                                                          

        return Response(serializer.data)    

但是,我想知道是否有更好的方法更适合ViewSet/Router(或其他)DRF机制。在

有什么想法吗?在


Tags: keynamefromimportnoneidfieldget
3条回答

我相信您可以用一种通用的方法来完成,首先将urlptenr更改为:

   urlpatterns = [
   path('api/somemodel/<str:pk>/', views.SomeModelDetailView.as_view()),
] ### this path matches both of the keys you wanted str and integer(integer is a str too)

然后在视图中,您只需以这种方式重写get_object()(不要重写get()这不是drf的方式):

^{pr2}$

使用Django所称的“qobjects”是可能的。它们允许您对查询执行逻辑操作,允许您查询id=model_id或{}。在

例如:

from django.db.models import Q
...
m = models.SomeModel.objects.get(Q(id=model_id) | Q(name=model_name))
...

我认为现有的两个答案(Don's和changak's)都是非常有用的。。。但是我想更进一步。在

这就是我最后得出的结论——它的灵感来自于Changak的答案,不过,这个答案稍微更一般一些

class MultiKeyGetObject(generics.GenericAPIView):
    def __init__(self):
        if not hasattr(self, 'lookup_fields'):
            raise AssertionError("Expected view {} to have `.lookup_fields` attribute".format(self.__class__.__name__))

    def get_object(self):
        for field in self.lookup_fields:
            if field in self.kwargs:
                self.lookup_field = field
                break
        else:
            raise AssertionError(
                'Expected view %s to be called with one of the lookup_fields: %s' %
                (self.__class__.__name__, self.lookup_fields))

        return super().get_object()

我还喜欢从Don学习Q对象-我可以想象一个用例,在这个用例中,您将希望使用所有查找字段(an AND或or)来检索对象。我觉得这是进入过滤领域,但它可能是有用的。。。在

^{pr2}$

以上两种方法都可以用于视图,例如。。。在

class SomeObjectDetailAPIView(MultiKeyGetObject, generics.RetrieveUpdateDestroyAPIView):
    serializer_class = serializers.SomeModelSerializer                                 
    queryset = models.SomeModel.objects.all()                                          
    lookup_fields = ('id', 'name')    

相关问题 更多 >