您好,登錄后才能下訂單哦!
restframework是基于restful協議開發的Django框架擴展
要理解RESTful架構,最好的方法就是去理解Representational State Transfer這個詞組到底是什么意思,翻譯是"表現層狀態轉化"。
資源(Resources)
一切皆是資源,所謂"資源",就是網絡上的一個實體,或者說是網絡上的一個具體信息,每種資源對應一個特定的URI。要獲取這個資源,訪問它的URI就可以。
表現層(Representation)
"資源"是一種信息實體,它可以有多種外在表現形式。我們把"資源"具體呈現出來的形式,叫做它的"表現層"(Representation)
狀態轉化(State Transfer)
訪問一個網站,就代表了客戶端和服務器的一個互動過程,客戶端用到的手段,只能是HTTP協議。具體來說,就是HTTP協議里面,四個表示操作方式的動詞:GET、POST、PUT、DELETE。它們分別對應四種基本操作:GET用來獲取資源,POST用來新建資源(也可以用于更新資源),PUT用來更新資源,DELETE用來刪除資源。
綜合上面的解釋,我們總結一下什么是RESTful架構:
每一個URI代表一種資源;
客戶端和服務器之間,傳遞這種資源的某種表現層;
客戶端通過四個HTTP動詞,對服務器端資源進行操作,實現"表現層狀態轉化"。
常用的HTTP動詞有下面五個(括號里是對應的SQL命令)
GET(SELECT):從服務器取出資源(一項或多項)。
POST(CREATE):在服務器新建一個資源。
PUT(UPDATE):在服務器更新資源(客戶端提供改變后的完整資源)。
PATCH(UPDATE):在服務器更新資源(客戶端提供改變的屬性)。
DELETE(DELETE):從服務器刪除資源。
下面是一些常見的參數
?limit=10:指定返回記錄的數量
?offset=10:指定返回記錄的開始位置。
?page=2&per_page=100:指定第幾頁,以及每頁的記錄數。
?sortby=name&order=asc:指定返回結果按照哪個屬性排序,以及排序順序。
?animal_type_id=1:指定篩選條件
針對不同操作,服務器向用戶返回的結果應該符合以下規范
GET /collection:返回資源對象的列表(數組)
GET /collection/resource:返回單個資源對象
POST /collection:返回新生成的資源對象
PUT /collection/resource:返回完整的資源對象
PATCH /collection/resource:返回完整的資源對象
DELETE /collection/resource:返回一個空文檔
舊來的方式,在url中有動詞
請求方式 | url | 對應視圖 | 備注 |
---|---|---|---|
GET | /books/ | books | 返回當前所有數據 |
POST | /books/add/ | addbook | 提交數據 |
POST | /books/(\d+)/change/ | changebook | 更新數據 |
GET | /books/(\d+)/delete/ | delbook | 刪除數據 |
新的方式
請求方式 | url | 對應視圖 | 備注 |
---|---|---|---|
GET | /books/ | books | 返回當前所有數據 |
POST | /books/ | books | 提交數據 |
GET | /books/(\d+) | bookdetail | 當前查看的單條數據 |
PUT | /books/(\d+) | bookdetail | 更新數據 |
DELTET | /books/(\d+) | bookdetail | 刪除數據 |
對應視圖
class Books(View):
def get(self,request):
pass # 查看所有書籍
def post(self,request):
pass # 添加書籍
class BooksDetail(View):
def get(self,request,id):
pass # 查看具體書籍
def put(self,request,id):
pass # 更新某本書籍
def delete(self,request,id):
pass # 刪除某本書籍
參考資料:https://www.cnblogs.com/yuanchenqi/articles/8719520.html
model_to_dict是Django ORM下的語句,可以把model對象轉換成一個字典
from django.forms.models import model_to_dict
from app01.models import Publish
obj = Publish.objects.filter(pk=1).first()
obj
<Publish: 蘋果出版社>
model_to_dict(obj)
{'id': 1, 'name': '蘋果出版社', 'email': '123@qq.com'}
#QuerySet無法直接序列化,需要轉換成list
publish_list = list(Publish.objects.all().values("name", "email"))
print(publish_list)
[{'name': '蘋果出版社', 'email': '123@qq.com'}, {'name': '橘子出版社', 'email': '345@qq.com'}]
publish_list = Publish.objects.filter(pk=1)
#這是Django原生的serializers
from django.core import serializers
#serialize(format, queryset, **options)
ret = serializers.serialize("json", publish_list)
print(ret)
[{"model": "app01.publish",
"pk": 1,
"fields": {
"name": "\u82f9\u679c\u51fa\u7248\u793e",
"email": "123@qq.com"
}
}
]
上面的三種方式都沒有用到restframework
這里利用restframework封裝出來的serializers,其用法與Django的Form組件很相似
可以序列化QuerySet和model對象
from rest_framework.views import APIView
from rest_framework import serializers
#創建一個序列化類
class PublishSerializers(serializers.Serializer):
name = serializers.CharField()
email = serializers.CharField()
class PublishView(APIView):
def get(self, request):
publish_list = Publish.objects.filter(pk=1)
ret = PublishSerializers(publish_list, many=True)
#可以序列化QuerySet和model對象,many=True代表轉換的是QuerySet,默認為False
print(ret.data)
#結果
#[OrderedDict([('name', '蘋果出版社'), ('email', '123@qq.com')])]
#得出一個OrderedDict對象,這個對象本質就是有序字典
return HttpResponse("ok")
def post(self, request):
pass
使用postman發送x-www-form-urlencoded數據后看一下request.body和request.POST都收到了什么
def post(self, request):
print("POST==>", request.POST)
print("body==>", request.body)
return HttpResponse("POST ok")
結果:
POST==> <QueryDict: {'a': ['1'], 'b': ['2']}> #處理過的數據
body==> b'a=1&b=2' #請求體中的數據,沒有處理過的原始數據
由上可知,request.POST拿到一個字典,其過程就是判斷contentType如果等于urlencoded,那么就將接收到的數據轉換為一個字典,如果是其它類型例如JSON那么request.POST就是個空字典
也就是說原生Django的request只支持form表單數據的解析
如果傳過來的是JSON數據,那么就只能從request.body中拿到字符串,然后再反序列化成字典
request.POST:
if contentType:urlencoded:
a=1&b=2----->{"a":1,"b":2}
APIViwe還是繼承原生Django的View,但自己構建了一個dispatch(restframework的關鍵點都在這里,可以看前面的博客了解CBV)
在這個dispatch中構建了一個新的request
class PublishView(APIView):
def post(self, request):
#新的request支持的操作
print("request.data==>", request.data)
print("request.data_type==>", type(request.data))
#前端發送JSON數據,接收到的是一個字典,說明接收的同時完成了反序列化
#request.data==> {'a': 1, 'b': 2}
#request.data_type==> <class 'dict'>
return HttpResponse("POST ok")
如果前端POST請求發送過來一個form表單,或者是GET請求,則會構建成QueryDict
總結一下:
request.data 接收到的是Body中的數據
GET請求可以用request.GET來取
開發我們的Web API的第一件事是為我們的Web API提供一種將代碼片段實例序列化和反序列化為諸如json之類的表示形式的方式。我們可以通過聲明與Django forms非常相似的序列化器(serializers)來實現。
models
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
views
from rest_framework.views import APIView
from .models import *
from rest_framework import serializers
from rest_framework.response import Response
#創建一個序列化類
class BookSerializers(serializers.Serializer):
title = serializers.CharField(max_length=32)
price = serializers.IntegerField()
pub_date = serializers.DateField()
#下面兩個是一對多和多對多的字段
#source="publish.name"可以理解為取obj.publish.name
publish = serializers.CharField(source="publish.name")
#SerializerMethodField為多對多服務,與get_authors配合(類似鉤子)使用
#可以理解為get_authors(obj),此時authors的返回值取決于get_authors的返回結果
authors = serializers.SerializerMethodField()
def get_authors(self, obj):
temp = []
for obj in obj.authors.all():
temp.append(obj.name)
return temp
class BookView(APIView):
def get(self, request):
book_list = Book.objects.all()
ret = BookSerializers(book_list, many=True)
#此處的Response來自rest_framework
return Response(ret.data)
序列化BookSerializers(book_list, many=True)的過程可以簡單理解為下面的例子:
temp = []
for obj in book_list:
temp.append({
"title":obj.title,
"price":obj.price,
"pub_date":obj.pub_date,
"publist":obj.publish.name
"authors":get_authors(obj)
})
在上面的例子中Response把結果從有序字典轉換為JSON格式了,其結果為:
[
{
"title": "三體",
"price": 18,
"pub_date": null,
"publish": "蘋果出版社",
"authors": [
"alex",
"egon"
]
},
{
"title": "go",
"price": 58,
"pub_date": null,
"publish": "橘子出版社",
"authors": [
"egon"
]
}
]
GET請求
類似于ModleForm,將Modle直接序列化
class BookModelSerializers(serializers.ModelSerializer):
class Meta:
model = Book
fields = "__all__"
#fields = ["id", "title", "pub_time"]
#exclude = ["user"]
#分別是所有字段 包含某些字段 排除某些字段
#depth = 1
#depth 代表找嵌套關系的第幾層
#注意:當序列化類MATE中定義了depth時,這個序列化類中引用字段(外鍵)則自動變為只讀
#自定義字段
#下面兩個一對多和多對多的字段
#source="publish.name"可以理解為取obj.publish.name
publish = serializers.CharField(source="publish.name")
#SerializerMethodField為多對多服務
#與get_authors配合(類似鉤子),可以理解為get_authors(obj),此時authors的返回值取決于get_authors的返回結果
authors = serializers.SerializerMethodField()
def get_authors(self, obj):
temp = []
for obj in obj.authors.all():
temp.append(obj.name)
return temp
結果:
[
{
"id": 1,
"publish": "蘋果出版社",
"authors": [
"alex",
"egon"
],
"title": "三體",
"price": 18,
"pub_date": null
},
{
"id": 2,
"publish": "橘子出版社",
"authors": [
"egon"
],
"title": "go",
"price": 58,
"pub_date": null
}
]
class BookModelSerializers(serializers.ModelSerializer):
class Meta:
model = Book
fields = "__all__"
class BookView(APIView):
def post(self, request):
#request.data中是post請求的數據
bs = BookModelSerializers(data=request.data, many=False)
if bs.is_valid():
#打印正確數據
print(bs.validated_data)
bs.save() #create方法
#返回當前添加的內容
return Response(bs.data)
else:
print(bs.errors)
#返回錯誤項目信息
return Response(bs.errors)
在Postman中提交JSON數據
{"title": "Python", "price":100, "pub_date": "2012-12-12", "publish":1, "authors":[1,2]}
Serializer提供了.is_valid()和.save()方法
如果是post請求那么.save()就是調用create方法,如果是put請求,那么.save()就是調用update方法
上面我們自定義了publish的返回數據,因此我們要自己寫一個create方法
#向http://127.0.0.1:8000/books/發送post請求
{
"title": "go第三版",
"price": 70,
"pub_date": "2017-10-01",
"publish": 1,
"authors": [
1,
2
]
}
views.py
class BookModelSerializers(serializers.ModelSerializer):
class Meta:
model = Book
fields = "__all__"
publish = serializers.CharField(source="publish.name")
#validated_data是所有接受到的數據,此時已經反序列化為字典
def create(self, validated_data):
#print("validated_data==>", validated_data)
#查看發現{'publish': {'name': '1'},這個name就是上面自定義返回內容是改變的key值
#{'publish': {'name': '1'}, 'title': 'go第三版', 'price': 70, 'pub_date': datetime.date(2017, 10, 1), 'authors': [<Author: alex>, <Author: egon>]}
obj = Book.objects.create(title=validated_data["title"],
price=validated_data["price"],
pub_date=validated_data["pub_date"],
publish_id=validated_data["publish"]["name"])
obj.authors.add(*validated_data["authors"])
return obj
class BookView(APIView):
def post(self, request):
#request.data中是post請求的數據
bs = BookModelSerializers(data=request.data)
if bs.is_valid():
bs.save() #create方法
#返回當前添加的內容
return Response(bs.data)
else:
#返回錯誤項目信息
return Response(bs.errors)
class BookDetailView(APIView):
def get(self, request, id):
book = Book.objects.filter(pk=id).first()
bs = BookModelSerializers(book, context={'request': request})
return Response(bs.data)
def put(self, request, id):
book = Book.objects.filter(pk=id).first()
bs = BookModelSerializers(book, data=request.data)
if bs.is_valid():
bs.save()
return Response(bs.data)
else:
return Response(bs.errors)
class BookModelSerializers(serializers.ModelSerializer):
class Meta:
model = Book
fields = "__all__"
publish = serializers.HyperlinkedIdentityField(
view_name="detail_publish", #url中反向解析的別名
lookup_field="publish_id", #對應的字段名稱
lookup_url_kwarg="pk", #url中有名分組的名稱
)
urls部分:
使用有名分組和反向解析
from app01 import views
urlpatterns = [
......
url(r'^publish/(?P<pk>\d+)/$', views.PublishDetailView.as_view(), name="detail_publish"),
]
views部分:
注意有名分組中的別名要與視圖中的名稱對應
class PublishDetailView(APIView):
def get(self, request, pk): #這個pk與url中的有名分組pk對應
publish = Publish.objects.filter(pk=pk).first()
bs = PublishModelSerializers(publish)
return Response(bs.data)
class BookDetailView(APIView):
def get(self, request, id):
book = Book.objects.filter(pk=id).first()
#注意添加context={'request': request}
bs = BookModelSerializers(book, context={'request': request})
return Response(bs.data)
訪問
向http://127.0.0.1:8000/books/1發送GET請求
返回結果:
{
"id": 1,
"publish": "http://127.0.0.1:8000/publish/1/",
"title": "三體",
"price": 18,
"pub_date": null,
"authors": [
1,
2
]
}
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。