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