gpt4 book ai didi

python - 在 Django DRF 中注册多个路由 - 使用和调用 ModelViewSets 或 Generics 中的方法

转载 作者:行者123 更新时间:2023-12-01 00:20:23 24 4
gpt4 key购买 nike

我想了解如何使用Django DRF进行注册:

  • 两个不同的端点,并且
  • 只有一个端点使用自定义字段

请说明使用 ViewSet 和泛型的差异。

这些是我的尝试。

我来自Flask,发现使用装饰器定义多个端点非常清晰。

Flask - 获取对象列表、最后一个对象的示例端点

选项 1

@application.route('/people/', endpoint='people')
def people():
# return a list of people
pass

@application.route('/last/', endpoint='last_person')
def last_person():
# return last person
pass

选项 2

@application.route('/people/', endpoint='people')
def people():
field = request.args.get('last', None)
if field:
# return last person from list of people
else:
# return list of people

我了解 DRF 的好处可能是一致性并阅读了文档,但发现比较麻烦,希望更清楚地了解如何利用ModelsViewSets和Generics来看看VS Flask的好处。

请提供一个示例来获取用户列表和最后一个用户。

<小时/>

Django DRF - 第一种方法(ModelViewSet)

# serializer.py
from rest_framework import serializers
from .models import Person

class PersonSerializer( serializers.HyperlinkedModelSerializer):
class Meta:
model = Person
fields = ('name', 'nickname', 'timestamp')
# views.py
class PersonViewSet( viewsets.ModelViewSet):
queryset = Person.objects.all().order_by('name')
serializer_class = PersonSerializer

我理解类 PersonViewSet 应该准备好公开方法来获取列表以及检索项目,因为 ModelViewSet: https://www.django-rest-framework.org/api-guide/viewsets/#modelviewset

但是在注册端点时如何明确地看到这一点?

示例:

# urls.py
router = routers.DefaultRouter()
router.register(r'people', views.PersonViewSet)

app_name = 'myapi'

urlpatterns = [
path('', include(router.urls)),
]

当我浏览 http://127.0.0.1:8000/api/ 时,我只能看到一个端点。是的,如果我尝试 http://127.0.0.1:8000/api/1/ 它会自行检索用户,但是我如何在上面的代码中读取它?如何从 PersonViewSet 映射一个方法(例如 PersonViewSet.get_last_person() )来指示使用相同的端点来获取最后一个条目?

Django DRF - 第二种方法(泛型)

我读到 Generics 模型公开了适合检索单个项目而不是列表的 API 模型:

https://www.django-rest-framework.org/api-guide/generic-views/#retrieveapiview

我尝试在views.py中添加:

# I make use of RetrieveAPIView now
class LastPersonView( generics.RetrieveAPIView):
queryset = Person.objects.all()
serializer_class = PersonSerializer

urls.py中:

router.register(r'people', views.PersonViewSet)
router.register(r'last-person', views.LastPersonView)

但这会产生错误:AttributeError:类型对象“LastPersonView”没有属性“get_extra_actions”因为 Generics 没有 get_extra_actions ,比如 ViewSet

在第二个示例中,如何在我的路由器中注册两个 View ?

Django DRF - 第三次尝试(具有基本名称的 ModelViewSet)

https://stackoverflow.com/a/40759051/305883

我还可以通过分配基本名称来指示 ViewSet 在我的 urls.py 中注册不同的端点:

router.register(r'people', views.PersonViewSet)
router.register(r'last-person', views.PersonViewSet, basename='lastperson')

并使用相同的ModelViewSet:

class PersonViewSet( viewsets.ModelViewSet):
queryset = Person.objects.all().order_by('name')
serializer_class = PersonSerializer

我知道这种方法的好处是更“简单”,因为查询集总是相同的。

但是我可以注册一个方法来检索最后一个对象,并将该方法映射到我的路由器中(include(router.urls))吗?

<小时/>

可以提供使用 ModelViewSets、泛型和更明确的方法的示例,在 View 中声明方法并在端点中调用这些方法吗?

您能否说明哪种方法可能更好:

  • 使用 viewSet 处理列表,并公开从列表中检索项目的方法
  • 使用两个单独的 View ,一个用于列表,一个用于项目
  • 从一个 View 或两个单独的 View 映射路由器中的两个不同端点
  • 从一个 View 将一个带有字段选项的端点映射到我的路由器

最佳答案

我将详细介绍您所采取的每种方法,并提供一个解决方案来满足您基于该方法的需求。那么让我们开始吧...

<小时/>

您的第一种方法:

您的第一种方法使用非常典型的 DRF 设置,并为 PersonViewSet 的各种操作生成路由。由 DRF 本身提供。

现在,您需要添加一个新的 URL 端点,该端点将解析为 queryset 的最后一个对象。 :

Person.objects.all().order_by('name')

据推测,端点应位于 person 下基本名称。

我们可以利用action这里的装饰器将 HTTP GET 映射到要映射到 View 集中的某个方法的某个 URL,并且从该方法我们可以设置 kwargs要设置的 View 集实例的属性 pk到最后一个对象,最后将请求发送到retrieve方法本身例如:

from rest_framework.decorators import action

class PersonViewSet(viewsets.ModelViewSet):
queryset = Person.objects.all().order_by('name')
serializer_class = PersonSerializer

@action(
methods=['get'],
detail=False,
url_path='last',
url_name='last',
)
def get_last_person(self, request, *args, **kwargs):
last_pk = self.queryset.all().last().pk
self.kwargs.update(pk=last_pk)
return self.retrieve(request, *args, **kwargs)

现在,如果您请求/people/last/端点,您将获得最后检索到的对象的响应。

请注意,如果您有 lookup_url_kwargslookup_field不同于pk ,您需要使用 kwargs 中的设置正如你所想象的那样。另外,您可以对 retrieve 进行操作你自己而不是委托(delegate)给 retrieve但让我们保持干燥。

FWIW,如果您也想使用此端点进行 PUT/PATCH/DELETE,则需要添加 action 中的方法并根据方法名称将它们委托(delegate)给相应的操作。

<小时/>

第二种方法:

View 不是 ViewSet(查看两者的基类: rest_framework.views.Viewrest_framework.viewsets.ViewSet ); DRF 路由器为 View 集而不是 View 创建端点。有多种方法可以将 View 转换为 View 集,基本上只需继承 viewsets.GenericViewSet 即可。 -- 它继承自 viewsets.ViewSetMixingenerics.GenericAPIView .

viewsets.ViewSetMixin通过在 as_view 中提供所有必要的操作方法映射,具有将 View 转换为 View 集的实际魔力类方法。

为了使这种方法发挥作用,我们需要定义一个 retrieve从序列化器发送响应的方法:

from rest_framework import generics
from rest_framework.response import Response

class LastPersonView(generics.RetrieveAPIView):

serializer_class = PersonSerializer
queryset = Person.objects.all().order_by('name')

def retrieve(self, request, *args, **kwargs):
instance = self.queryset.all().last()
serializer = self.get_serializer(instance)
return Response(serializer.data)

generics.RetrieveAPIViewget方法将请求委托(delegate)给 retrieve因此我们重写了 retrieve 方法在这里。

现在,我们需要将路由定义为常规端点,而不是在 DRF 路由器中:

urlpatterns = router.urls + [
path('last-person/', LastPersonView.as_view()),
]
<小时/>

第三种方法:

您已经为同一 View 集注册了两个不同的前缀(这里再次使用 View 不起作用,必须是 View 集),因此两组不同的 URL 映射具有所有相同的 CRUD 操作。根据您的期望,我认为这不是您想要的,因此我不会进一步讨论这种方法,但我认为您从上面已经明白为什么它不相关了。

<小时/>

现在,如果我必须选择,我会更喜欢第一种方法,因为所有内容都在相同的 View 集、前缀和基本名称下,并且您不需要乱搞 URLConf。

我希望以上内容能澄清一两件事。

关于python - 在 Django DRF 中注册多个路由 - 使用和调用 ModelViewSets 或 Generics 中的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59006970/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com