我正在使用Django 2.0和Django 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')我想要的是遵循端点
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可以作为get_queryset默认动作来实现,但是如何让get_queryset接受contact_id作为所需参数?
编辑2
我明确遵循了文档Binding ViewSet到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'I'm using Django 2.0 and Django REST Framework.
I have two models in contacts app
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.phonecontacts/serializers.py
class ContactPhoneNumberSerializer(serializers.ModelSerializer): class Meta: model = ContactPhoneNumber fields = ('id', 'phone', 'primary', 'created', 'modified')and 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')What I want is following endpoints
GET: /contact-phone/{contact_id}/ list phones numbers of particular contact POST:/contact-phone/{contact_id}/ add phone numbers to particular contact PUT: /contact-phone/{contact_phone_number_id}/ update particular phone number DELETE: /contact-phone/{contact_phone_number_id}/ delete particular phone numberPUT and Delete can be achieved as default action of ModelViewSet but how to make get_queryset to accept contact_id as required parameter?
Edit 2
I followed doc Binding ViewSets to URLs explicitly
update 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), ]But it is giving error
AttributeError: 'function' object has no attribute 'get_extra_actions'最满意答案
你可以使用@action decorator为视图添加额外的动作:
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), ]You can add extra actions to the viewset using @action decorator:
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
Since you don't need additional actions, you can override retrieve and create defaults methods:
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)To change standard create url use explicitly url binding:
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), ]更多推荐
发布评论