serializers 序列化

20 个模块?

BrowsableAPIRenderer
https://www.django-rest-framework.org/topics/browsable-api/#the-browsable-api
https://www.imooc.com/video/22363

$ python manage.py createsuperuser

$ python manage.py makemigrations $ python manage.py migrate

os.pardir ❓

os.pathdir ❓

views 返回 HTML,全栈开发, PHP / JAVA

$ python3 manage.py runserver 0.0.0.0:8080

Restful API 规范
RESTFUL 最佳实践维度:


python manage.py migrate
python manage.py makemigrations
here, https://github.com/liaogx/drf-tutorial
http://github.com/liaogx/drf-tutorial
DRF提供了几种permission level:

如何在API level提供非全局的权限控制?

类view:

然而上面还是不够的,不能提供基于业务的精细化的权限控制。比如老师只能修改自己的课程信息,不能修改不是自己的课程的信息。
本节后半段提供的是如何基于业务需要,自定义权限。从6:03开始的内容开始看
Token Authentication
需要在setting的installed 里添加'rest_framework.authtoken',
这节就看看就好了。有些细节我觉得要看源码才能懂。而且正常也是用jwt,不用这个了。
通过这种方式,认证成功的话,request.user 还是django的user,
request.auth就变成了rest_framework.authtoken.models.Token
如果认证失败,resp的header会多一个www-authenticate的field,成功是没这个fIeld的

如何对不同的view提供不同的认证方式?而不是所有api的view都用同一个认证方式呢?
function view:
用@authentication_classes()
class view/viewset:
用 class property
authentication_classses = (a,,b,c)
auth: 登录的用户能访问哪些资源,API
authen: 对登录中的用户身份进行认证

认证机制依赖于django.contrib.auth
Django会按上面的列表顺序逐个尝试,并使用第一个成功通过的认证
Basic: 密码认证。不建议用于Producrion。前端要用户输入密码后,会在header里加一个authorizaion field, 内容是一个bas64 加密的hash value 但是base 64可以被解密。所以不安全。
使用Basic认证的话,如果通过了。会把下面的self.request.user设置成 contrib.auth.models.User
self.request.auth 设置为none

如何认证失败。会在response的header里多一个 WWW-authenticate的field 这个就是个规律。方便你debug
Session认证:
如果是post,put, 需要提供CSRF token。
认证通过的话,如果通过了。会把下面的self.request.user设置成 contrib.auth.models.User
self.request.auth 设置为none。
认证失败的话会响应403 forbidden,但是response的header里不会多额外信息
通用类视图简化了自己的代码。但是我觉得会让人觉得不清晰。因为hide details.
这节谈了到底该如何选择view的写法,func, class, or generics, viewsets
还有下面这些内容没有讲:
DRF的运行机制,限流,缓存
这节回头再来看看。就是讲解了怎么用那个api doc
本文demo了Postman里怎么用各种author。介绍了api key的形式和输入密码的形式。
还demo了collection的含义,查看History, 如何保存某个request,如何添加request 到某个collections
collections右键里可以设置这个collections的全局的authorization信息。这样就不用一个个copy token
drf的序列化器和django自带的有什么不同呢?
drf自带的缺点是:
缺乏前端json数据的验证处理
验证器的参数
同时序列化多个对象
序列化过程中添加上下文,比如添加queryset中没有的数据到最后想返回的json里
没有对无效数据的异常处理
本节内容

Django原生中是function base view 和class view2种。之前ins项目有用到。本节也有代码复习演示
这节课pycharm直接创建的方式我可能是社区版,没有这个功能。
anyway, demo里的首次migration我也做了一次。不然无法创建admin user for login to admin portal.
put,更新。指的是更新完整的一条DB记录。比如有个表有5个columns,你put请求要包含完整的5个columns的值。
patch部分更新,比如只是update username
这里调用gcbv/list/会报错:
views.py文件内容:
from django.http.response import HttpResponse
from rest_framework.decorators import api_view
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import Course
from .serializers import CourseSerializer
from rest_framework import generics
"""一、函数式编程"""
@api_view(["GET","POST"])
def course_list(request):
"""
获取所有课程信息或新增一个课程
"""
if request.method == "GET":
s = CourseSerializer(instance=Course.objects.all(),many=True)
return Response(data=s.data, status=status.HTTP_200_OK)
elif request.method == "POST":
s = CourseSerializer(data=request.data, partial=True)
if s.is_valid():
s.save(teacher=request.user)
return Response(data=s.data, status=status.HTTP_201_CREATED)
return Response(s.errors, status=status.HTTP_400_BAD_REQUEST)
@api_view(["GET","PUT","DELETE"])
def course_detail(request,pk):
"""
获取、删除更新一个课程
"""
try:
course = Course.objects.get(pk=pk)
except Course.DoesNotExist:
return Response(data={"msg": "没有此课程信息"},status=status.HTTP_404_NOT_FOUND)
else:
if request.method == "GET":
s = CourseSerializer(instance=course)
return Response(data=s.data, status=status.HTTP_200_OK)
elif request.method == "PUT":
# 这里的instance的只是查出来的course,而data则是request传来的值
s = CourseSerializer(instance=course, data=request.data)
if s.is_valid():
s.save()
return Response(s.data,status=status.HTTP_200_OK)
elif request.method == "DELETE":
course.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
"""类试图 Class Based Views"""
class CourseList(APIView):
def get(self, request):
queryset = Course.objects.all()
s = CourseSerializer(instance=queryset, many=True) # instance = xxx 是查询集
return Response(s.data, status=status.HTTP_200_OK)
def post(self,request):
s = CourseSerializer(data=request.data) # data是传递过来的数据,return前要先调用is_valid()方法验证数据
if s.is_valid():
s.save(teacher=self.request.user)
return Response(data=s.data, status=status.HTTP_201_CREATED)
return Response(s.errors, status.HTTP_400_BAD_REQUEST)
class CourseDetail(APIView):
@staticmethod
def get_object(pk):
try:
return Course.objects.get(pk=pk)
except Course.DoesNotExist:
# 返回none
return
def get(self,request,pk):
obj = self.get_object(pk)
if not obj:
return Response(data={"msg": "没有此课程信息"}, status=status.HTTP_404_NOT_FOUND)
s = CourseSerializer(instance=obj)
return Response(s.data, status=status.HTTP_200_OK)
def put(self,request,pk):
obj = self.get_object(pk)
if not obj:
return Response(data={"msg": "没有此课程信息"}, status=status.HTTP_404_NOT_FOUND)
s = CourseSerializer(instance=obj, data=request.data)
if s.is_valid():
s.save()
return Response(data=s.data, status=status.HTTP_201_CREATED)
return Response(data=s.data,status=status.HTTP_400_BAD_REQUEST)
def delete(self,request,pk):
obj = self.get_object(pk)
if not obj:
return Response(data={"msg": "没有此课程信息"}, status=status.HTTP_404_NOT_FOUND)
obj.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
"""三、通用类试图 Generic Class Based View"""
class GCourseList(generics.ListCreateAPIView):
queryset = Course.objects.all()
serializer_class = CourseSerializer
def perform_create(self, serializer):
serializer.save(teacher=self.request.user)
class GCourseDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Course.objects.all()
serializer_class = CourseSerializer
course的views.py
from django.http.response import HttpResponse
from rest_framework.decorators import api_view
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import Course
from .serializers import CourseSerializer
"""一、函数式编程"""
@api_view(["GET","POST"])
def course_list(request):
"""
获取所有课程信息或新增一个课程
"""
if request.method == "GET":
s = CourseSerializer(instance=Course.objects.all(),many=True)
return Response(data=s.data, status=status.HTTP_200_OK)
elif request.method == "POST":
s = CourseSerializer(data=request.data, partial=True)
if s.is_valid():
s.save(teacher=request.user)
return Response(data=s.data, status=status.HTTP_201_CREATED)
return Response(s.errors, status=status.HTTP_400_BAD_REQUEST)
@api_view(["GET","PUT","DELETE"])
def course_detail(request,pk):
"""
获取、删除更新一个课程
"""
try:
course = Course.objects.get(pk=pk)
except Course.DoesNotExist:
return Response(data={"msg": "没有此课程信息"},status=status.HTTP_404_NOT_FOUND)
else:
if request.method == "GET":
s = CourseSerializer(instance=course)
return Response(data=s.data, status=status.HTTP_200_OK)
elif request.method == "PUT":
# 这里的instance的只是查出来的course,而data则是request传来的值
s = CourseSerializer(instance=course, data=request.data)
if s.is_valid():
s.save()
return Response(s.data,status=status.HTTP_200_OK)
elif request.method == "DELETE":
course.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
"""类试图 Class Based Views"""
class CourseList(APIView):
def get(self, request):
queryset = Course.objects.all()
s = CourseSerializer(instance=queryset, many=True) # instance = xxx 是查询集
return Response(s.data, status=status.HTTP_200_OK)
def post(self,request):
s = CourseSerializer(data=request.data) # data是传递过来的数据,return前要先调用is_valid()方法验证数据
if s.is_valid():
s.save(teacher=self.request.user)
return Response(data=s.data, status=status.HTTP_201_CREATED)
return Response(s.errors, status.HTTP_400_BAD_REQUEST)
class CourseDetail(APIView):
@staticmethod
def get_object(pk):
try:
return Course.objects.get(pk=pk)
except Course.DoesNotExist:
# 返回none
return
def get(self,request,pk):
obj = self.get_object(pk)
if not obj:
return Response(data={"msg": "没有此课程信息"}, status=status.HTTP_404_NOT_FOUND)
s = CourseSerializer(instance=obj)
return Response(s.data, status=status.HTTP_200_OK)
def put(self,request,pk):
obj = self.get_object(pk)
if not obj:
return Response(data={"msg": "没有此课程信息"}, status=status.HTTP_404_NOT_FOUND)
s = CourseSerializer(instance=obj, data=request.data)
if s.is_valid():
s.save()
return Response(data=s.data, status=status.HTTP_201_CREATED)
return Response(data=s.data,status=status.HTTP_400_BAD_REQUEST)
def delete(self,request,pk):
obj = self.get_object(pk)
if not obj:
return Response(data={"msg": "没有此课程信息"}, status=status.HTTP_404_NOT_FOUND)
obj.delete()
return Response(status=status.HTTP_204_NO_CONTENT)添加 course下的路由:
from django.urls import path, include
from course import views
urlpatterns = [
# Function Based View
path("fbv/list/", views.course_list, name="fbv-list"),
path("fbv/detail/<int:pk>/", views.course_detail, name="fbv-detail"),
# Class Based View
path("cbv/list/", views.CourseList.as_view(), name="cbv-list"),
path("cbv/detail/<int:pk>/", views.CourseDetail.as_view(), name="cbv-detail")
]工程下的urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('api-auth/', include('rest_framework.urls')), # DRF的登录退出
path('admin/', admin.site.urls),
path('course/', include('course.urls'))
]
实例代码:course工程下views.py
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status
from .models import Course
from .serializers import CourseSerializer
"""一、函数式编程 Function Baseed View"""
@api_view(["GET","POST"])
def course_list(request):
"""
获取所有课程信息或新增一个课程
:param request:
:return:
"""
if request.method == "GET":
s = CourseSerializer(instance=Course.objects.all(), many=True)
return Response(data=s.data, status=status.HTTP_200_OK)
elif request.method == "POST":
# partial=True 允许传部分字段过来不是全部,但是model要求必须传的,这个参数设置了也没用
# 只适用于非必填字段
s = CourseSerializer(data=request.data, partial=True)
if s.is_valid():
s.save(teacher=request.user)
return Response(data=s.data,status=status.HTTP_201_CREATED)
return Response(s.errors, status=status.HTTP_400_BAD_REQUEST)
@api_view(["GET","PUT","DELETE"])
def course_detail(request, pk):
"""
获取删除或更新一个课程
"""
try:
course = Course.objects.get(pk=pk)
except Course.DoesNotExist:
return Response(data={"msg": "没有此课程信息"}, status=status.HTTP_404_NOT_FOUND)
else:
if request.method == "GET":
s = CourseSerializer(instance=course)
return Response(data=s.data, status=status.HTTP_200_OK)
elif request.method == "PUT":
s = CourseSerializer(instance=course,data=request.data)
if s.is_valid():
s.save()
return Response(s.data, status=status.HTTP_200_CREATED)
elif request.method == "DELETE":
course.delete()
return Response(status=status.HTTP_204_NO_CONTENT)