day 90 DjangoRestFramework學習二之序列化組件

 

DjangoRestFramework學習二之序列化組件

 

 

本節目錄html

一 序列化組件

  首先按照restful規範我們建立一些api接口,按照下面這些形式寫吧:前端

    Courses --- GET ---> 查看數據----->返回全部數據列表[{},{},]java

    Courses--- POST --->添加數據 -----> 返回添加的數據{ }python

    courses/1 ---PUT---> 更新pk=1的數據 ----->返回更新後的數據{ }linux

    courses/1 --- DELETE---> 刪除pk=1的數據 -----> 返回空git

    courses/1 --- GET --->查看單條數據 -----> 返回單條數據 { }django

  這樣,咱們先看一個drf給咱們提供的一個相似於Postman功能的頁面,首先咱們建立一個django項目,建立一個Course表,而後添加一些數據,而後按照下面的步驟操做,json

    第一步:引入drf的Response對象  api

複製代碼
from django.shortcuts import render,HttpResponse,redirect
import json
from django.views import View
from app01 import models
from rest_framework.views import APIView

#引用drf提供的Response對象
from rest_framework.response import Response

#寫咱們的CBV視圖 class CourseView(APIView):   #返回全部的Course數據 def get(self,request): course_obj_list = models.Course.objects.all() ret = [] for course_obj in course_obj_list: ret.append({ "title":course_obj.title, "desc":course_obj.desc, }) # return HttpResponse(json.dumps(ret, ensure_ascii=False)) return Response(json.dumps(ret, ensure_ascii=False)) #這裏使用Response來返回消息 def post(self,request): print(request.data) return HttpResponse('POST')
複製代碼

    第二步:配置App,在咱們的settings配置文件中配置瀏覽器

複製代碼
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01.apps.App01Config',
    'rest_framework',  #將它註冊成App
]
複製代碼

    第三步,配置咱們的路由

複製代碼
"""
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^courses/', views.CourseView.as_view(),name='courses'),
]
複製代碼

    第四步:啓動項目,經過瀏覽器訪問咱們的路由(必須是瀏覽器訪問才能看到對應的功能),看效果:

      

    這裏面咱們能夠發送不一樣類型的請求,看到對應的返回數據,相似於Postman,可是沒有Postman好用,因此之後調試咱們仍是用Postman工具,可是咱們知道一下昂。

  上面的數據,咱們經過json本身進行的序列化,其實django也給咱們提供了一個簡單的序列化組件,看用法:

複製代碼
from django.shortcuts import render,HttpResponse,redirect
import json
from django.views import View
from app01 import models
from rest_framework.views import APIView
from django.core.serializers import serialize  #django的序列化組件,不是咱們要學的drf的序列化組件昂

#不用json本身來序列化了,太麻煩,咱們使用drf提供的序列化組件
from rest_framework.response import Response

class CourseView(APIView):

    def get(self,request):
        course_obj_list = models.Course.objects.all()
        # ret = []
        # for course_obj in course_obj_list:
        #     ret.append({
        #         "title":course_obj.title,
        #         "desc":course_obj.desc,
        #     })
        # return HttpResponse(json.dumps(ret, ensure_ascii=False))
        # return Response(json.dumps(ret, ensure_ascii=False)
        se_data = serialize('json',course_obj_list,ensure_ascii=False)
        print(se_data)#也拿到了序列化以後的數據,簡潔不少
        #[{"model": "app01.course", "pk": 1, "fields": {"title": "python", "desc": "666"}}, {"model": "app01.course", "pk": 2, "fields": {"title": "linux", "desc": "\u4e5f\u5f88\u597d"}}, {"model": "app01.course", "pk": 3, "fields": {"title": "go", "desc": "\u5c06\u6765\u53ef\u80fd\u5f88\u597d"}}]

        return Response(se_data)
複製代碼

  那麼咱們知道了兩個序列化方式了,這個序列化是否是就簡單不少啊,可是drf給咱們作了一個更牛逼的序列化組件,功能更強大,並且不只僅能作序列化,還能作其餘的事情,因此呢,作api的時候,咱們仍是用drf提供的序列化組件。

複製代碼
import json
from datetime import datetime
from datetime import date

#對含有日期格式數據的json數據進行轉換
class JsonCustomEncoder(json.JSONEncoder):
    def default(self, field):
        if isinstance(field,datetime):
            return field.strftime('%Y-%m-%d %H:%M:%S')
        elif isinstance(field,date):
            return field.strftime('%Y-%m-%d')
        else:
            return json.JSONEncoder.default(self,field)


d1 = datetime.now()

dd = json.dumps(d1,cls=JsonCustomEncoder)
print(dd)
複製代碼

 

  接下來重點到了,咱們玩一下drf提供的數據序列化組件:

  1.咱們經過GET方法,來查看全部的Course數據。

複製代碼
from django.shortcuts import render,HttpResponse,redirect
import json
from django.views import View
from app01 import models
from rest_framework.views import APIView
from django.core.serializers import serialize  #django的序列化組件,不是咱們要學的drf的序列化組件昂

from rest_framework.response import Response

# 序列化方式3,1.引入drf序列化組件
from rest_framework import serializers

# 2.首先實例化一個類,繼承drf的serializers.Serializer,相似於咱們的form組件和models的用法
class CourseSerializers(serializers.Serializer):
    #這裏面也要寫對應的字段,你寫了哪些字段,就會對哪些字段的數據進行序列化,沒有被序列化的字段,不會有返回數據,你能夠註釋掉一個,而後看返回的數據是啥
    title = serializers.CharField(max_length=32) #序列化的時候還能校驗字段
    desc = serializers.CharField(max_length=32)

class CourseView(APIView):

    def get(self,request):
        course_obj_list = models.Course.objects.all()
        # 3.使用咱們建立的序列化類
        cs = CourseSerializers(course_obj_list, many=True)  # 序列化多個對象的時候,須要些many=True參數
        #4.經過返回對象的data屬性就能拿到序列化以後的數據
        se_data = cs.data
        print(se_data) #[OrderedDict([('title', 'python'), ('desc', '666')]), OrderedDict([('title', 'linux'), ('desc', '也很好')]), OrderedDict([('title', 'go'), ('desc', '未來可能很好')])] 列表嵌套的有序字典。

        #還記得建立字典的另一種寫法嗎?這個沒啥用昂,給你們回顧一下以前的知識
        # d1 = {'name':'chao'}
        # d2 = dict([('name','chao'),('age',18)])
        # print(d1) #{'name': 'chao'}
        # print(d2) #{'age': 18, 'name': 'chao'}
        # # 有序字典
        # from collections import OrderedDict
        # d3 = OrderedDict([('name','Jaden'),('age',22)])
        # print(d3) #OrderedDict([('name', 'Jaden'), ('age', 22)])

        return Response(se_data) #drf的Response若是返回的是drf序列化以後的數據,那麼客戶端拿到的是一個有格式的數據,再也不是一行顯示了
複製代碼

   看效果:

    

  2.經過POST方法來添加一條數據:

複製代碼
from django.shortcuts import render,HttpResponse,redirect
from django.views import View
from app01 import models
from rest_framework.views import APIView

from rest_framework.response import Response

from rest_framework import serializers

class CourseSerializers(serializers.Serializer):
    title = serializers.CharField(max_length=32)
    desc = serializers.CharField(max_length=32)

class CourseView(APIView):

    def get(self,request):
        course_obj_list = models.Course.objects.all()
        cs = CourseSerializers(course_obj_list, many=True)
        se_data = cs.data
        return Response(se_data)

    def post(self,request):
        # print(request.data) #{'desc': 'java也挺好', 'title': 'java'}
        #發送過來的數據是否是要進行驗證啊,drf的序列化組件還能校驗數據
        cs = CourseSerializers(data=request.data,many=False) #注意必須是data=這種關鍵字參數,注意,驗證單條數據的時候寫上many=False參數,並且咱們還要序列化這個數據,由於咱們要給客戶端返回這個數據
        # print(cs.is_valid()) #True ,若是少數據,獲得的是False
        if cs.is_valid():
            print(cs.data)
            models.Course.objects.create(**cs.data)#添加數據
            return Response(cs.data) #按照post添加數據的api規則,我們要返回正確的數據
        else:
            # 假如客戶端發送過來的數據是這樣的,少title的數據
            # {
            #     "desc": "java也挺好"
            # }
            cs_errors = cs.errors
            # print(cs_errors) #{'title': ['This field is required.']}
            return Response(cs_errors)
            # postman上咱們看到的效果是下面這樣的
            # {
            #     "title": [
            #         "This field is required."
            #     ]
            # }
複製代碼

  而後添加一些數據,好,接下來咱們玩一些有關聯關係的表

複製代碼
class Author(models.Model): 
    nid = models.AutoField(primary_key=True)
    name=models.CharField( max_length=32)
    age=models.IntegerField()

class AuthorDetail(models.Model):

    nid = models.AutoField(primary_key=True)
    birthday=models.DateField()
    telephone=models.BigIntegerField()
    addr=models.CharField( max_length=64)

class Publish(models.Model):
    nid = models.AutoField(primary_key=True)
    name=models.CharField( max_length=32)
    city=models.CharField( max_length=32)
    email=models.EmailField()

class Book(models.Model):

    nid = models.AutoField(primary_key=True)
    title = models.CharField( max_length=32)
    publishDate=models.DateField()
    price=models.DecimalField(max_digits=5,decimal_places=2)
    publish=models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE) #多對一到Publish表
    authors=models.ManyToManyField(to='Author',) #多對多到Author表
複製代碼

  看序列化代碼: 

複製代碼
from django.shortcuts import render,HttpResponse,redirect
from django.views import View
from app01 import models

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers


class BookSerializers(serializers.Serializer):
    #咱們先序列化寫兩個字段的數據,別忘了這裏面的字段和model表中的字段變量名要同樣
    title = serializers.CharField(max_length=32)
    price = serializers.DecimalField(max_digits=5, decimal_places=2)

    #一對多的處理
    # publish = serializers.CharField(max_length=32)  #返回對象
    publish_email = serializers.CharField(max_length=32, source='publish.email')  # source指定返回的多對一的那個publish對象的email數據,而且咱們如今找到書籍的email,因此前面的字段名稱就能夠不和你的publish對應好了,隨便取名字
    publish_name = serializers.CharField(max_length=32, source='publish.email')  # source指定返回的多對一的那個publish對象的其餘字段數據,能夠接着寫字段,也就是說關聯的全部的字段的數據均可以寫在這裏進行序列化

    #對多對的處理
    # authors = serializers.CharField(max_length=32) #bookobj.authors拿到的相似於一個models.Authors.object,打印的時候這是個None
    # authors = serializers.CharField(max_length=32,source="authors.all") #這樣寫返回的是queryset類型的數據,這樣給前端確定是不行的,因此按照下面的方法寫
    authors = serializers.SerializerMethodField() #序列化方法字段,專門給多對多字段用的,而後下面定義一個方法,方法名稱寫法是這樣的get_字段名,名字必須是這樣
    def get_authors(self,obj): #參數寫一個obj,這個obj是一個一個的書籍對象,而後咱們經過書籍對象來返回對應的數據
        # author_list_values = obj.authors.all().values() #返回這樣類型的數據也行,那麼具體你要返回什麼結構的數據,須要和前端人員溝通清楚,而後這裏對數據進行加工
        #假如加工成的數據是這種類型的[ {},{} ],就能夠按照下面的邏輯來寫,我簡單寫的,確定有更好的邏輯來加工這些數據
        author_list_values = []
        author_dict = {}
        author_list = obj.authors.all()
        for i in author_list:
            author_dict['name'] = i.name
            author_list_values.append(author_dict)
        return author_list_values


class BookView(APIView):
    def get(self,request):
        book_obj_list = models.Book.objects.all()
        s_books = BookSerializers(book_obj_list,many=True)
        return Response(s_books.data)

    def post(self,request):
        pass
複製代碼

  其實serializer在內部就作了這點事兒,僞代碼昂。

    

  urls.py是這樣寫的:

urlpatterns = [
    #url(r'^admin/', admin.site.urls),
    #作一些針對書籍表的接口
    url(r'^books/', views.BookView.as_view(),),

]

   而後看Postman返回的數據:

    

  那麼咱們就可以完成各類數據的序列化了,可是你會發現,這樣寫太累啦,這只是一張表啊,要是上百張表咋整啊,因此還有一個更簡單的方式(相似於form和modelform的區別)。

  咱們使用ModelSerializer,看代碼:

複製代碼
#ModelSerializer
class BookSerializers(serializers.ModelSerializer):
    class Meta:
        model=models.Book
        # fields=['title','price','publish','authors']
        fields = "__all__"
        # 若是直接寫all,你拿到的數據是下面這樣的,可是若是人家前端和你要的做者的id和名字,你是否是要處理一下啦
        # [
        #     {
        #         "nid": 3,
        #         "title": "go",
        #         "publishDate": null,
        #         "price": "122.00",
        #         "publish": 2,
        #         "authors": [
        #             2,
        #             1
        #         ]
        #     }
        # ]
    #那麼沒辦法,只能本身再進行加工處理了,按照以前的方式
    authors = serializers.SerializerMethodField()
    def get_authors(self,obj):
        author_list_values = []
        author_dict = {}
        author_list = obj.authors.all()
        for i in author_list:
            author_dict['id'] = i.pk
            author_dict['name'] = i.name
            author_list_values.append(author_dict)
        return author_list_values #這個數據就會覆蓋上面的序列化的authors字段的數據
    # 那麼前端拿到的數據就這樣了
    # [
    #     {
    #         "nid": 3,
    #         "authors": [
    #             {
    #                 "name": "chao",
    #                 "id": 1
    #             },
    #             {
    #                 "name": "chao",
    #                 "id": 1
    #             }
    #         ],
    #         "title": "go",
    #         "publishDate": null,
    #         "price": "122.00",
    #         "publish": 2
    #     }
    # ]
    # 那若是一對多關係的那個publish,前端想要的數據是名字怎麼辦呢?仍是老辦法,source
    # publish_name = serializers.CharField(max_length=32, source='publish.name')#可是你會發現序列化以後的數據有個publish:1對應個id值,若是我不想要他怎麼辦,那麼能夠起個相同的變量名來覆蓋它,好比下面的寫法
    publish = serializers.CharField(max_length=32, source='publish.name')

class BookView(APIView):
    def get(self,request):
        book_obj_list = models.Book.objects.all()
        s_books = BookSerializers(book_obj_list,many=True)
        return Response(s_books.data)

    def post(self,request):
        pass
複製代碼

  上面咱們完成了get請求來查看全部的書籍信息,接下來咱們玩一個post請求添加一條book數據,直接上代碼吧:

複製代碼
class BookSerializers(serializers.ModelSerializer):
    class Meta:
        model=models.Book
        fields = "__all__"
   # 注意先把下面這些註釋掉
    # authors = serializers.SerializerMethodField()
    # def get_authors(self,obj):
    #     author_list_values = []
    #     author_dict = {}
    #     author_list = obj.authors.all()
    #     for i in author_list:
    #         author_dict['id'] = i.pk
    #         author_dict['name'] = i.name
    #         author_list_values.append(author_dict)
    #     return author_list_values
    # publish = serializers.CharField(max_length=32, source='publish.name')

class BookView(APIView):
    def get(self,request):
        book_obj_list = models.Book.objects.all()
        s_books = BookSerializers(book_obj_list,many=True)
        return Response(s_books.data)


    def post(self,request):

        b_serializer = BookSerializers(data=request.data,many=False)
        if b_serializer.is_valid():
            print('xxxx')
            b_serializer.save() #由於這個序列化器咱們用的ModelSerializer,而且在BookSerializers類中咱們指定了序列化的哪一個表,因此直接save,它就知道咱們要將數據保存到哪張表中,其實這句話執行的就是個create操做。
            return Response(b_serializer.data) #b_serializer.data這就是個字典數據

        else:
            return Response(b_serializer.errors)
複製代碼

  上面咱們完成了GET和POST請求的接口寫法,下面咱們來完成PUT、DELETE、GET查看單條數據的幾個接口。

  urls.py內容以下:

複製代碼
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    # url(r'^courses/', views.CourseView.as_view()),
    #作一些針對書籍表的接口
    #GET和POST接口的url
    url(r'^books/$', views.BookView.as_view(),), #別忘了$符號結尾

    #PUT、DELETE、GET請求接口
    url(r'^books/(\d+)/', views.SBookView.as_view(),),

]
複製代碼

  views.py代碼以下:

複製代碼
from django.shortcuts import render,HttpResponse,redirect
from django.views import View
from app01 import models

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers

class BookSerializers(serializers.ModelSerializer):
    class Meta:
        model=models.Book
        fields = "__all__"

class BookView(APIView):
    def get(self,request):
        '''
        查看全部書籍
        :param request:
        :return:
        '''
        book_obj_list = models.Book.objects.all()
        s_books = BookSerializers(book_obj_list,many=True)
        return Response(s_books.data)

    def post(self,request):
        '''
        添加一條數據
        :param request:
        :return:
        '''
        b_serializer = BookSerializers(data=request.data,many=False)
        if b_serializer.is_valid():
            b_serializer.save()
            return Response(b_serializer.data)
        else:
            return Response(b_serializer.errors)

#由於更新一條數據,刪除一條數據,獲取一條數據,都有個單獨的參數(獲取一條數據的,通常是id,因此我將put、delete、get寫到了一個視圖類裏面,也就是說結合上面那個BookView視圖類,完成了咱們的那些接口)
class SBookView(APIView):
    def get(self,request,id):
        '''
        獲取單條數據
        :param request:
        :param id:
        :return:
        '''
        book_obj = models.Book.objects.get(pk=id)#獲取這條數據對象
        #接下來序列化單個model對象,序列化單個對象返回的是一個字典結構 {},序列化多個對象返回的是[{},{}]這種結構
        book_serializer = BookSerializers(book_obj,many=False)
        return Response(book_serializer.data)


    def put(self,request,id):
        '''
        更新一條數據
        :param request:request.data更新提交過來的數據
        :param id:
        :return:
        '''
        book_obj = models.Book.objects.get(pk=id)
        b_s = BookSerializers(data=request.data,instance=book_obj,many=False) #別忘了寫instance,因爲咱們使用的ModelSerializer,因此前端提交過來的數據必須是全部字段的數據,固然id字段不用
        if b_s.is_valid():
            b_s.save() #翻譯成的就是update操做
            return Response(b_s.data) #接口規範要求我們要返回更新後的數據
        else:
            return Response(b_s.errors)

    def delete(self,request,id):
        '''
        刪除一條數據
        :param request:
        :param id:
        :return:
        '''
        book_obj = models.Book.objects.get(pk=id).delete()
        return Response("") #別忘了接口規範說最好返回一個空
複製代碼

 

  好,五個接口寫完,我們的序列化組件就算是講完了。

 

 

 

二 xxx

  

 

 

 

三 xxx

 

 

 

 

 

四 xxx

 

 

 

 

 

五 xxx

 

 

 

 

 

 

六 xxx

 

 

 

 

七 xxx

 

 

 

 

八 xxx

相關文章
相關標籤/搜索