1. 程式人生 > >Django restframe 檢視函式以及ModelSerializer的使用

Django restframe 檢視函式以及ModelSerializer的使用

建立model資料庫

from django.db import models

__all__ = ['Book', 'Publisher', 'Author']


# Create your models here.
class Book(models.Model):
    title = models.CharField(max_length=32)
    CHOICES = ((1, 'python'), (2, 'linux'), (3, 'go'))
    category = models.IntegerField(choices=CHOICES, default=1, verbose_name='分類')
    pub_time = models.DateField(verbose_name='出版日期')
    publisher = models.ForeignKey(to='Publisher', verbose_name='出版社')
    authors = models.ManyToManyField(to='Author', verbose_name='作者')

    class Meta:
        db_table = 'book'
        verbose_name = '書籍表'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.title


class Publisher(models.Model):
    name = models.CharField(max_length=32, verbose_name='出版社')
    address = models.CharField(max_length=32, verbose_name='地址')

    class Meta:
        db_table = 'publisher'
        verbose_name = '出版社表表'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name


class Author(models.Model):
    name = models.CharField(max_length=32, verbose_name='作者')
    country = models.CharField(max_length=32, verbose_name='國家')

    class Meta:
        db_table = 'author'
        verbose_name = '作者表'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name

資料庫部分一共三張表,書籍表以及作則和出版社表

admin註冊

from django.contrib import admin
from SerDemo import models
# Register your models here.
for table in models.__all__:
    admin.site.register(getattr(models,table))

這裡用到了小技巧,利用匯入的models.__all__迴圈批量註冊model模型

序列器的實現

在專案下新建serializers,py檔案

from rest_framework import serializers
from SerDemo.models import Book, Author, Publisher

# 自定義檢驗函式在欄位引數validators中作為引數新增
def my_validate(value):
    if "敏感詞彙" in value.lower():
        raise serializers.ValidationError("輸入的資訊含有敏感詞彙")
    return value

### 建立django序列化器類,繼承serializers.ModelSerializer欄位可自動關聯
class BookSerializer(serializers.ModelSerializer):
    ## 需要重寫的欄位,SerializerMethodField 會去找get_欄位名的函式並執行獲取返回值作為欄位值
    category_read = serializers.SerializerMethodField(read_only=True,validators=[my_validate,])
    publisher_read = serializers.SerializerMethodField(read_only=True)
    authors_read = serializers.SerializerMethodField(read_only=True)

    # category_read的鉤子函式,返回要顯示的值,注意obj是每個要顯示到前端的資料物件
    def get_category_read(self,obj):
        return obj.get_category_display()

    # publisher_read的鉤子函式,返回要顯示的值
    def get_publisher_read(self,obj):
        return {'id':obj.publisher_id,'title':obj.publisher.name}

    def get_authors_read(self,obj):
        ret = [{'id':i.id,'name':i.name} for i in obj.authors.all()]
        return ret
    
    ## 全域性校驗鉤子函式
    def validate(self, attrs):
        # attrs 包含所有欄位的資料
        if 'se' in attrs['title']:
            #如果敏感詞彙在title欄位中則丟擲錯誤
            raise serializers.ValidationError('含有敏感詞彙')
        # 否則返回原資訊
        return attrs
        
    # 區域性校驗鉤子函式validate_+欄位名
    def validate_title(self, data):
        if 'se' in data:
            raise serializers.ValidationError('含有敏感詞彙')
        return data
    
    # 序列化器的元資訊
    class Meta:
        # 繫結的資料表model
        model=Book
        #要展示的表的欄位
        fields = '__all__'
        # depth = 1
        # depth 讓你所有的外來鍵關係變成read_only=True,不建議使用
        # 額外要新增的欄位的屬性引數
        extra_kwargs = {
            'category':{'write_only':True},
            'publisher': {'write_only': True},
            'authors':{'write_only':True},
        }

路由以及檢視函式部分

from django.conf.urls import url
from SerDemo.views import BooklistView,EditBookView
urlpatterns = [
    # 展示書籍資訊路由
    url(r'^booklist/',BooklistView.as_view()),
    #編輯書籍路由,接受id引數
    url(r'^editbook/(?P<id>\d+)/',EditBookView.as_view())
]

檢視部分

展示所有書籍資料和新增資料檢視,

class BooklistView(ListCreateModelMixin):
    #get 請求傳送所有資料給前端
    def get(self, request):
        # 獲取資料庫中所有資料物件
        query_set = Book.objects.all()
        # 將queryset物件傳給序列化器例項化,many=True告訴序列化器這是多個物件
        ser_obj = BookSerializer(query_set, many=True)
        # 所有要顯示的資料都在ser_obj.data中用restframe的Response返回
       return Response(ser_obj.data)

    # post請求為新增資料
    def post(self, request):
        # 序列化前端傳過來的資料(request.data)
        ser_obj = BookSerializer(data=request.data)
        # 校驗各欄位資料是否符合要求
        if ser_obj.is_valid():
            ser_obj.save()
            return Response(ser_obj.data)
        else:
            return Response(ser_obj.errors)
           

編輯資料和刪除書籍部分

class EditBookView(UpdateDestroyModelMixin):
    # 展示當前要編輯的資料物件
    def get(self, request, id):
    #根據url中的id引數獲取要編輯資料物件
        book_obj = Book.objects.filter(id=id).first()
        if book_obj:
            # 返回給前端頁面
            ser_obj = BookSerializer(book_obj)
            return Response(ser_obj.data)
        return Response('沒有')


    #put請求對應修改資料
    def put(self, request, id):
        #根據url中的id引數獲取要編輯資料物件
        book_obj = Book.objects.filter(id=id).first()
        if book_obj:
            #將前端提交的資料和要修改的物件傳給序列化器partial=True允許只修改部分欄位資料
            ser_obj = BookSerializer(data=request.data, instance=book_obj, partial=True)
            if ser_obj.is_valid():
                ser_obj.save()
                return Response(ser_obj.data)
            else:
                return Response(ser_obj.errors)
        
    def delete(self,request,id):
        book_obj = Book.objects.filter(id=id).first()
        if book_obj:
            book_obj.delete()
            return Response('')
        return Response('沒有次物件')

模仿djngo restframe原始碼封裝各個方法

from django.shortcuts import render, HttpResponse, redirect
from django.http import JsonResponse
import json
from SerDemo.models import Author, Publisher, Book
from django import views
from rest_framework import serializers
from rest_framework.views import APIView
from rest_framework.response import Response
from SerDemo.serializers import BookSerializer

# 把每個方法抽離出來

class GenericAPIView(APIView):
    query_set = None
    serializer_class = None
    def _get_queryset(self):
        return self.query_set
    def _get_serializer(self,*args,**kwargs):
        return self.serializer_class(*args,**kwargs)

class ListModelMixin:
   def list(self):
       query_set = self._get_queryset().all()

       ser_obj = self._get_serializer(query_set, many=True)
       return Response(ser_obj.data)

class CreateModelMixin:
    def create(self,request):
        ser_obj = self._get_serializer(data=request.data)
        if ser_obj.is_valid():
            ser_obj.save()
            return Response(ser_obj.data)
        else:
            return Response(ser_obj.errors)

class RetrieveModelMixin:
    def retrieve(self,id):
        book_obj = self._get_queryset().filter(id=id).first()
        if book_obj:
            ser_obj = self._get_serializer(book_obj)
            return Response(ser_obj.data)
        return Response('沒有')

class UpdateModelMixin:
    def update(self,request,id):
        book_obj = self._get_queryset().filter(id=id).first()
        if book_obj:
            ser_obj = self._get_serializer(data=request.data, instance=book_obj, partial=True)
            if ser_obj.is_valid():
                ser_obj.save()
                return Response(ser_obj.data)
            else:
                return Response(ser_obj.errors)

class DestroyModelMixin:
    def destroy(self,id):
        book_obj = self._get_queryset().filter(id=id).first()
        if book_obj:
            book_obj.delete()
            return Response('')
        return Response('沒有次物件')

class ListCreateModelMixin(GenericAPIView,ListModelMixin, CreateModelMixin):
    pass

class UpdateDestroyModelMixin(GenericAPIView,DestroyModelMixin,UpdateModelMixin,RetrieveModelMixin):
    pass

class BooklistView(ListCreateModelMixin):
    query_set = Book.objects.all()
    serializer_class = BookSerializer
    def get(self, request):
        # query_set = Book.objects.all()
        # ser_obj = BookSerializer(query_set, many=True)
        # return Response(ser_obj.data)
        return self.list()

    def post(self, request):
        # ser_obj = BookSerializer(data=request.data)
        # if ser_obj.is_valid():
        #     ser_obj.save()
        #     return Response(ser_obj.data)
        # else:
        #     return Response(ser_obj.errors)
        return self.create(request)


class EditBookView(UpdateDestroyModelMixin):
    query_set = Book.objects.all()
    serializer_class = BookSerializer
    def get(self, request, id):
        # book_obj = Book.objects.filter(id=id).first()
        # if book_obj:
        #     ser_obj = BookSerializer(book_obj)
        #     return Response(ser_obj.data)
        # return Response('沒有')
        return self.retrieve(id)


    def put(self, request, id):
        # book_obj = Book.objects.filter(id=id).first()
        # if book_obj:
        #     ser_obj = BookSerializer(data=request.data, instance=book_obj, partial=True)
        #     if ser_obj.is_valid():
        #         ser_obj.save()
        #         return Response(ser_obj.data)
        #     else:
        #         return Response(ser_obj.errors)
        return self.update(request,id)

    def delete(self,request,id):
        # book_obj = Book.objects.filter(id=id).first()
        # if book_obj:
        #     book_obj.delete()
        #     return Response('')
        # return Response('沒有次物件')
        return self.destroy(id)