Как использовать drf-writable-nested для создания или обновления? - PullRequest
0 голосов
/ 19 апреля 2019

Я взял пакет Django drf-writable-nested и сделал его полной реализацией под названием drf-writable-example , добавив немного кода REST (см. Ниже). (Сведения о моделях и сериализаторах см. На странице drf-writeable-nested .)

Если я дважды разместил их пример JSON (см. Ниже), он дважды создаст каждый объект в JSON. Итак, два объекта Site с URL "http://google.com", два объекта Avatar с изображением "image-1.png" и т. д.

Как мне вместо этого изменить этот код для создания или обновления? То есть, если сайт "http://google.com" уже существует, просто используйте его, а если объект аватара с" image-1.png "уже существует, просто используйте его и т. Д .?

Редактировать : Похоже, эта проблема об этом вопросе.

Редактировать 2 : Я думал, что могут появиться POST / PUT. Да, я прочитал несколько блогов сообщений и stackoverflow ответов о POST и PUT. Но я хочу update_or_create (также здесь и здесь ), также называемый "upsert". Это может не вписываться в REST, но для клиента это проще, так что я этого хочу. POST ближе, потому что там не может быть объекта, поэтому нет идентификатора.

REST код :

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)

и регистрация этого маршрутизатора по 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 голосов
/ 19 апреля 2019

Как следует из нескольких комментариев, в семантике REST:

  • Технически, RFC говорит, что POST должен обрабатывать запрос «в соответствии с собственной специфической семантикой ресурса», но это обычно создание. Несколько POST - это несколько запросов на создание, которые должны обрабатываться таким образом.
  • В вашем случае должно быть ограничение уникальности username. Если бы это было на месте, второй запрос был бы ошибкой. Я полагаю, что правильный код ошибки для второго POST - 409 Conflict , хотя многие инструменты (включая DRF) вернут 400 . 409 лучше подходит (теоретически), поскольку ошибка была не в запросе, а в несовместимости между запросом и состоянием базы данных (т. Е. Конфликтом ключей).
  • Допустимой альтернативой будет PUT-запрос к URL-адресу, например /users/<username>/. Это гарантирует, что вам никогда не нужно знать user_id (как в комментарии выше). Первый запрос будет создан, а второй будет обновлен. Если вы используете подобную стратегию, вам действительно следует реализовать проверку параллелизма - например, это DRF-совместимая библиотека.
...