[Django learning] (fourteen) custom action_router

Before our view class can inherit GenericViewSet or ModelViewSet, we no longer need to customize the general action method, but sometimes we need to customize the action, how should we design it?

custom action

1. Handwritten view logic

1.1, first customize the action method in the view set, the name is names

class ProjectsViewSet(
    viewsets.ModelViewSet):
    # 指定当前类视图需要使用的查询集
    queryset = ProjectsModel.objects.all()
    # 指定当前类视图需要使用的序列化器类
    serializer_class = ProjectModelSerializer
    # lookup_field = 'Id'
    # 声明需要使用的引擎类
    filter_backends = [filters.SearchFilter,
                       filters.OrderingFilter
                       ]
    # 定义需要过滤的字段
    search_fields = ['name', 'id']

    # 定义需要排序的字段
    ordering_fields = ['id', 'name']
    # 声明需要使用的分页引擎
    pagination_class = PageNumberPagination
    @action(methods=['GET', 'POST'], detail=False)
    def names(self, request, *args, **kwargs):
        qs = self.get_queryset()
        lst = []
        for obj in qs:
            dict = {
                'id': obj.id,
                'name': obj.name,
            }
            lst.append(dict)
        return Response(lst, content_type='application/json')

1.2. Define a new route in the routing table url.py

urlpatterns = [
    path('projects/names/',views.ProjectsViewSet.as_view({'get':'names','post':'names'})),
]

 Support get and post request methods

 

 2. Use the serializer class

2.1 Create a new serializer class

class ProjectNameSerializer(serializers.ModelSerializer):

    class Meta:
        model = ProjectsModel
        fields = ('id', 'name')

2.2 Routing table defines routing

urlpatterns = [
    path('projects/names/',views.ProjectsViewSet.as_view({'get':'names','post':'names'})),
]

Only after the view set inherits Viewset or GenericViewset, it has the function of one-to-one correspondence between method name and action 

2.3 Rewrite the custom action method in the view class

from .serializers import ProjectNameSerializer
    @action(methods=['GET', 'POST'], detail=False)
    def names(self, request, *args, **kwargs):
        qs = self.get_queryset()
        # lst = []
        # for obj in qs:
        #     dict = {
        #         'id': obj.id,
        #         'name': obj.name,
        #     }
        #     lst.append(dict)
        # return Response(lst, content_type='application/json')
        serializer_obj = ProjectNameSerializer(instance=qs, many=True)
        return Response(serializer_obj.data, status=status.HTTP_200_OK)

 2.4 Extract the ProjectNameSerializer and rewrite the get_serializer_class method

  • If multiple different serializer classes are used in the current class view, then get_serializer_class can be rewritten
  • After inheriting the view set class, the action attribute will be provided to specify the name of the action method of the current request
  • Different serializer classes (different query sets) can be selected according to different actions
    @action(methods=['GET', 'POST'], detail=False)
    def names(self, request, *args, **kwargs):
        qs = self.get_queryset()
        serializer_obj=self.get_serializer(instance=qs, many=True)
        return Response(serializer_obj.data, status=status.HTTP_200_OK)

    def get_serializer_class(self):
        if self.action=='names':
            return ProjectNameSerializer
        return self.serializer_class

 If the request is /projects/names/, a custom serializer class is used for data output

 If other routing paths are requested, the globally specified serializer class (serializer_class=ProjectModelSerializer) can be used to process data normally and serialize output

  •  You can use the action decorator to specify a custom action method (when using a router, routing entries will be automatically generated)
  • If methods are not specified, the current action only supports GET method requests
  • You can specify that the current action supports multiple request methods, and you need to add the uppercase request method to the list
  • detail specifies whether the current action is a detail view
  • url_path specifies the path string of the url
  • url_name specifies the name of the url path
  • If url_path and url_name are not specified, the default is the name of the action method

 register route

Import routers in the routing table

from rest_framework import routers

router = routers.SimpleRouter()
# 注册路由
router.register(r'projects', views.ProjectsViewSet)

urlpatterns = router.urls
​

 Register routes:

  • Only viewsets support defining router functions
  • The register method can register routing entries
  • The first parameter is the prefix of the routing entry, often need to add r'sub-application name'
  • The second parameter is the view set object, no need to call as_view({})
  •  The DefaultRouter object can be defined. Compared with the SimpleRouter routing object, a root route will be automatically added (specify the entry address of the current project)
    • router = routers.DefaultRouter()

 

If url_path and url_name are not specified, the URL path is obtained through the routing name

 If url_path and url_name are specified in action, url_path specifies the path string of url, and url_name specifies the name of url path

@action(methods=['GET', 'POST'], detail=False,url_path='na', url_name='an')
def names(self, request, *args, **kwargs):
    qs = self.get_queryset()

 

 Sometimes, some routes we don't want to generate through the router, need to be generated in urlpatterns

Way 1: router.urlsA list that can be appended to an existing view.

from rest_framework import routers

router = routers.SimpleRouter()
# 注册路由
router.register(r'projects', views.ProjectsViewSet)
urlpatterns = []
urlpatterns += router.urls

Method 2: Or you can use Django's includefunction, like this

from rest_framework import routers

router = routers.SimpleRouter()
# 注册路由
router.register(r'projects', views.ProjectsViewSet)
urlpatterns = [
          path('', include(router.urls))
]

Guess you like

Origin blog.csdn.net/weixin_43569834/article/details/131722624