先後端分離:就是前臺的開發和後臺的開發分離,這個技術方案的實現須要藉助API,簡單來講就是開發人員提供編程的接口被其餘人調用,調用以後會返回數據供其使用python
安裝:pip install djangorestframework
程序員
什麼是序列化?:把模型對象轉換爲JSON格式而後響應出去,便於客戶端進行數據解析shell
在應用目錄下建立名爲serializers.py的文件django
from rest_framework import serializers from myApp.models import Student, Grade #給學生類建立序列化類 class StudentSerializer(serializers.ModelSerializer): class Meta: model = Student fields = ("id", "name", "sex", "age", "content", "isDelete", "grade") #該班級建立序列化類 class GradeSerializer(serializers.ModelSerializer): class Meta: model = Grade fields = ("id", "name", "boyNum", "girlNum", "isDelete")
python manage.py shell
>>> from myApp.serializers import StudentSerializer >>> serializer = StudentSerializer() >>> print(serializer) StudentSerializer(): id = IntegerField(label='ID', read_only=True) name = CharField(max_length=20) sex = BooleanField(required=False) age = IntegerField(max_value=2147483647, min_value=-2147483648) contend = CharField(max_length=40) isDelete = BooleanField(label='IsDelete', required=False) grade = PrimaryKeyRelatedField(queryset=Grade.objects.all())
>>> from myApp.models import Student >>> stu = Student.objects.get(pk=1) >>> print(stu) 薛延美
>>> serializer = StudentSerializer(stu) >>> print(serializer.data) {'id': 1, 'name': '薛延美', 'sex': False, 'age': 20, 'contend': '我叫薛延美', 'isDelete': False, 'grade': 4} >>> print(type(serializer.data)) <class 'rest_framework.utils.serializer_helpers.ReturnDict'>
>>> from rest_framework.renderers import JSONRenderer >>> content = JSONRenderer().render(serializer.data) >>> print(content) b'{"id":1,"name":"\xe8\x96\x9b\xe5\xbb\xb6\xe7\xbe\x8e","sex":false,"age":20,"contend":"\xe6\x88 \x91\xe5\x8f\xab\xe8\x96\x9b\xe5\xbb\xb6\xe7\xbe\x8e","isDelete":false,"grade":4}'
>>> from rest_framework.parsers import JSONParser >>> from django.utils.six import BytesIO >>> stream = BytesIO(content) >>> print(stream) <_io.BytesIO object at 0x000001EECF597E08> >>> stu2 = JSONParser().parse(stream) >>> print(stu2) {'id': 1, 'name': '薛延美', 'sex': False, 'age': 20, 'contend': '我叫薛延美', 'isDelete': False, 'grade': 4} >>> print(type(stu2)) <class 'dict'>
>>> stu2.save() Traceback (most recent call last): File "<console>", line 1, in <module> AttributeError: 'dict' object has no attribute 'save' >>> serializer = StudentSerializer(data=stu2) >>> print(serializer.is_valid()) True >>> print(serializer.validated_data) OrderedDict([('name', '薛延美'), ('sex', False), ('age', 20), ('contend', '我叫薛延美'), ('isDel ete', False), ('grade', <Grade: python04>)]) >>> print(type(serializer.validated_data)) <class 'collections.OrderedDict'> >>> print(serializer.validated_data["name"]) 薛延美 >>> serializer.save() <Student: 薛延美>
from django.shortcuts import render from django.http import HttpResponse, JsonResponse from myApp.models import Student, Grade from rest_framework.renderers import JSONRenderer from rest_framework.parsers import JSONParser from django.utils.six import BytesIO from myApp.serializers import StudentSerializer, GradeSerializer def studentsList(request): if request.method == "GET": stus = Student.objects.all() #序列化 serializer = StudentSerializer(stus, many=True) return JsonResponse(serializer.data, safe=False) elif request.method == "POST": # content = JSONRenderer().render(request.POST) # stream = BytesIO(content) # stuDict = JSONParser().parse(stream) # serializer = StudentSerializer(data=stuDict) serializer = StudentSerializer(data=request.POST) if serializer.is_valid(): #存數據 serializer.save() return JsonResponse(serializer.data, status=201) return JsonResponse({"error":serializer.errors}, status=400) def studentDetail(request, pk): try: stu = Student.objects.get(pk=pk) except Student.DoesNotExist as e: return JsonResponse({"error":str(e)}, status=404) if request.method == "GET": serializer = StudentSerializer(stu) return JsonResponse(serializer.data) elif request.method == "PUT": #content = JSONRenderer().render(request.data) #stream = BytesIO(content) #stuDict = JSONParser().parse(stream) # print(stuDict) #修改 serializer = StudentSerializer(stu, data=request.data) if serializer.is_valid(): #存數據 serializer.save() return JsonResponse(serializer.data, status=201) return JsonResponse({"error":serializer.errors}, status=400) elif request.method == "DELETE": stu.delete() return HttpResponse(status=204,content_type="application/json")
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'myApp', 'rest_framework', ]
request.POST: 只能處理表單數據,而且只能處理POST請求擴展: request.data 能處理各類請求的數據,能夠處理PUT和PATCH請求的數據編程
HttpResponse、JsonResponse類: 用於返回json數據,在return的時候須要指明json格式擴展: Reponse類 會根據客戶端的請求頭信息返回正確的內容類型json
發送http請求會返回各類各樣的狀態碼,可是狀態碼都是數字,不可以明確的讓程序員瞭解是什麼問題擴展 HTTP_400_BAD_REQUEST 極大提升了可讀性後端
# from django.shortcuts import render # from django.http import HttpResponse, JsonResponse from myApp.models import Student, Grade # from rest_framework.renderers import JSONRenderer # from rest_framework.parsers import JSONParser # from django.utils.six import BytesIO from myApp.serializers import StudentSerializer from rest_framework import status from rest_framework.decorators import api_view from rest_framework.response import Response @api_view(["GET", "POST"]) def studentsList(request): if request.method == "GET": stus = Student.objects.all() #序列化 serializer = StudentSerializer(stus, many=True) # 不須要指定json格式,返回客戶端能夠返回json或者HTML,返回HTML內容的話,會在瀏覽器中通過渲染成頁面 return Response(serializer.data, status=status.HTTP_200_OK) elif request.method == "POST": # content = JSONRenderer().render(request.POST) # stream = BytesIO(content) # stuDict = JSONParser().parse(stream) serializer = StudentSerializer(data=request.data) if serializer.is_valid(): #存數據 serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) return Response({"error":serializer.errors}, status=status.HTTP_400_BAD_REQUEST) @api_view(["GET", "PUT", "DELETE"]) def studentDetail(request, pk): try: stu = Student.objects.get(pk=pk) except Student.DoesNotExist as e: return Response({"error":str(e)}, status=status.HTTP_404_NOT_FOUND) if request.method == "GET": serializer = StudentSerializer(stu) return Response(serializer.data) elif request.method == "PUT": # content = JSONRenderer().render(request.POST) # stream = BytesIO(content) # stuDict = JSONParser().parse(stream) # print(stuDict) #修改 serializer = StudentSerializer(stu, data=request.data) if serializer.is_valid(): #存數據 serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) return Response({"error":serializer.errors}, status=status.HTTP_400_BAD_REQUEST) elif request.method == "DELETE": stu.delete() return Response(status=status.HTTP_204_NO_CONTENT)
def studentsList(request, format=None): def studentDetail(request, pk, format=None):
from django.conf.urls import url from myApp import views #格式後綴 from rest_framework.urlpatterns import format_suffix_patterns urlpatterns = [ # GET /students/ # POST /students/ url(r'^students/$', views.studentsList), # GET /students/id # PUT /students/id # PATCH /students/id # DELETE /students/id url(r'^students/(?P<pk>\d+)/$', views.studentDetail), ] urlpatterns = format_suffix_patterns(urlpatterns)
http://127.0.0.1:8000/students.api http://127.0.0.1:8000/students.json
from myApp.models import Student from myApp.serializers import StudentSerializer from rest_framework import status from rest_framework.response import Response from rest_framework.views import APIView from django.http import Http404 class StudentsList(APIView): def get(self, request, format=None): stus = Student.objects.all() serializer = StudentSerializer(stus, many=True) return Response(serializer.data, status=status.HTTP_200_OK) def post(self, request, format=None): serializer = StudentSerializer(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) return Response({"error": serializer.errors}, status=status.HTTP_400_BAD_REQUEST) class StudentDetail(APIView): def getObject(self, pk): try: return Student.objects.get(pk=pk) except Student.DoesNotExist as e: raise Http404 def get(self, request, pk, format=None): stu = self.getObject(pk) serializer = StudentSerializer(stu) return Response(serializer.data) def put(self, request, pk, format=None): stu = self.getObject(pk) serializer = StudentSerializer(stu, data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) return Response({"error": serializer.errors}, status=status.HTTP_400_BAD_REQUEST) def delete(self, request, pk, format=None): stu = self.getObject(pk) stu.delete() return Response(status=status.HTTP_204_NO_CONTENT)
from django.conf.urls import url from myApp import views #格式後綴 from rest_framework.urlpatterns import format_suffix_patterns urlpatterns = [ # GET /students/ # POST /students/ url(r'^students/$', views.StudentsList.as_view()), # GET /students/id # PUT /students/id # PATCH /students/id # DELETE /students/id url(r'^students/(?P<pk>\d+)/$', views.StudentDetail.as_view()), ] urlpatterns = format_suffix_patterns(urlpatterns)
基本使用api
from myApp.models import Student from myApp.serializers import StudentSerializer from rest_framework import mixins, generics #父類中有且只有一個能繼承自APIView類 class StudentsList(mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView): queryset = Student.objects.all() serializer_class = StudentSerializer def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) def post(self, request, *args, **kwargs): return self.create(request, *args, **kwargs) class StudentDetail(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, generics.GenericAPIView): queryset = Student.objects.all() serializer_class = StudentSerializer def get(self, request, *args, **kwargs): return self.retrieve(request, *args, **kwargs) def put(self, request, *args, **kwargs): return self.update(request, *args, **kwargs) def delete(self, request, *args, **kwargs): return self.destroy(request, *args, **kwargs)
通用視圖使用瀏覽器
from myApp.models import Student from myApp.serializers import StudentSerializer from rest_framework import generics class StudentsList(generics.ListCreateAPIView): queryset = Student.objects.all() serializer_class = StudentSerializer class StudentDetail(generics.RetrieveUpdateDestroyAPIView): queryset = Student.objects.all() serializer_class = StudentSerializer
若是沒有權限認證功能,任何資源都會被任何用戶隨意修改,因此實現以下功能session
給學生添加所屬用戶字段:owner = models.ForeignKey("auth.User", related_name="students")
從新生成表
建立幾個用戶 python manage.py createsuperuser
在serializers.py文件中給User添加序列化類
from django.contrib.auth.models import User class UserSerializer(serializers.ModelSerializer): class Meta: model = User fields = ("id", "username", "students")
路由
from django.conf.urls import url from myApp import views #格式後綴 from rest_framework.urlpatterns import format_suffix_patterns urlpatterns = [ url(r'^students/$', views.StudentsList.as_view()), url(r'^students/(?P<pk>\d+)/$', views.StudentDetail.as_view()), url(r'^users/$', views.UsersList.as_view()), url(r'^users/(?P<pk>\d+)/$', views.UserDetail.as_view()), ] urlpatterns = format_suffix_patterns(urlpatterns)
視圖
from django.contrib.auth.models import User class UsersList(generics.ListCreateAPIView): queryset = User.objects.all() serializer_class = UserSerializer class UserDetail(generics.RetrieveDestroyAPIView): queryset = User.objects.all() serializer_class = UserSerializer
概述: 還不能把Student和User關聯,由於在使用的時候User的數據時經過Request傳入的,而不是以序列化數據傳遞的,此時剛纔添加了一個owner做爲外鍵,此時使用外鍵
class StudentsList(generics.ListCreateAPIView): queryset = Student.objects.all() serializer_class = StudentSerializer #讓用戶在經過post請求建立一個新的student時,在保證建立學生時會把request中的user賦值給該學生的owner字段 def perform_create(self, serializer): serializer.save(owner=self.request.user)
class StudentSerializer(serializers.ModelSerializer): class Meta: owner = serializers.ReadOnlyField(source="owner.username") model = Student fields = ("id", "name", "sex", "age", "contend", "isDelete", "grade", "owner")
from rest_framework import permissions class StudentsList(generics.ListCreateAPIView): queryset = Student.objects.all() serializer_class = StudentSerializer permission_classes = (permissions.IsAuthenticatedOrReadOnly,) #讓用戶在經過post請求建立一個新的student時,在保證建立學生時會把request中的user賦值給該學生的owner字段 def perform_create(self, serializer): serializer.save(owner=self.request.user) class StudentDetail(generics.RetrieveUpdateDestroyAPIView): queryset = Student.objects.all() serializer_class = StudentSerializer # 只有全部者用戶才能刪除、修改,其餘用戶只能訪問 permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
工程目錄下與工程目同名目錄下的urls.py文件
from django.conf.urls import url, include from django.contrib import admin urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^api-auth/', include("rest_framework.urls", namespace="rest_framework")), url(r'^', include("myApp.urls")), ]
要實現讓全部的Students能夠被全部人訪問,可是每一個學生只能被其建立者所操做。
須要自定義權限,讓每一個學生只能被其建立者所操做,在應用目錄下建立permissions.py的文件
from rest_framework import permissions class IsOwnerOrReadOnly(permissions.BasePermission): def has_object_permission(self, request, view, obj): if request.method in permissions.SAFE_METHODS: # 用戶請求爲GET 能夠只讀 return True return obj.owner == request.user
添加自定義權限
from myApp.permissions import IsOwnerOrReadOnly class StudentDetail(generics.RetrieveUpdateDestroyAPIView): queryset = Student.objects.all() serializer_class = StudentSerializer # 只有全部者用戶才能刪除、修改,其餘用戶只能訪問 permission_classes = (permissions.IsAuthenticatedOrReadOnly,IsOwnerOrReadOnly)
from django.contrib.auth import login
目的: 介紹另外一種基於類的視圖的寫法,它的抽象程度更高,代碼更少
from myApp.models import Student from myApp.serializers import StudentSerializer, UserSerializer from rest_framework import permissions from myApp.permissions import IsOwnerOrReadOnly from django.contrib.auth.models import User from rest_framework import viewsets class StudentViewSet(viewsets.ModelViewSet): queryset = Student.objects.all() serializer_class = StudentSerializer permission_classes = (permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly) def perform_create(self, serializer): serializer.save(owner=self.request.user) class UserViewSet(viewsets.ReadOnlyModelViewSet): queryset = User.objects.all() serializer_class = UserSerializer
from django.conf.urls import url, include from myApp.views import StudentViewSet, UserViewSet from rest_framework.urlpatterns import format_suffix_patterns students_list = StudentViewSet.as_view({ "get":"list", "post":"create" }) student_detail = StudentViewSet.as_view({ "get":"retrieve", "put":"update", "patch":"partial_update", "delete":"destroy" }) users_list = UserViewSet.as_view({ "get":"list" }) user_detail = UserViewSet.as_view({ "get":"retrieve" }) urlpatterns = format_suffix_patterns([ url(r'^students/$', students_list, name="students_list"), url(r'^students/(?P<pk>\d+)/$', student_detail, name="student_detail"), url(r'^users/$', users_list, name="users_list"), url(r'^users/(?P<pk>\d+)/$', user_detail, name="user_detail"), ])
from django.conf.urls import url, include from myApp import views from rest_framework.routers import DefaultRouter router = DefaultRouter() router.register(r'students', views.StudentViewSet) router.register(r'users', views.UserViewSet) urlpatterns = [ url(r'^', include(router.urls)) ]