Фильтрация списка Django ModelViewSet из параметра URL

Привет, у меня есть такая модель:

class Appointment(models.Model):
    hospital = models.ForeignKey(Hospital, on_delete=models.CASCADE)
    patient = models.ForeignKey(Patient, on_delete=models.CASCADE)

Мой вид выглядит так:

class AppointmentViewSet(viewsets.ModelViewSet):
    queryset = Appointment.objects.all()
    serializer_class = AppointmentSerializer

В моих URL:

router.register(r'appointments', AppointmentViewSet)

Теперь я хочу отфильтровать список назначений по идентификатору пациента. Этот идентификатор должен быть предоставлен запрашивающей стороной через URL-адрес. Я думаю об использовании kwargs, чтобы поймать его. Но я понятия не имею, как это сделать. Я знаю, что мне нужно переопределить метод list.

def list(self, request, *args, **kwargs):
    # what do I write here? so that the queryset would be filtered by patient id sent through the url? 

Как настроить url и/или представление для размещения параметра идентификатора пациента? Я просто хочу изменить запрос списка, все остальные действия (создание, детализация, уничтожение) должны обрабатываться поведением по умолчанию для modelviewset.

Спасибо.


person QuestionEverything    schedule 14.06.2017    source источник
comment
После предоставления идентификатора вам нужен экземпляр или список?   -  person Moses Koledoye    schedule 14.06.2017
comment
список. список назначений.   -  person QuestionEverything    schedule 14.06.2017
comment
Вы передаете идентификатор из URL-адреса, верно?   -  person Moses Koledoye    schedule 14.06.2017


Ответы (3)


Вот как я это сделал:

Я добавил запись URL следующим образом:

url(r'appointments/ofpatient/(?P<patient>\d+)', AppointmentViewSet.as_view({'get': 'list'})),

Который я могу вызвать из браузера как:

http://localhost:8000/appointments/ofpatient/6

и на виду:

def list(self, request, patient=None):
    if patient:
        patient = Patient.active.filter(id=patient)
        appts = Appointment.active.order_by('appt_time').filter(patient=patient)
        serializer = self.get_serializer(appts, many=True)
        return Response(serializer.data)
    else:
        appts = Appointment.active.order_by('appt_time')
        serializer = self.get_serializer(appts, many=True)
        return Response(serializer.data)

Таким образом, URL-адрес /appointments также сохраняется.

person QuestionEverything    schedule 14.06.2017

Вы можете определить собственный метод для обработки маршрутизации URL-адреса с идентификатором пациента:

from rest_framework.decorators import list_route
rom rest_framework.response import Response

class AppointmentViewSet(viewsets.ModelViewSet):
    ...

    @list_route()
    def patient_appointments(self, request, id=None):
        serializer = self.get_serializer(queryset.filter(patient_id=id), many=True)
        return Response(serializer.data)

Декоратор list_route помечает ваш метод как требующий маршрутизации.

Обновление:

Вы можете вручную зарегистрировать URL как:

url(r'^(?P<id>[0-9]+)/appointments/$', AppointmentViewSet.as_view({'get': 'patient_appointments'}), name='patient-appointments')
person Moses Koledoye    schedule 14.06.2017
comment
как должен выглядеть мой URL-адрес запроса в этом случае? - person QuestionEverything; 14.06.2017
comment
вы имеете в виду ‹app_name›/appointments/‹id›? но в этом есть проблема. этот формат URL-адреса должен предоставлять «подробное» представление. как бы я передал идентификатор пациента через него? - person QuestionEverything; 14.06.2017
comment
Он не конфликтует с подробным представлением, в конце есть appointments. Я предлагаю вам сначала попробовать это, прежде чем гадать. Если у вас есть какие-либо ошибки/проблемы, сообщите об этом. - person Moses Koledoye; 14.06.2017
comment
я пробовал с этим URL-адресом: url(r'(\d+)/appointments/', AppointmentViewSet.as_view({'get': 'list'})), но он игнорирует идентификатор в начале и дает мне все записи - person QuestionEverything; 14.06.2017
comment
Я обновил ответ. Представление должно быть построено из метода patient_appointments, а не list, но я не уверен, почему вы хотите написать конфиг URL самостоятельно. - person Moses Koledoye; 14.06.2017

пытаться

if(self.request.get('pid')):
    pk = self.request.get('pid')
    all_appointment = Appointment.objects.filter(patient__pk=pk)

для пациентов URL будет appoinment/?pid=9

и подробности встречи appoinment/9

person Exprator    schedule 14.06.2017
comment
что тогда писать в url? как мне оформить запрос? - person QuestionEverything; 14.06.2017
comment
как вы сказали, вы хотите передать идентификатор, поэтому назначение/1 или 2 что-то в этом роде - person Exprator; 14.06.2017
comment
но поскольку я использую modelviewset, любой идентификатор после встреч обрабатывается как идентификатор самой записи о назначении, а не идентификатор пациента. - person QuestionEverything; 14.06.2017
comment
хорошо, так что вы можете сделать одну вещь: получить идентификатор пациента из идентификатора встречи, а затем отфильтровать в соответствии с этим идентификатором пользователя. - person Exprator; 14.06.2017
comment
на самом деле я пытаюсь получить все назначения пациента. поэтому сначала необходимо получить идентификатор пациента. - person QuestionEverything; 14.06.2017
comment
Скажи мне кое-что, братан, если ты пройдешь как пациент с идентификатором 9 и получишь pk и отфильтруешь объекты, подобные тому, который я дал, он даст тебе список назначений этого пользователя, pk будет рассматриваться как назначение или что-то еще не имеет значения, вы будете фильтровать запрос в соответствии с идентификатором пользователя, поэтому вам не нужно об этом думать - person Exprator; 14.06.2017
comment
если я правильно понял, вы предлагаете сделать что-то вроде: servername/appointments/9. правильно? затем рассматривать это 9 как идентификатор пациента? но та же ссылка должна работать и для самой информации о встрече. например: если запись о встрече имеет идентификатор 9, то она должна называться так. - person QuestionEverything; 14.06.2017
comment
по-видимому, он игнорирует часть «pid» и вызывает представление сведений о встрече. - person QuestionEverything; 14.06.2017
comment
извини братан, сделал небольшую ошибку, попробуй отредактированный ответ - person Exprator; 14.06.2017