如何在Django 2.0 + DRF 3.8中正确配置并注册ViewSet路由
Hey there! Let's break down how to smoothly switch from class-based views with explicit URLs to using DRF ViewSets and routers for automatic URL generation in your DRF 3.8 + Django 2.0 setup. I've done this plenty of times, so let's walk through it step by step.
First, you'll want to replace your existing class-based views (like ListAPIView, RetrieveAPIView, etc.) with a ViewSet. DRF provides pre-built ViewSets that bundle common actions together to save you time.
For example, if you're working with a UserProfile model, update your UserProfile/views.py like this:
from rest_framework import viewsets from .models import UserProfile from .serializers import UserProfileSerializer # ModelViewSet gives you all CRUD actions: list, create, retrieve, update, partial_update, destroy class UserProfileViewSet(viewsets.ModelViewSet): queryset = UserProfile.objects.all() serializer_class = UserProfileSerializer
If you only need read-only access (no create/update/delete), use viewsets.ReadOnlyModelViewSet instead—it includes just list and retrieve actions.
Next, let's configure the router in UserProfile/urls.py to auto-generate URLs for your ViewSet. DRF's DefaultRouter handles all the URL mapping automatically, so you don't have to write each URL pattern manually.
Here's how to update your app's urls.py:
from django.urls import path, include from rest_framework.routers import DefaultRouter from .views import UserProfileViewSet # Initialize the router router = DefaultRouter() # Register your ViewSet: the first argument is the base path, basename is used for reverse lookups router.register(r'', UserProfileViewSet, basename='userprofile') urlpatterns = [ # Include all URLs generated by the router path('', include(router.urls)), ]
With this setup, the router will automatically create these URLs:
GET /userprofile/→ Lists all user profiles (listaction)POST /userprofile/→ Creates a new user profile (createaction)GET /userprofile/<pk>/→ Retrieves a single user profile (retrieveaction)PUT /userprofile/<pk>/→ Updates a user profile (updateaction)PATCH /userprofile/<pk>/→ Partially updates a user profile (partial_updateaction)DELETE /userprofile/<pk>/→ Deletes a user profile (destroyaction)
Want Custom Actions?
If you need to add custom endpoints (like a stats endpoint for a user), use the @action decorator on your ViewSet:
from rest_framework.decorators import action from rest_framework.response import Response class UserProfileViewSet(viewsets.ModelViewSet): queryset = UserProfile.objects.all() serializer_class = UserProfileSerializer # detail=True means this action applies to a single instance (needs a pk) @action(detail=True, methods=['get']) def stats(self, request, pk=None): profile = self.get_object() # Example: calculate some stats for the profile stats_data = { 'total_posts': profile.posts.count(), 'follower_count': profile.followers.count() } return Response(stats_data)
This will add a new URL: GET /userprofile/<pk>/stats/
Your existing project urls.py looks good, but since you're on Django 2.0, you can use path instead of url for cleaner syntax (though url still works):
from django.urls import path, include urlpatterns = [ path('userprofile/', include('UserProfile.urls', namespace='UserProfile')), ]
When using reverse lookups (like in templates or views), you can reference the auto-generated routes using the namespace and basename:
reverse('UserProfile:userprofile-list')→ Points to the list endpointreverse('UserProfile:userprofile-detail', kwargs={'pk': 1})→ Points to the detail endpoint for profile with pk=1reverse('UserProfile:userprofile-stats', kwargs={'pk': 1})→ Points to the custom stats endpoint
- If you don't want the auto-generated API root view (the one that lists all endpoints), use
SimpleRouterinstead ofDefaultRouter—it's more minimal. - You can still set
permission_classes,authentication_classes, orpagination_classon your ViewSet just like you did with class-based views. - If you need to override a default action (like customizing the
listresponse), just define alistmethod in your ViewSet, same as you would with a class-based view.
内容的提问来源于stack exchange,提问作者mr530

