Пути URL-адресов конечных точек Django REST API

У меня есть приложение на Django 4.2 с базой данных Postgres и REST API. Мой urls.py содержит этот путь в urlpatterns:

path('create/<int:pk>/<str:name>/', ComponentCreate.as_view(), name='create-component')

ComponentCreate in views.py относится к простой таблице базы данных (component) с идентификатором в качестве целочисленного первичного ключа и именем в качестве единственного другого столбца.

views.py содержит:

class ComponentCreate(generics.CreateAPIView):
    queryset = Component.objects.all(),
    serializer_class = ComponentSerializer
    lookup_field = "id"

моделей.в py есть:

class Component(models.Model):
    id = models.IntegerField(primary_key=True)
    name = models.CharField(max_length=255, blank=True, null=True)
    class Meta:
        managed = True
        db_table = 'component'

serializers.py содержит:

class ComponentSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField()
    name = serializers.CharField()

    class Meta:
        model = Component
        fields = ('id', 'name')

Я пытаюсь использовать API для добавления строки в таблицу компонентов, используя, например, как показано ниже (где приложение называется SystemTestDB):

запись curl -X http://127.0.0.1:8000/SystemTestDB/create/2/whatever/

Однако это не удается с ответом:

{"идентификатор":["Это поле обязательно для заполнения."],"имя":["Это поле обязательно для заполнения."]}

У меня есть другие конечные точки, которые работают корректно, например, с path:

path('delete/<int:pk>/', ComponentDelete.as_view(), name='delete-component')

В этом случае, очевидно, идентификатор передается через int:pk, в то время как в случае сбоя в запросе не указаны ни идентификатор, ни имя.

Я неправильно указал путь к URL-адресу или что-то не так с model/view/serializer?

Удалите пользовательские поля, сделав их обязательными для заполнения:

class ComponentSerializer(serializers.ModelSerializer):
    # id = serializers.IntegerField()
    # name = serializers.CharField()

    class Meta:
        model = Component
        fields = ('id', 'name')

или, если вы действительно хотите настроить, установите required=False [drf-doc]:

class ComponentSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField(read_only=True)
    name = serializers.CharField(required=False)

    class Meta:
        model = Component
        fields = ('id', 'name')

в модели вы устанавливаете id как AutoField или просто скрываете его:

class Component(models.Model):
    id = models.AutoField(primary_key=True)
    # …

Предложенная вами настройка не подходит для передачи полей в запросе. С djangorestframework URL-адрес не предназначен для сохранения динамических данных, он указывает серверу, к каким ресурсам вы хотите получить доступ.

ПРИМЕЧАНИЕ: Следующий фрагмент текста является учебным. Код приведен внизу.

Для пути delete ваше приложение ведет себя корректно, потому что этот является правильным способом передачи такого запроса - вы хотите получить доступ к ресурсу, указанному в id (чтобы удалить его), поэтому URL-адрес является подходящим местом для его размещения.

Для путей create ресурс еще не существует, поэтому у него нет id - и, как таковой, у вас нет возможности сообщить серверу, что вы хотите получить доступ к этому ресурсу. Вы хотите, чтобы сервер создал этот ресурс.

И подходящее место для размещения информации, необходимой для создания этого конкретного ресурса, находится в теле запроса, а не в URL-адресе.

То же самое верно для update (или в HTML, PATCH/PUT), за исключением тех случаев, когда ресурс действительно существует, поэтому вы будете передавать id как часть URL-адреса, но данные, с помощью которых можно обновить этот ресурс, все равно должны передаваться в теле запроса.

Вы можете выполнить настройку с передачей переменных данных в URL-адрес - это просто не обычно и не рекомендуется. Но если вы намеренно не выбираете этот шаблон по очень специфическим архитектурным соображениям, то почти всегда лучше придерживаться рекомендованного шаблона.

"Предполагаемый" способ ведения дел в djangorestframework

# models.py

class Component(models.Model):
    # Instead of IntegerField, use (Big)AutoField to let the database handle 
    # the resource's primary key (meaning you don't have to pass it manually)
    id = models.BigAutoField(primary_key=True)  
# serializers.py

class ComponentSerializer(serializers.ModelSerializer):
    # ModelSerializer fetches the fields from the model
    # Only define them here if you need to override the default behavior
    #    (which your use-case doesn't seem like you do)
    class Meta:
        model = Component
        fields = ('id', 'name')
class ComponentCreate(generics.CreateAPIView):
    queryset = Component.objects.all()
    serializer_class = ComponentSerializer
    # You don't need lookup_field in this view, CreateAPIView doesn't perform any lookups
# urls.py

path('create/', ComponentCreate.as_view(), name='create-component')
# request

curl -X POST http://127.0.0.1:8000/SystemTestDB/create/ -H "Content-Type: application/json" -d '{"name": "whatever"}'
Вернуться на верх