在Django REST Framework中为get_queryset请求添加参数

时间:2018-05-19 05:27:34

标签: django django-rest-framework

我正在使用Django 2.0Django REST Framework

我在联系人应用

中有两个模型

联系人/ 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

联系人/ 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')

我想要的是遵循端点

  • 获取: /contact-phone/{contact_id}/ 列出特定联系人的电话号码
  • POST: /contact-phone/{contact_id}/ 为特定联系人添加电话号码
  • PUT: /contact-phone/{contact_phone_number_id}/ 更新特定电话号码
  • 删除: /contact-phone/{contact_phone_number_id}/ 删除特定的电话号码

PUTDelete可以作为ModelViewSet的默认操作实现,但如何使get_queryset接受contact_id作为必需参数?< /强>

  

编辑2

我关注了文档Binding ViewSets to URLs explicitly

更新 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 :(得分:1)

您可以使用@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

由于您不需要其他操作,因此您可以覆盖retrievecreate默认方法:

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网址,请使用明确的网址绑定:

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),
]