Restframework
這裏先簡單的介紹一下restful協議,Django REST framework 是一個強大且靈活的工具包,用以構建Web APIs,體現了一切皆是資源,操做只是請求方式前端
基於restful協議的框架有不少,Django下的restframework只是其中的一種,restful協議是一套開發的規範,url裏不能有動做相關的詞彙,好比add,edit,這些都經過用請求的方式來實現。python
安裝數據庫
pip3 install djangorestframework
註冊django
INSTALLED_APPS = ( ... 'rest_framework', )
基本使用json
登陸認證restful
url(r'^login/$', views.LoginView.as_view(),name="login"),
def get_random_str(user): import hashlib,time ctime=str(time.time()) md5=hashlib.md5(bytes(user,encoding="utf8")) md5.update(bytes(ctime,encoding="utf8")) return md5.hexdigest() from .models import User class LoginView(APIView): def post(self,request): name=request.data.get("name") pwd=request.data.get("pwd") user=User.objects.filter(name=name,pwd=pwd).first() res = {"state_code": 1000, "msg": None} if user: random_str=get_random_str(user.name) token=Token.objects.update_or_create(user=user,defaults={"token":random_str}) res["token"]=random_str else: res["state_code"]=1001 #錯誤狀態碼 res["msg"] = "用戶名或者密碼錯誤" import json return Response(json.dumps(res,ensure_ascii=False))
認證類app
from .models import * class TokenAuth(BaseAuthentication): def authenticate(self,request): token = request.GET.get("token") token_obj = Token.objects.filter(token=token).first() if not token_obj: raise exceptions.AuthenticationFailed("驗證失敗123!") else: return token_obj.user.name,token_obj.token
models.py
from django.db import models class Author(models.Model): name=models.CharField(max_length=32) age=models.IntegerField() def __str__(self): return self.name
urls.py框架
from django.conf.urls import url from django.contrib import admin from rest_demoimport views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^authors/$', views.AuthorsView.as_view()), url(r'^authors/(\d+)/$', views.AuthorsDetailView.as_view()), ]
serializer.pydom
from rest_framework import serializers from rest_demo import models class AuthorModelSerializers(serializers.ModelSerializer): class Meta: model = models.Author fields = '__all__'
views.py工具
from rest_demo import serializer from rest_framework.views import APIView from rest_framework.response import Response from rest_demo import models class AuthorsView(APIView): def get(self,request): ''' 查詢全部做者 :param request: :return: ''' author_list = models.Author.objects.all() auts = serializer.AuthorModelSerializers(author_list,many=True)# 默認爲False return Response(auts.data) # .data 拿json對象 def post(self,request): ''' 添加做者 :param request: :return: ''' auts = serializer.AuthorModelSerializers(data=request.data) if auts.is_valid(): auts.save() return Response(auts.data) return Response(auts.errors) class AuthorsDetailView(APIView): def get(self,request,id): ''' 查詢單條做者 :param request: :param id: :return: ''' author = models.Author.objects.filter(pk=id).first() auts = serializer.AuthorModelSerializers(author) return Response(auts.data) def put(self,request,id): ''' 修改單條做者 :param request: :param id: :return: ''' author = models.Author.objects.filter(pk=id).first() auts = serializer.AuthorModelSerializers(instance=author,data=request.data) if auts.is_valid(): auts.save() return Response(auts.data) return Response(auts.errors) def delete(self,request,id): ''' 刪除單條做者 :param request: :param id: :return: ''' models.Author.objects.filter(pk=id).delete() return Response()
url中
urlpatterns = [ url(r'^books/$', views.BookViewSet.as_view(),name="book_list"), url(r'^books/(?P<pk>\d+)$', views.BookDetailViewSet.as_view(),name="book_detail"), url(r'^publishers/$', views.PublishViewSet.as_view(),name="publish_list"), url(r'^publishers/(?P<pk>\d+)$', views.PublishDetailViewSet.as_view(),name="publish_detail"), ]
view視圖中
class Books(View): def get(self,requset): pass #查看全部書籍 def post(self,request): pass #添加書籍 class BooksDetail(View): def get(self,request,id): pass #查看某一本書籍 def put(self,requset,id): pass #更新書籍 def delete(self,request,id): pass #刪除書籍
在父類的基礎上擴展,並執行父類方法
繼承後調用父類的方法: 擴展後子類繼續調用父類的方法: class LoginView(View): def dispatch(self,request,*arg,**kwargs): # 兩種方式均可以 print('擴展父類方法') ret = super(LoginView,self).dispatch(self,request,*arg,**kwargs) ret = super().dispatch(self,request,*arg,**kwargs) return ret
序列化的方式,下列三種
model.py中
rom django.db import models # Create your models here. class Book(models.Model): title=models.CharField(max_length=32) price=models.IntegerField() pub_date=models.DateField() publish=models.ForeignKey("Publish") authors=models.ManyToManyField("Author") def __str__(self): return self.title class Publish(models.Model): name=models.CharField(max_length=32) email=models.EmailField() def __str__(self): return self.name class Author(models.Model): name=models.CharField(max_length=32) age=models.IntegerField() def __str__(self): return self.name model
view部分
from rest_framework.views import APIView from rest_framework.response import Response from .models import * from django.shortcuts import HttpResponse from django.core import serializers from rest_framework import serializers class BookSerializers(serializers.Serializer): title=serializers.CharField(max_length=32) price=serializers.IntegerField() pub_date=serializers.DateField() # 一對多核多對多須要咱們本身構建 publish=serializers.CharField(source="publish.name") #authors=serializers.CharField(source="authors.all") authors=serializers.SerializerMethodField() def get_authors(self,obj): temp=[] for author in obj.authors.all(): temp.append(author.name) return temp class BookViewSet(APIView): def get(self,request,*args,**kwargs): book_list=Book.objects.all() # 序列化方式1: # from django.forms.models import model_to_dict # import json # data=[] # for obj in book_list: # data.append(model_to_dict(obj)) # print(data) # return HttpResponse("ok") # 序列化方式2: # data=serializers.serialize("json",book_list) # return HttpResponse(data) # 序列化方式3: bs=BookSerializers(book_list,many=True) return Response(bs.data)
上面能作的知識單純的將queryset序列化,那麼有沒有可以既可以序列化對象傳給前端,
又可以接受前端的數據而後更新到數據庫呢?
ModelSerializer
modelserializer和modelform很相似,用法也很類似.
class BookSerializers(serializers.ModelSerializer): class Meta: model=Book fields="__all__" depth=1
提交post請求
def post(self,request,*args,**kwargs): bs=BookSerializers(data=request.data,many=False) if bs.is_valid(): # print(bs.validated_data) bs.save() return Response(bs.data) else: return Response(bs.errors)
重寫save和create方法
class BookSerializers(serializers.ModelSerializer): class Meta: model=Book fields="__all__" # exclude = ['authors',] # depth=1 def create(self, validated_data): authors = validated_data.pop('authors') obj = Book.objects.create(**validated_data) obj.authors.add(*authors) return obj
單條數據的get和put請求
class BookDetailViewSet(APIView): def get(self,request,pk): book_obj=Book.objects.filter(pk=pk).first() bs=BookSerializers(book_obj) return Response(bs.data) def put(self,request,pk): book_obj=Book.objects.filter(pk=pk).first() bs=BookSerializers(book_obj,data=request.data) if bs.is_valid(): bs.save() return Response(bs.data) else: return Response(bs.errors)
咱們能夠看到中間CBV的類繼承了restframework的APIView,那麼裏面的繼承關係,和流程是怎麼樣的呢?
url(r'^books/$', views.BookView.as_view(),name="books")#views.BookView.as_view()至關於 View下的view,用戶訪問執行view
也就至關於books/一旦被訪問: view(request) 就執行APIView: dispatch()方法
在restframework的dispatch方法裏幹了什麼事?
從新構建request對象
self.request=Request(request)
self.request._request
Django原生的request:
如何在重構的request對象裏獲取數據?
request.GET # get request.data # POST PUT delete
超連接API:Hyperlinked
class BookSerializers(serializers.ModelSerializer): publish= serializers.HyperlinkedIdentityField( view_name='publish_detail', #要找的url的別名 name lookup_field="publish_id", 關聯的publish_id lookup_url_kwarg="pk") 對應URL中?P<pk> class Meta: model=Book fields="__all__" #depth=1
urls部分:
urlpatterns = [ url(r'^books/$', views.BookViewSet.as_view(),name="book_list"), url(r'^books/(?P<pk>\d+)$', views.BookDetailViewSet.as_view(),name="book_detail"), url(r'^publishers/$', views.PublishViewSet.as_view(),name="publish_list"), url(r'^publishers/(?P<pk>\d+)$', views.PublishDetailViewSet.as_view(),name="publish_detail"), ]