如何构建一个返回自定义模型列表的Django REST-Api?

时间:2020-12-10 15:49:48

I'm having a great deal of trouble trying build my API using the Django Rest Framework. I have been stuck on the same issue now for several days. I've tried numerous solutions and code-snippets and asked plenty of people but to no avail. I've tried to follow all the instructions in the docs, but to me they are unclear and incomplete. So I'm very desperate for a clear, concise, complete working example to solve me problem.

我在使用Django Rest Framework构建我的API时遇到了很多麻烦。我好几天都被困在同一个问题上了。我已经尝试了很多解决方案和代码片段并且问了很多人,但无济于事。我试图遵循文档中的所有说明,但对我来说,它们不清楚且不完整。因此,我非常渴望一个清晰,简洁,完整的工作示例来解决我的问题。

Now here is my question:

现在这是我的问题:

I have been successful at building a simple Django Rest API by following the instructions here. These instructions make it very easy to build an API that returns a list of all instances of a certain model, or a single instance based on a user-provided ID. So, since I have a model named MyObject, I have built an api that returns a list of all the myObjects when you hit the URL /api/myObjects. If I hit the URL /api/myObjects/60, it gives me the myObject with ID==60. So far so good!

我按照这里的说明成功构建了一个简单的Django Rest API。这些指令使构建API非常容易,该API返回特定模型的所有实例的列表,或基于用户提供的ID的单个实例。所以,因为我有一个名为MyObject的模型,所以我构建了一个api,当你点击URL / api / myObjects时会返回所有myObjects的列表。如果我点击URL / api / myObjects / 60,它会给我一个ID == 60的myObject。到现在为止还挺好!

But I don't want to do this. I want something a bit more complex. The myObject model has a method called getCustomObjects(). This method itself returns a list of myObjects. When I hit the URL /api/myObjects/60, I want it to return the list produced by calling getCustomObjects() on the myObject with ID==60. This seemingly simple change is causing me a very major headache and I can't figure out how to do it. The reason is that because I want to return a non-standard list of objects, I cannot use the standard way of doing things with a ModelViewSet as described in the docs. When I make the changes that I think should work, I get errors. My current error is: base_name argument not specified, and could not automatically determine the name from the viewset, as it does not have a .model or .queryset attribute.. All the docs I have read to cure this error say that I need to specify a "base_name" argument. What the value of that base_name argument should be and how I should use it in my URL are very unclear to me. I don't have a good explanation. That's why I'm posting my complete code. If someone can advise me clearly and completely how to fix it, I would be very grateful.

但我不想这样做。我想要一些更复杂的东西。 myObject模型有一个名为getCustomObjects()的方法。此方法本身返回myObjects列表。当我点击URL / api / myObjects / 60时,我希望它返回通过在ID == 60的myObject上调用getCustomObjects()生成的列表。这个看似简单的变化让我非常头疼,我无法弄清楚如何去做。原因是因为我想返回一个非标准的对象列表,我不能使用标准的方法来处理模型中描述的ModelViewSet。当我做出我认为应该有效的更改时,我会遇到错误。我当前的错误是:未指定base_name参数,并且无法自动确定视图集中的名称,因为它没有.model或.queryset属性..我读过的所有文档都可以解决这个错误说我需要指定“base_name”参数。该base_name参数的值应该是什么以及我应该如何在我的URL中使用它对我来说非常不清楚。我没有一个很好的解释。这就是我发布完整代码的原因。如果有人可以清楚地告诉我如何解决它,我将非常感激。

My Route looks like this in myApp's url.py:

我的路线在myApp的url.py中看起来像这样:

from rest_framework import routers
router = routers.DefaultRouter()    router.register(r'myObjects/(?P<id>\d+)/?$', views.MyObjectsViewSet)
url(r'^api/', include(router.urls)),

My Model looks like this:

我的模型看起来像这样:

class MyObject(models.Model):
    name = models.TextField()

My Serializer looks like this:

我的Serializer看起来像这样:

class MyObjectSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = MyObject
    fields = ('id', 'name',)

My Viewset looks like this:

我的Viewset看起来像这样:

class MyObjectsViewSet(viewsets.ViewSet):

    def retrieve(self,request,pk=None):
        queryset = MyObjects.objects.get(pk=pk).customMyObjectList()

        if not queryset:
            return Response(status=status.HTTP_400_BAD_REQUEST)
        else:
            serializer = MyObjectSerializer(queryset)
            return Response(serializer.data,status=status.HTTP_200_OK)

When I hit /api/myObjects/60/ I get the following error:

当我点击/ api / myObjects / 60 /时出现以下错误:

`base_name` argument not specified, and could not automatically determine the name from the viewset, as it does not have a `.model` or `.queryset` attribute.

1 个解决方案

#1


13  

base_name is used so the router can properly name the URLs. The DefaultRouter you are using uses the model or queryset attributes of the view set. But since you are using viewsets.ViewSet which has neither, the router cannot determine the base name used to name the generated URL patterns (eg, 'myobject-detail' or 'myobject-list')

使用base_name以便路由器可以正确地命名URL。您正在使用的DefaultRouter使用视图集的模型或查询集属性。但由于您使用的是viewsets.ViewSet,因此路由器无法确定用于命名生成的URL模式的基本名称(例如,'myobject-detail'或'myobject-list')

router.register(r'myObjects', views.MyObjectsViewSet, base_name='myobject')

This will result in creating the following URL pattern: ^myObjects/{pk}/$ with the name: 'myobject-detail'.

这将导致创建以下URL模式:^ myObjects / {pk} / $,其名称为:'myobject-detail'。

Notice the first param to router.register must be r'myObjects' not r'myObjects/(?P<id>\d+)/?$' because the router just needs the prefix and will take care of creating the patterns. To summarize this is an excerpt from DRF docs

请注意,router.register的第一个参数必须是r'myObjects'而不是r'myObjects /(?P \ d +)/?$',因为路由器只需要前缀并负责创建模式。总结一下,这是DRF文档的摘录

There are two mandatory arguments to the register() method:

register()方法有两个必需参数:

prefix - The URL prefix to use for this set of routes.

prefix - 用于此路由集的URL前缀。

viewset - The viewset class.

viewset - 视图集类。

Optionally, you may also specify an additional argument:

(可选)您还可以指定其他参数:

base_name - The base to use for the URL names that are created. If unset the basename will be automatically generated based on the model or queryset attribute on the viewset, if it has one. Note that if the viewset does not include a model or queryset attribute then you must set base_name when registering the viewset.

base_name - 用于创建的URL名称的基础。如果未设置,将根据视图集上的模型或queryset属性自动生成基本名称(如果有)。请注意,如果视图集不包含模型或查询集属性,则必须在注册视图集时设置base_name。

See routers docs: www.django-rest-framework.org/api-guide/routers

请参阅路由器文档:www.django-rest-framework.org/api-guide/routers

#1


13  

base_name is used so the router can properly name the URLs. The DefaultRouter you are using uses the model or queryset attributes of the view set. But since you are using viewsets.ViewSet which has neither, the router cannot determine the base name used to name the generated URL patterns (eg, 'myobject-detail' or 'myobject-list')

使用base_name以便路由器可以正确地命名URL。您正在使用的DefaultRouter使用视图集的模型或查询集属性。但由于您使用的是viewsets.ViewSet,因此路由器无法确定用于命名生成的URL模式的基本名称(例如,'myobject-detail'或'myobject-list')

router.register(r'myObjects', views.MyObjectsViewSet, base_name='myobject')

This will result in creating the following URL pattern: ^myObjects/{pk}/$ with the name: 'myobject-detail'.

这将导致创建以下URL模式:^ myObjects / {pk} / $,其名称为:'myobject-detail'。

Notice the first param to router.register must be r'myObjects' not r'myObjects/(?P<id>\d+)/?$' because the router just needs the prefix and will take care of creating the patterns. To summarize this is an excerpt from DRF docs

请注意,router.register的第一个参数必须是r'myObjects'而不是r'myObjects /(?P \ d +)/?$',因为路由器只需要前缀并负责创建模式。总结一下,这是DRF文档的摘录

There are two mandatory arguments to the register() method:

register()方法有两个必需参数:

prefix - The URL prefix to use for this set of routes.

prefix - 用于此路由集的URL前缀。

viewset - The viewset class.

viewset - 视图集类。

Optionally, you may also specify an additional argument:

(可选)您还可以指定其他参数:

base_name - The base to use for the URL names that are created. If unset the basename will be automatically generated based on the model or queryset attribute on the viewset, if it has one. Note that if the viewset does not include a model or queryset attribute then you must set base_name when registering the viewset.

base_name - 用于创建的URL名称的基础。如果未设置,将根据视图集上的模型或queryset属性自动生成基本名称(如果有)。请注意,如果视图集不包含模型或查询集属性,则必须在注册视图集时设置base_name。

See routers docs: www.django-rest-framework.org/api-guide/routers

请参阅路由器文档:www.django-rest-framework.org/api-guide/routers