DRF: Метод ВОЗВРАЩАЕТ объекты на основе параметра

#python #django #django-rest-framework

#python #django #django-rest-framework

Вопрос:

Я изучаю Django и пытаюсь создать конечную точку, которая возвращает объекты на основе параметра, указанного в URL.

В настоящее время у меня есть эти URL-адреса:

/api/v1/ как root, который возвращает:

 GET /api/v1/

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

{
    "device-groups": "http://127.0.0.1:8000/api/v1/device-groups/"
}
  

/api/v1/device-groups/ который возвращает все группы устройств:

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

[
    {
        "device_group_name": "Default",
        "group_uuid": "7465febe-7c46-4420-85a1-73dfe0af812c",
        "color": "4286f4",
        "is_default": true,
        "customer": {
            "customer_name": "Customer1",
            "customer_uuid": "b3eb5d7d-d1a8-4997-a65b-28bed71b7cc6"
        }
    },
    {
        "device_group_name": "Default",
        "group_uuid": "e12d02d0-7916-477e-b318-9680a38617db",
        "color": "4286f4",
        "is_default": true,
        "customer": {
            "customer_name": "Another customer",
            "customer_uuid": "5b5dafab-c311-4f58-80f5-c50d77fcf8a5"
        }
    },
    {
        "device_group_name": "group of customer1",
        "group_uuid": "c72e87b1-e7c8-4dcd-a9c7-4f6a016d7676",
        "color": "#ffffff",
        "is_default": false,
        "customer": {
            "customer_name": "Customer1",
            "customer_uuid": "b3eb5d7d-d1a8-4997-a65b-28bed71b7cc6"
        }
    }
]
  

Мне нужна конечная точка типа /api/v1/device-groups/<customer_uuid>/ , которая возвращает группы устройств, связанные с данным customer_uuid.

Мой serializers.py :

 class CustomerSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Customer
        fields = ('customer_name', 'customer_uuid')


class DeviceGroupSerializer(serializers.HyperlinkedModelSerializer):
    customer = CustomerSerializer(many=False, read_only=True)

    class Meta:
        model = DeviceGroup
        fields = ('device_group_name', 'group_uuid', 'color', 'is_default', 'customer')
  

Мой views.py :

 class DeviceGroupViewSet(viewsets.ModelViewSet):
    serializer_class = DeviceGroupSerializer
    queryset = DeviceGroup.objects.all()
  

Мой urls.py :

 router = routers.DefaultRouter()
router.register(r'device-groups', views.DeviceGroupViewSet)


urlpatterns = [
   path('admin/', admin.site.urls),
   path('api/v1/', include(router.urls)),
]
  

Я попытался переопределить get_queryset следующим образом:

 def get_queryset(self):
    customer = self.request.GET['customer']
    queryset = DeviceGroup.objects.filter(customer=customer)
    return queryset
  

Но это приводит к: AssertionError: basename argument not specified, and could not automatically determine the name from the viewset, as it does not have a .queryset attribute.

Что мне нужно изменить, чтобы получить /api/v1/device-groups/<customer_uuid>/ конечную точку, которая показывает только группы устройств, связанные с данным customer_uuid?

Редактировать

 Internal Server Error: /api/v1/device-groups/
Traceback (most recent call last):
File "C:UsersStevyPycharmProjectstapartisan-apienvlibsite- 
packagesdjangoutilsdatastructures.py", line 77, in __getitem__
list_ = super().__getitem__(key)
KeyError: 'customer'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "C:UsersStevyPycharmProjectstapartisan-apienvlibsite- 
packagesdjangocorehandlersexception.py", line 34, in inner
response = get_response(request)
File "C:UsersStevyPycharmProjectstapartisan-apienvlibsite- 
packagesdjangocorehandlersbase.py", line 126, in _get_response
response = self.process_exception_by_middleware(e, request)
File "C:UsersStevyPycharmProjectstapartisan-apienvlibsite- 
packagesdjangocorehandlersbase.py", line 124, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:UsersStevyPycharmProjectstapartisan-apienvlibsite- 
packagesdjangoviewsdecoratorscsrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "C:UsersStevyPycharmProjectstapartisan-apienvlibsite- 
packagesrest_frameworkviewsets.py", line 116, in view
return self.dispatch(request, *args, **kwargs)
File "C:UsersStevyPycharmProjectstapartisan-apienvlibsite- 
packagesrest_frameworkviews.py", line 495, in dispatch
response = self.handle_exception(exc)
File "C:UsersStevyPycharmProjectstapartisan-apienvlibsite- 
packagesrest_frameworkviews.py", line 455, in handle_exception
self.raise_uncaught_exception(exc)
File "C:UsersStevyPycharmProjectstapartisan-apienvlibsite- 
packagesrest_frameworkviews.py", line 492, in dispatch
response = handler(request, *args, **kwargs)
File "C:UsersStevyPycharmProjectstapartisan-apienvlibsite- 
packagesrest_frameworkmixins.py", line 40, in list
queryset = self.filter_queryset(self.get_queryset())
File "C:UsersStevyPycharmProjectstapartisan-apiappcoreviews.py", line 
13, in get_queryset
customer = self.request.GET['customer']
File "C:UsersStevyPycharmProjectstapartisan-apienvlibsite- 
packagesdjangoutilsdatastructures.py", line 79, in __getitem__
raise MultiValueDictKeyError(key)
django.utils.datastructures.MultiValueDictKeyError: 'customer'`
  

Ответ №1:

Маршрутизатору не удалось определить basename . Вы должны определить basename в своем маршрутизаторе. Вот так

 router.register(r'device-groups', views.DeviceGroupViewSet, base_name='device-groups')
  

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

Комментарии:

1. Спасибо за ваш ответ. Я добавил base_name , как вы предложили. Когда я перехожу к /api/v1/device-groups/ , он выдает мне MultiValueDictKeyError .

2. Я добавил полную обратную трассировку ошибки в качестве РЕДАКТИРОВАНИЯ

Ответ №2:

Я не знаком с DRF, но в целом, чтобы получить объект на основе параметра, вы должны:

1) Определите свой URL таким образом, чтобы учитывать идентификатор customer_uuid, который вы собираетесь вводить динамически, когда хотите создать свою конечную точку, поэтому с помощью регулярного выражения вам нужно создать что-то вроде:

 url(r'^/api/v1/device-groups/(?P<customer_uuid>d )/$', views.your_view, name='your_view')
  

Регулярное выражение d будет соответствовать целому числу произвольного размера. Это целое число будет использоваться для извлечения клиента из базы данных. Теперь обратите внимание, что я написал регулярное выражение как (?P d ), это говорит Django записать значение в аргумент ключевого слова с именем customer_uuid .

2) Определите свою функцию просмотра

 from django.shortcuts import render, get_object_or_404
from .models import Customer

def your_view(request, customer_uuid):
    customer = get_object_or_404(Customer, pk=customer_uuid)
    return render(request, 'customer.html', {'customer': customer})
  

Надеюсь, это поможет

Ответ №3:

Вы должны получить то, что хотите, если вы определите другое lookup_field в представлении, подобном:

 class DeviceGroupViewSet(viewsets.ModelViewSet):
    serializer_class = DeviceGroupSerializer
    queryset = DeviceGroup.objects.all()
    lookup_field = 'customer_uuid'
  

Или, может быть, вы захотите взглянуть на эту документацию, чтобы рассмотреть другой подход.