добавить параметр в запрос get_queryset в Django REST Framework - PullRequest
0 голосов
/ 19 мая 2018

Я использую Django 2.0 и Django REST Framework.

У меня есть две модели в контакты приложение

contacts / models.py

class Contact(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100, blank=True, null=True, default='')


class ContactPhoneNumber(models.Model):
    contact = models.ForeignKey(Contact, on_delete=models.CASCADE)
    phone = models.CharField(max_length=100)
    primary = models.BooleanField(default=False)

    def __str__(self):
        return self.phone

contacts / serializers.py

class ContactPhoneNumberSerializer(serializers.ModelSerializer):
    class Meta:
        model = ContactPhoneNumber
        fields = ('id', 'phone', 'primary', 'created', 'modified')

и contacts / views.py

class ContactPhoneNumberViewSet(viewsets.ModelViewSet):
    serializer_class = ContactPhoneNumberSerializer

    def get_queryset(self):
        return ContactPhoneNumber.objects.filter(
            contact__user=self.request.user
        )

urls.py

router.register(r'contact-phone', ContactPhoneNumberViewSet, 'contact_phone_numbers')

Мне нужны следующие конечные точки

  • GET: /contact-phone/{contact_id}/ список телефоновномера определенного контакта
  • POST: /contact-phone/{contact_id}/ добавление номеров телефонов для конкретного контакта
  • PUT: /contact-phone/{contact_phone_number_id}/ обновить номер телефона
  • УДАЛИТЬ: /contact-phone/{contact_phone_number_id}/ удалить номер телефона

PUT и Delete могут быть выполнены как действие по умолчанию ModelViewSet, но как заставить get_queryset принять contact_id в качестве обязательного параметра?

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

Я следовал за документом Явное привязывание ViewSets к URL-адресам

обновление app / urls.py

router = routers.DefaultRouter()
router.register(r'contacts', ContactViewSet, 'contacts')
contact_phone_number_view_set = ContactPhoneNumberViewSet.as_view({
    'get': 'list/<contact_pk>/',
    'post': 'create/<contact_pk>/',
    'put': 'update',
    'delete': 'destroy'
})
router.register(r'contact-phone-number', contact_phone_number_view_set, 'contact_phone_numbers')

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

Но это дает ошибку

AttributeError: 'function' object has no attribute 'get_extra_actions'

1 Ответ

0 голосов
/ 19 мая 2018

Вы можете добавить дополнительные действия в набор, используя @action оформитель:

class ContactPhoneNumberViewSet(viewsets.ModelViewSet):
    serializer_class = ContactPhoneNumberSerializer

    def get_queryset(self):
        return ContactPhoneNumber.objects.filter(
            contact__user=self.request.user
        )

    @action(methods=['post'], detail=False)
    def add_to_contact(self, request, contact_id=None):
        contact = Contact.objects.get(id=contact_id)
        serializer = ContactPhoneNumberSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save(contact=contact)
            return Response(serializer.data)
        else:
            return Response(serializer.errors,
                            status=status.HTTP_400_BAD_REQUEST)

    @action(methods=['get'], detail=False)
    def set_password(self, request, contact_id=None):
        contact = Contact.objects.get(id=contact_id)
        serializer = PasswordSerializer(contact.contactphonenumber_set.all(), many=True)
        return Response(serializer.data)

UPD

Поскольку вы этого не сделаетенеобходимы дополнительные действия, вы можете переопределить методы retrieve и create по умолчанию:

class ContactPhoneNumberViewSet(viewsets.ModelViewSet):
        serializer_class = ContactPhoneNumberSerializer

        def get_queryset(self):
            return ContactPhoneNumber.objects.filter(
                contact__user=self.request.user
            )

        def create(self, request, pk=None):
            contact = Contact.objects.get(id=contact_id)
            serializer = ContactPhoneNumberSerializer(data=request.data)
            if serializer.is_valid():
                serializer.save(contact=contact)
                return Response(serializer.data)
            else:
                return Response(serializer.errors,
                                status=status.HTTP_400_BAD_REQUEST)

        def retrieve(self, request, pk=None):
            contact = Contact.objects.get(pk=pk)
            serializer = PasswordSerializer(contact.contactphonenumber_set.all(), many=True)
            return Response(serializer.data)

Для изменения стандартного create url использовать явно привязку URL:

contact_list = ContactPhoneNumberViewSet.as_view({
    'get': 'list',
    'post': 'create',
    'put': 'update',
    'delete': 'destroy'
})

urlpatterns = [
    path('api//contact-phone/<int:pk>/', contact_list, name='contact-list'),
    url(r'^admin/', admin.site.urls),
]
...