我通过添加一些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 posts和stackoverflow answers。但是我想要update_or_create(也称为here和here),也称为“ upsert”。这可能不完全适合REST,但是对于客户端来说更容易,所以这就是我想要的。 POST更近了,因为可能没有对象,所以没有id。
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"
}
]
答案 0 :(得分:0)
在REST语义下,几个注释者都回显了:
username
上应该有唯一性约束。如果就位,则第二个请求将出错。我相信第二个POST的正确错误代码是409 Conflict,尽管许多工具(包括DRF)都会返回400。从理论上讲,409是一个更好的选择,因为错误不是在请求中,而是请求和数据库状态(即键冲突)之间不兼容。/users/<username>/
的URL中。这样可以确保您永远不需要知道user_id
(就像您在上面的评论中那样)。第一个请求将创建,第二个将更新。如果您使用这样的策略,则实际上应该实施并发检查-例如this兼容DRF的库。