what's different about list_route and detail_r

2019-04-07 07:00发布

问题:

like title,
what's different about list_route and detail_route in django-rest-framework?
if I want to get 1 in url xxx/books/1/,
how can I write url.py and views.py ?

回答1:

@list_route and @detail_route are extra actions that we can add to a ViewSet. Both provide a custom routing facility in view set. Any methods on the ViewSet decorated with @detail_route or @list_route will also be routed. list_route will give all the related records, whereas detail_route will provide only a particular record. For example, given a method like this on the UserViewSet class:

class UserViewSet(ModelViewSet):
    ...

    @detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf])
    def set_password(self, request, pk=None):

The following URL pattern would additionally be generated:

URL pattern: ^users/{pk}/set_password/$ Name: 'user-set-password'

For more information on routers you can visit the official Django Rest Rramewrok documentation on routers.

If you want get xxx/books/1/ then your url.py and views.py should look like this.

urls.py:

url(r'^xxx/books/(?P<id>[0-9]+)$', views.myview)

views.py:

@csrf_exempt
def myview(request , id):


回答2:

**Read this and definitely you will get the difference and how to use it **

If we have a ad hoc method (for e.g. current method which is in the same viewset that we have used for different methods, basically ad-hoc means 'this'), we can use custom route for this method, we can define our own url above the method inside the @list_route and @detail_route decorator

The difference between the @list_route and @detail_route is the @detail_route decorator contains pk in its URL pattern and is intended for methods which require a single instance. The @list_route decorator is intended for methods which operate on a list of objects (list of records)

Get reference through enter link description here

For example

**It will hit to the same url at the url.py but for @list_raoute we have append /reset-user-password/ which we have mention on @list_route to the url when we call it.(e.g 

/// In url.py**

router = routers.DefaultRouter()

router.register(r'register', api_views.UserProfileViewSet,  base_name="userprofileviewset")
urlpatterns = [
    url(r'^api/v1/', include(router.urls)),
]

**////// In API call or in url call

for create user**
http://127.0.0.1:8000/api/v1/register/

### forget password

http://127.0.0.1:8000/api/v1/resister/reset-user-password/

)
class UserProfileViewSet(viewsets.ViewSet):
    """
    IT's use to create new user(auth user). accepted method is post. 
    end point /register
    """
    permission_classes = (AllowAny,)
    serializer_class = UserProfileSerializer

"""
It gives the list of all users
"""
def list(self, request):
    queryset = UserProfile.objects.all()
    serializer = self.serializer_class(queryset, many=True)
    return Response(serializer.data)

"""
It creates new user
"""
def create(self, request):
    serializer = self.serializer_class(data=request.data)
    # check email address is exists or not.
    user_type = request.data['user_type']
    user_token = register_by_social(request.data['email'], request.data['username'], user_type)

    if not user_token or user_token == True:
        if not User.objects.filter(Q(email=request.data['email']) 
            | Q(username=request.data['username'])).exists():

            if serializer.is_valid():
                userprofile = serializer.save()

                return Response({
                    'status': status.HTTP_201_CREATED,
                    'message': 'Successfully signup new user.',
                    'token': userprofile.user.auth_token.key })

            return Response({
                'status': status.HTTP_400_BAD_REQUEST,
                'message': 'Please provided required fields.',
                'error' : serializer.errors })

        return Response({
            'status': status.HTTP_409_CONFLICT,
            'message': 'Email address or username is already exists.'})

    return Response({
        'status': status.HTTP_200_OK,
        'message': 'Social user is already registered.',
        'token': user_token })


@list_route(permission_classes=[IsAuthenticated], authentication_classes = (BasicAuthentication, TokenAuthentication), 
        methods=['post'], url_path='reset-user-password')
def reset_user_password(self, request, pk=None):
    """
    It resets the user password
    """
    reset_password_serializer = UserResetPasswordSerializer(request.user, data=request.data)

    if reset_password_serializer.is_valid():

        if not request.user.check_password(request.data.get('password')):
            return Response({
                'status': status.HTTP_400_BAD_REQUEST,
                'message': 'Password id wrong, please enter correct password',
                })

        request.user.set_password(request.data.get('new_password'))
        request.user.save()
        return Response({
                'status': status.HTTP_201_CREATED,
                'message': 'Password updated successfully',
                })


class PlayListViewSet(viewsets.ViewSet):
    permission_classes = (IsAuthenticated,)
    serializer_class = PlayListSerializer
    serializer_add_playlist_class = LikeContentSerializer

    @detail_route(methods=['post'], url_path='add-content-to-playlist')
    def add_playlist(self, request, pk=None):

        serializer = self.serializer_add_playlist_class(data=request.data)
        playlist = PlayList.objects.filter(id=pk)
        if serializer.is_valid():
            content_type = request.data['content_type']

            if content_type =="audio":  
                content = Song.objects.filter(id=request.data['content'])
                playlist[0].songs.add(content[0])
                playlist[0].save()


            if content_type =="video":
                content = Video.objects.filter(id=request.data['content'])
                playlist[0].videos.add(content[0])
                playlist[0].save()

            if content_type =="youtube":
                content = YouTubeVideo.objects.filter(id=request.data['content'])
                playlist[0].youtbue_videos.add(content[0])
                playlist[0].save()

            return Response({
                'status': status.HTTP_201_CREATED,
                'message': 'Successfully playlist updated'})

        return Response({
            'status': status.HTTP_400_BAD_REQUEST,
            'message': 'Data is not valid, try again',
            'error' : serializer.errors })


回答3:

detail_route, is for an instance. What I mean, method generated with detail route, will be appended after an instance method, i.e. a retrieve. {prefix}/{lookup}/

Check : django drf router doc

If your model is books and 1 is the id:

class ParkingViewSet(viewsets.ModelViewSet):
serializer_class = BookSerializer

def retrieve(self, request, pk=None):
    # Here pk will be 1.
    queryset = Book.objects.get(pk=pk)         
    serializer = BookSerializer(queryset)                         
    return Response({'msg':"",'data':serializer.data, 'status':'OK'})

If xxx is your instance, you should user url_path variable to change default url. Something like this:

@detail_route(methods=['get'], url_path='(books/?P<num>\d+)')

Then in the method, you will have num as a parmeter

urls.py, will be generated with default router:

from django.conf.urls import url, include                                        
from recharge_card import views                                                  
from rest_framework.routers import DefaultRouter                                 

# Create a router and register our viewsets with it.                             
router = DefaultRouter()                                                         
router.register(r'xxx', views.XxxViewSet, base_name="xxx")  

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