1. 程式人生 > >DRF之序列化

DRF之序列化

獲取 values pat 沒有 date fir 2-0 choices ron

目錄

  • 準備事項
  • 序列化組件初見
  • 序列化字段
  • ModelSerializer
  • 重載create方法
  • 單條數據處理
  • 現階段代碼

準備事項

# models.py
from django.db import models


class Publisher(models.Model):
    title = models.CharField(max_length=32)
    address = models.CharField(max_length=128)

    def __str__(self):
        return self.title



class Author(models.Model):
    name = models.CharField(max_length=32)
    birth_date = models.DateField()
    gender = models.IntegerField(choices=((0,'male'),(1,'female')),default=0)
    email = models.EmailField(max_length=64)

    def __str__(self):
        return self.name


class Book(models.Model):
    title = models.CharField(max_length=32)
    authors = models.ManyToManyField(Author)
    publisher = models.ForeignKey(Publisher)
    pub_date = models.DateField()
    word_count = models.IntegerField()
    price = models.IntegerField(null=True,blank=True)

    def __str__(self):
        return self.title
# settings.py
INSTALLED_APPS = [
    'app01',
    'rest_framework',
]

序列化組件初見

利用HttpResponse返回json或者文本數據。

from rest_framework.views import APIView
from django.shortcuts import  HttpResponse
from .models import Publisher
import json
from .models import Publisher
from rest_framework import serializers


class PublisherSerializer(serializers.Serializer):
    title = serializers.CharField()
    address = serializers.CharField()


class PubliserView(APIView):
    """獲取所有出版社"""
    def get(self,request,*args,**kwargs):
        # 方式1:
        # publishers = Publisher.objects.all().values()  # query set對象不能直接被序列化
        # publishers = list(publishers)
        # return HttpResponse(json.dumps(publishers), content_type='application/json')


        # 方式2:
        from django.forms.models import model_to_dict
        # publishers = Publisher.objects.all()
        # temp = []
        # for obj in publishers:
        #     temp.append(model_to_dict(obj))

        # return HttpResponse(json.dumps(temp), content_type='application/json')


        # 方式3
        # from django.core import serializers  # django的方法,與rest無關
        # publishers = Publisher.objects.all()
        # ret = serializers.serialize('json',publishers)
        # return HttpResponse(ret)  # 內容更多

        
        # 方式4:
        publishers = Publisher.objects.all()
        ser = PublisherSerializer(instance=publishers,many=True)  # 若實例是對象集合,則必須增加many=True
        print(ser.data)
        # [OrderedDict([('title', '長江出版社'), ('address', '武漢市武昌區')]), OrderedDict([('title', '人民出版社')]
        return HttpResponse(ser.data)

序列化字段

類似django form。

# urls.py
from app01.views import PubliserView, BookView
url(r'^books/',BookView.as_view()),


# views.py
class BookView(APIView):
    def get(self, request, *args, **kwargs):
        book_list = Book.objects.all()
        from .my_serializer import BookSerializer
        ser = BookSerializer(instance=book_list, many=True)

        # 1、返回json格式的字符串,對於瀏覽器相應內容會渲染到drf模板中,若是postman發的請求直接返回原始的數據
        from rest_framework.response import Response
        return Response(ser.data)
        
        # 2、直接返回字符串
        # return HttpResponse(ser.data)



# my_serializer.py

from rest_framework import serializers

class BookSerializer(serializers.Serializer):
    title = serializers.CharField(max_length=32)
    pub_date = serializers.DateField()
    word_count = serializers.IntegerField()

    # 一對多使:用source屬性
    publisher = serializers.CharField(source='publisher.address')  # 可以指定關聯表的字段
    price = serializers.IntegerField()

    # 針對多對多字段
    # authors = serializers.CharField(source="authors.all")
    authors = serializers.SerializerMethodField()
    def get_authors(self,obj):
        # print(obj)
        authors = list(obj.authors.all().values_list('name'))  # [('蔣勛',), ('易中天',)]
        # authors = list(obj.authors.all().values('name'))  # [{'name': '蔣勛'}, {'name': '易中天'}]
        authors = [item[0] for item in authors if item]
        return authors


# 本質
'''
book_list = BookSerializer(book_list,many=True)
temp = []
for obj in book_list:
    temp.append({
        "title":str(obj.title),
        "price":obj.price,
        "pub_date":str(obj.pub_date),
        "word_count":obj.word_count,
        "publisher":str(obj.publisher),
        
        "authors":str(get_authors(obj)), # 多對多字段
    })
'''

ModelSerializer

類似與django的model-form。
作用:

  1. 將query_set轉換成json數據

    def get(self,request):
        publishers = Publisher.objects.all()
        ser = PublisherSerializer(instance=publishers,many=True)  # 若實例是對象集合,則必須增加many=True
        return Response(ser.data)
  2. 將 model對象 轉換成json數據

    def get(self, request, pid):
        p_obj = Publisher.objects.filter(pk=int(pid)).first()
        ps = PublisherSerializer(instance=p_obj)
        return Response(ps.data)

3、做數據校驗,將json數據>>>成queryset或者model對象>>>記錄:

```
def post(self, request):
    bs = BookSerializers(data=request.data)
    # 做校驗
    if bs.is_valid(): 
        # 轉換成model對象
        bs.save()  # 把數據保存到數據庫中(會有反序列化操作),.save()中有 create()方法
        return Response(bs.data)

    else:
        return HttpResponse(bs.errors)  # bs.errors 表示 錯誤信息
```

語法實例:

from .models import  *

class BookSerializer(serializers.ModelSerializer):
    """
    僅適用於展示字段
    """
    # 重載默認的字段
    publisher = serializers.CharField(source='publisher.address')  # 可以指定關聯表的字段
    price = serializers.IntegerField()

    # 針對多對多字段
    authors = serializers.SerializerMethodField()
    def get_authors(self,obj):
        # print(obj)
        authors = list(obj.authors.all().values_list('name'))  # [('蔣勛',), ('易中天',)]
        # authors = list(obj.authors.all().values('name'))  # [{'name': '蔣勛'}, {'name': '易中天'}]
        authors = [item[0] for item in authors if item]
        return authors

    class Meta:
        model = Book
        fields = '__all__'
        # 對於多余多對多和一對多默認使用pk,一般為id
        depth = 1
        '''
        # 增加前
        [{
            "id": 2,
            "title": "蔣勛說唐詩",
            "pub_date": "2012-02-07",
            "word_count": 12,
            "price": 34,
            "publisher": 1,
            "authors": [
                1
            ]
        },
        
        
        # 增加後
        [
        {
            "id": 2,
            "title": "蔣勛說唐詩",
            "pub_date": "2012-02-07",
            "word_count": 12,
            "price": 34,
            "publisher": {
                "id": 1,
                "title": "長江出版社",
                "address": "武漢市武昌區"
            },
             "authors": [
            {
                "id": 1,
                "name": "蔣勛",
                "birth_date": "1956-10-12",
                "gender": 0,
                "email": "[email protected]"
            }
        ]
        '''

重載create方法

增加對象記錄。

from .my_serializer import BookSerializers

class BookView(APIView):
    def post(self, request, *args, **kwargs):
        """保存提交的數據"""
        bs = BookSerializers(data=request.data)
        if bs.is_valid():  # 做校驗
            print('validated_data>>>>>>',bs.validated_data)  # 結果為OrderedDict對象
            '''
            OrderedDict([
            ('title', 'who am i'), ('pub_date', datetime.date(2012, 12, 12)), ('word_count', 12), ('price', 29), 
            ('publisher', <Publisher: 長江出版社>), ('authors', [<Author: 蔣勛>, <Author: 易中天>])
            ])
            '''
            bs.save()  # 把數據保存到數據庫中(會有反序列化操作) # .save()中有 create()方法
            print('data>>>>>>', bs.data)  # 結果為字典
            '''
            {'id': 21, 'title': 'who am i', 'pub_date': '2012-12-12', 'word_count': 12, 'price': 29, 'publisher': 1, 'authors': [1, 2]}
            '''
            return Response(bs.data)
        else:
            return HttpResponse(bs.errors)  # bs.errors 表示 錯誤信息
            


# 1、使用默認的字段,則無需定制
# 在postman中提交json格式的數據:{"title":"1212312!","pub_date":"2012-12-12","word_count":12,"price":29,"publisher":1,"authors":[1,2]}
class BookSerializers(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = "__all__"
        

# 2、定制字段後
class BookSerializers(serializers.ModelSerializer):
    publisher = serializers.CharField(source='publisher.pk')

    class Meta:
        model = Book
        fields = "__all__"
        # exclude = ['authors',]
        # depth=1

    # 處理多對多字段時需要重寫 save()中的 create()方法
    def create(self, validated_data):
        print('validated_data>>>>>>>',validated_data)
        '''
        {
            'title': '鋼鐵是怎樣煉成的',
            'pub_date': datetime.date(2012, 12, 12),
            'word_count': 12, 'price': 29,
            'publisher': <Publisher: 長江出版社>,
            'authors': [<Author: 蔣勛>, <Author: 易中天>]
        }
        '''
        book_obj = Book.objects.create(
            title=validated_data['title'],
            pub_date=validated_data['pub_date'],
            word_count=validated_data['word_count'],
            publisher_id=validated_data['publisher']['pk'],  # 註意此處字段名稱為publisher_id!!!
            price=validated_data['price'],
        )
        print('book_obj',book_obj)

        # authors = validated_data.pop('authors')
        # obj = Book.objects.create(**validated_data)
        book_obj.authors.add(*validated_data['authors'])
        return book_obj

單條數據處理

對特定對象的刪、改、查操作。

# urls
url(r'^books/(?P<id>\d+)/$',BookDetailView.as_view()),


# views.py
class BookDetailView(APIView):
    """對特定書籍的查看、修改和刪除操作"""
    def get(self, request, id):
        b_obj = Book.objects.filter(pk=int(id)).first()
        bs = BookSerializers(instance=b_obj)
        return Response(bs.data)

    def put(self, request, id):
        """沒有對應的對象則更新,有則修改"""
        b_obj = Book.objects.filter(pk=int(id)).first()
        bs = BookSerializers(instance=b_obj,data=request.data)
        if bs.is_valid():  # 數據需要填寫完整
            bs.save()
            return Response(bs.data)
        else:
            return HttpResponse(bs.errors)

    def delete(self, request,id):
        """刪除指定的對象"""
        b_obj = Book.objects.filter(pk=int(id)).first()
        b_obj.delete()
        return Response()  # 返回空

例:postman進行put操作
技術分享圖片


現階段代碼

urls

from django.conf.urls import url
from django.contrib import admin

from app01.views import PubliserView, BookView, BookDetailView,PubliserDetailView

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^publishers/$',PubliserView.as_view()),  # 新增/查詢所有
    url(r'^publishers/(?P<pid>\d+)/$',PubliserDetailView.as_view()),  # 編輯/新增/刪除
    url(r'^books/$',BookView.as_view()),  # 新增/查詢所有
    url(r'^books/(?P<id>\d+)/$',BookDetailView.as_view()),  # 編輯/新增/刪除
]

serializer

from rest_framework import serializers
from .models import  *


class PublisherSerializer(serializers.ModelSerializer):

    class Meta:
        model = Publisher
        fields = '__all__'
        # depth = 1


class BookSerializers(serializers.ModelSerializer):

    class Meta:
        model = Book
        fields = "__all__"
        # exclude = ['authors',]
        # depth=1

views

有部分重復代碼,有待優化!

from rest_framework.views import APIView
from django.shortcuts import  HttpResponse
from .models import Publisher,Book
from rest_framework.response import Response
from .my_serializer import PublisherSerializer
from .my_serializer import BookSerializers



class PubliserView(APIView):
    def get(self,request):
        """查詢並返回所有出版社"""
        publishers = Publisher.objects.all()
        ser = PublisherSerializer(instance=publishers,many=True)  # 若實例是對象集合,則必須增加many=True
        return Response(ser.data)

    def post(self,request):
        """新增出版社"""
        bs = PublisherSerializer(data=request.data)
        if bs.is_valid():
            bs.save()
            return Response(bs.data)
        else:
            return Response(bs.errors)


class BookView(APIView):
    def get(self, request):
        """查詢所有書籍"""
        book_list = Book.objects.all()
        ser = BookSerializers(instance=book_list, many=True)

        from rest_framework.response import Response
        return Response(ser.data)

    def post(self, request):
        """新增書籍記錄"""
        bs = BookSerializers(data=request.data)
        if bs.is_valid():  # 做校驗
            bs.save()  # 把數據保存到數據庫中(會有反序列化操作) # .save()中有 create()方法
            return Response(bs.data)

        else:
            return HttpResponse(bs.errors)  # bs.errors 表示 錯誤信息


class PubliserDetailView(APIView):
    """獲取所有出版社"""
    def get(self, request, pid):
        """查詢並返回某一個的出版社信息"""
        p_obj = Publisher.objects.filter(pk=int(pid)).first()
        ps = PublisherSerializer(instance=p_obj)
        print(ps)
        return Response(ps.data)

    def put(self, request, pid):
        """修改或新增一條出版社信息"""
        p_obj = Publisher.objects.filter(pk=int(pid)).first()
        ps = PublisherSerializer(instance=p_obj, data=request.data)
        print('ps>>>>',ps)
        if ps.is_valid():  # 數據需要填寫完整
            ps.save()
            return Response(ps.data)
        else:
            return HttpResponse(ps.errors)

    def delete(self, request,pid):
        """刪除某一條出版社記錄"""
        Publisher.objects.filter(pk=int(pid)).delete()
        return Response()  # 返回空


class BookDetailView(APIView):
    def get(self, request, id):
        """查詢並返回某一本書籍信息"""
        b_obj = Book.objects.filter(pk=int(id)).first()
        bs = BookSerializers(instance=b_obj)
        return Response(bs.data)

    def put(self, request, id):
        """修改或新增一條書籍信息"""
        b_obj = Book.objects.filter(pk=int(id)).first()
        bs = BookSerializers(instance=b_obj,data=request.data)
        if bs.is_valid():  # 數據需要填寫完整
            bs.save()
            return Response(bs.data)
        else:
            return HttpResponse(bs.errors)

    def delete(self, request,id):
        """刪除某一條書籍記錄"""
        b_obj = Book.objects.filter(pk=int(id)).first()
        b_obj.delete()
        return Response()  # 返回空

DRF之序列化