如何使用drf-writable-nested创建或更新?

时间:2019-04-18 22:25:16

标签: django django-rest-framework drf-writable-nested

我通过添加一些REST代码(见下文),将Django drf-writable-nested软件包打包为完整的实现,名为drf-writable-example。 (有关模型和序列化器,请参见drf-writable-nested page。)

如果我两次发布其JSON示例(请参见下文),它将两次在JSON中创建每个对象。因此,两个具有网址“ {http://google.com”的Site对象,两个具有图片的Avatar对象 “ image-1.png”等

我该如何修改该代码以创建或更新?也就是说,如果“ http://google.com”站点已经存在,那么就使用它;如果“ image-1.png”的化身对象已经存在,就使用它吧,等等?

编辑:似乎this issue是关于这个问题的

编辑2 :我认为可能会发布POST / PUT。是的,我已经阅读了许多关于POST和PUT的blog postsstackoverflow answers。但是我想要update_or_create(也称为herehere),也称为“ upsert”。这可能不完全适合REST,但是对于客户端来说更容易,所以这就是我想要的。 POST更近了,因为可能没有对象,所以没有id。

REST code

from rest_framework import routers, viewsets

from .serializers import UserSerializer
from .models import User


class UserModelViewSet(viewsets.ModelViewSet):
    queryset = ExampleUser.objects.all()
    serializer_class = UserSerializer

router = routers.DefaultRouter()
router.register(r'users', UserModelViewSet)

registering that router to a URL

现在,我可以使用user-example.json从他们的文档(httpie)中发布示例了:

http POST http://localhost:8000/api/users/ \
    < examples/user-example.json > my.log

如果我两次发布,就会得到两套完整的东西:

GET /api/users/
HTTP 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

[
    {
        "pk": 1,
        "profile": {
            "pk": 1,
            "sites": [
                {
                    "pk": 1,
                    "url": "http://google.com"
                },
                {
                    "pk": 2,
                    "url": "http://yahoo.com"
                }
            ],
            "avatars": [
                {
                    "pk": 1,
                    "image": "image-1.png"
                },
                {
                    "pk": 2,
                    "image": "image-2.png"
                }
            ],
            "access_key": {
                "pk": 1,
                "key": "key"
            }
        },
        "username": "test"
    },
    {
        "pk": 2,
        "profile": {
            "pk": 2,
            "sites": [
                {
                    "pk": 3,
                    "url": "http://google.com"
                },
                {
                    "pk": 4,
                    "url": "http://yahoo.com"
                }
            ],
            "avatars": [
                {
                    "pk": 3,
                    "image": "image-1.png"
                },
                {
                    "pk": 4,
                    "image": "image-2.png"
                }
            ],
            "access_key": {
                "pk": 2,
                "key": "key"
            }
        },
        "username": "test"
    }
]

1 个答案:

答案 0 :(得分:0)

在REST语义下,几个注释者都回显了:

  • 从技术上讲,RFC说POST应该“根据资源自身的特定语义”处理请求,但这通常是一个创建。多个POST是要创建的多个请求,应该以这种方式处理。
  • 对于您来说,username上应该有唯一性约束。如果就位,则第二个请求将出错。我相信第二个POST的正确错误代码是409 Conflict,尽管许多工具(包括DRF)都会返回400。从理论上讲,409是一个更好的选择,因为错误不是在请求中,而是请求和数据库状态(即键冲突)之间不兼容。
  • 有效的替代方法是将请求放置到类似/users/<username>/的URL中。这样可以确保您永远不需要知道user_id(就像您在上面的评论中那样)。第一个请求将创建,第二个将更新。如果您使用这样的策略,则实际上应该实施并发检查-例如this兼容DRF的库。