python django

DRF(django-rest-framwork)

技术分享

systemime
2020-04-28
7 min

django-rest-framework简单使用介绍

# 视图-序列化数据

from api import models
from rest_framework import serializers
from rest_framework.view import APIView
from rest_framework.generics import GenericAPIView  # get,delete,put,post均有
from rest_framework.generics import ListAPIView, DestoryAPIView, UpdateAPIView, CreateAPIView, RetrieveAPIView
from rest_framework.response import Response
class CourseSerializers(serializers.ModelSerializer):
    """
    序列化查询数据为列表
    一般写法
    """
    class Mate:
        model = models.Course  # 需要序列化的类的名称
        fields = "__all__"
        
    """
    只需要其中某几个字段
    """
    class Mate:
        model = models.Course  # 需要序列化的类的名称
        fields = ['id','name',...]
        
    """
    不需要某个字段
    """
    class Mate:
        model = models.Course  # 需要序列化的类的名称
        exclude = ['字段名']  # 不显示某一字段,写这句话不写fields
        
	"""
    存在表单表关联情况,关联数据默认只显示ID
    """
    cname = serializers.CharField(source='course.title')
    class Mate:
        model = models.Course
        fields = ['id', 'name', 'cname']
        
    """
    存在多对多关系时,关联数据默认只显示ID
    假设多对多字段是tag
    """
    tag_text = serializers.SerializerMethodFeild()  # 也可以时tag_xxx随便写
    class Mate:
        model = models.Course
        fields = ['id', 'name', 'tag_text']
    def get_tag_text(self, obj):
        tag_list = obj.tag.all()
        return [{'id':row.id,'caption':row.name} for row in tag_list]
    	# return [row.name for row in tag_list]
        
    """
    models存在choices情况
    level_choices = (
    	(1,"中级"),
        (2,"高级")
    )
    level = models.IntegerField(verbose_name='级别', choices=level_choices, default=1)
    已获得单条数据库对象xxx,一般获取方法:xxx.get_level_display()
    """
    level_text = serializers.CharFiled(source='get_level_display()')
    class Mate:
        model = models.Course
        fields = ['id', 'name', 'level_text']
    
# 方法一(待确认)
class CourseView(GenericAPIView):
    queryset = models.Course.object.all()
    def get(self, request, *args, **kwargs):
        data = self.get_queryset()
        ser = CourseSerializers(instance=data, many=True)  # 单条数据many=false
        return Response("课程列表")

# 方法二
class CourseView(APIView):
    def get(self, request, *args, **kwargs):
        queryset = models.Course.object.all()
        ser = CourseSerializers(instance=queryset, many=True)  # 单条数据many=false
        return Response(ser.data)

# 方法三
class CourseView(ListAPIView, DestoryAPIView, UpdateAPIView, CreateAPIView, RetrieveAPIView):
    """
    LiserAPIView: get方法,获取列表数据
    DestroyAPIView: delete方法
    UpdateAPIView: put和patch方法
    CreateAPIView: create方法
    RetrieveAPIView:获取一条数据
    """
    queryset = models.Course.objects.all()
    serializer_class = CourseSerializers
    
# 方法三
from rest_framework.viewsets import ModelViewSet
class CourseView(ModelViewSet):
    """
    ModelViewSet 包括方法二中比如创建删除等class
    但是url中需要这样写
    ...
    url(r'^user/(?P<pk>\d+)/$', view.CourseView.as_view({'get': 'list', ''})),
    """
    queryset = models.Course.objects.all()
    serializer_class = CourseSerializers

# View类应用场景

# APIView

一般用于非常复杂的非数据库操作

图片.png

# ListAPIView等

from rest_framework.generics import ListAPIView, DestoryAPIView, UpdateAPIView, CreateAPIView, RetrieveAPIView

一般用于项目只需要一个或者几个接口时,而不是全部增删改查方法

# ModelViewSet

一般用于实现全部增删改查功能

# 面试题

# 你曾经写接口时继承过那些类

至少说出:APIView,ListAPIView,ModelViewset

# GenericAPIView作用

# 制定了接口执行流程

如果继承了GenericAPIView的类,他们内部取数据时调用self.get_queryset(),
而它定义在GenericAPIView, 内部返回self.queryset

# 版本控制

如果加入了版本控制,所有的api接口都必须带上版本号

# 总/分发url.py
from app_name import views
...
urlpatterns = [
	url(r'api/(?P<version>\w+)/test/', view.TestView.as_view())  # url关键字必须是version
]

# views.py
from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response 

class TestView(APIView):
    def get(self, request, *args, **kwargs):
        print(request.version)
        return Response('...')

# settings.py
INSTALLED_APPS = [
	...
    'rest_framework',
]

REST_FRAMEWORK = {
	'DEFAULT_VERSIONING_CLASS': "rest_framework.versioning.URLPathVersioning",
    'ALLOWED_VERSIONS': ['V1', 'V2'],  # 允许的版本
}

# 访问
http://127.0.0.1:8000/api/v1/test/
  • 不可忽视
# urls.py
from app_name import views
...
urlpatterns = [
	url(r'api/(?P<version>\w+)/crossdomiam/', view.TestView.as_view())  # url关键字必须是version
]

# view.py
from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response 

class CrossView(APIView):
    def get(self, request):
        return Response('...')
    
# 报错原因
url中携带参数传递,方法中必须接受参数
# 正确写法
def get(self, request, *args, **kwargs):

# 读取xml文件

class CrossView(APIView):
    def get(self, request, *args, **kwargs):
        with open('crossdomian.xml') as f:
            data = f.read()
        return Response(data)

# CRUD实现(创建、读取、更新、删除)

  • urls.py
from app_name import views

urlpatterns = [
	url(r'api/(?P<version>\w+)/course/new/$',views.CourseNewView.as_view()),
    # 或
    url(r'api/(?P<version>\w+)/course/crud/$',views.CourseCrudView.as_view({'get':'list','post':'create'}))
    url(r'api/(?P<version>\w+)/course/crud/(?P<pk>\d+)/$',views.CourseCrudView.as_view({'get':'retrieve','put':'update','patch':'partial_update','delete':'destroy'}))
    # patch 调用的方法本质也是update,增加了一个属性,其实可以不写
]
  • view.py
from rest_framework.generics  import CreateAPIView,ListAPIView

class CourseNewView(ListAPIView, CreateAPIView):
# 获取单条数据需要把ListAPIView换成RetrieveAPIView
# 同时增加一条url用于接收需要获取数据id等信息
    queryset = models.Course.object.all()
    serializer_class = CourseSerializer
# 或
from rest_framework.viewset import ModelViewset

class CourseCrudView(ModelViewset):
    queryset = models.Course.object.all()
    serializer_class = CourseSerializer
   

# ModelViewSet URL简写方式

  • 一般方法
from django.conf.urls import url
from app_name import views

urlpatterns = [
    url(r'^api/(?P<version>\w+)/course/crud/$',views.CourseCrudView.as_view({'get':'list','post':'create'}))
    url(r'^api/(?P<version>\w+)/course/crud/(?P<pk>\d+)/$',views.CourseCrudView.as_view({'get':'retrieve','put':'update','patch':'partial_update','delete':'destroy'}))
]
  • 简写
from django.conf.urls import url, include
from rest_framework import routers
from app_name import views

router = routers.DefaultRouter()
router.register(r'前缀名称,如 video_new', views.CourseCrudView)

urlpatterns = [
	url(r'^', include(router.urls)),
    # 也可以加前缀
    # url(r'^api/(?P<version>\w+)/', include(router.urls)),
]

# 多对多请求增加数据

# 数据请求格式
{"id":1, "title":"xxx", "tag":[1,2]}  # tag是多对多对应关系

# 后端
ModelViewSet

# CRUD实现(从文件中获取)

  • urls.py
from app_name import view

urlpatterns = [
	url(r'api/(?P<version>\w+)/course/file/$',views.CourseFileView.as_view({'get':'list','post':'create'}))
    url(r'api/(?P<version>\w+)/course/file/(?P<pk>\d+)/$',views.CourseFileView.as_view({'get':'retrieve','put':'update','patch':'partial_update','delete':'destroy'}))
]
  • views.py
from rest_framework.viewset import ModelViewset

class CourseFileView(ModelViewset):
    queryset = models.Course.object.all()
    serializer_class = CourseSerializer
    
    # 开始重写list方法
    def list(self, request, *args, **kwargs):
        with open('crossdomian.xml') as f:
            data = f.read()
        return Response(data)
上次编辑于: 5/24/2021, 5:55:49 AM