序列化多表操作、請求與響應、視圖組件(子類與拓展類)、繼承GenericAPIView類重寫介面

  • 2022 年 3 月 31 日
  • 筆記

今日內容概要

  • 序列化多表操作
  • 請求與相應
  • 視圖組件

內容詳細

1、序列化多表操作

模型類 models.py中

# 新建django項目
# 創建表 模型類models.py中:
from django.db import models

# 4張表
class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)  # to='Publish' 自動關聯publish表主鍵 // on_delete=models.CASCADE 級聯刪除
    authors = models.ManyToManyField(to='Author')

    def __str__(self):
        return self.name

    @property
    def publish_detail(self):  # 訂製欄位
        return {'name': self.publish.name, 'addr': self.publish.city}

    @property
    def author_list(self):  # 訂製欄位
        l = []
        # print(self.authors.all())
        for author in self.authors.all():
            # print(author.author_detail)
            l.append({'name': author.name, 'age': author.age, 'addr': author.author_detail.addr})
        return l
    
    
class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    author_detail = models.OneToOneField(to='AuthorDatail', on_delete=models.CASCADE)
    # OneToOneField 就是 ForeignKey + unique=True


class AuthorDatail(models.Model):
    telephone = models.BigIntegerField()
    addr = models.CharField(max_length=64)


class Publish(models.Model):
    name = models.CharField(max_length=32)
    city = models.CharField(max_length=32)
    email = models.EmailField()
    
    
"""
在每個表中寫入數據一一對應
第五個自動創建的關聯表 也寫入數據
"""

image

創建序列化類 serializer.py

from .models import *
from rest_framework import serializers


class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        # fields = '__all__'
        fields = ['id', 'name', 'price', 'authors', 'publish', 'publish_detail', 'author_list']

        # 由於前端的publish與authors會顯示為:id 所以需要訂製序列化欄位
        # depth=1  # 等同於訂製序列化的欄位(2種方案) 但是盡量不要用,因為它是關聯表一層全部取出來
        # 訂製序列化的欄位(2種方案)選擇表模型中: 顯示出版社名、地址;作者名年齡地址
        extra_kwargs = {
            'publish': {'write_only': True},  # 原有的欄位就不需要再顯示
            'authors': {'write_only': True},
        }


class AuthorSerializer(serializers.ModelSerializer):
    class Meta:
        model = Author
        fields = '__all__'


class AuthorDetailSerialzier(serializers.ModelSerializer):
    class Meta:
        model = AuthorDatail
        fields = '__all__'


class PublishSerialzier(serializers.ModelSerializer):
    class Meta:
        model = Publish
        fields = '__all__'

視圖類 views.py中:

from .serializer import *
from rest_framework.response import Response
from rest_framework.views import APIView
from app01.models import Book


class BookView(APIView):
    # 查詢所有圖書
    def get(self, request):
        book_list = Book.objects.all()
        ser = BookSerializer(instance=book_list, many=True)
        return Response(ser.data)

    # 新增圖書數據
    def post(self, request):
        ser = BookSerializer(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({"code": 100, 'msg': '新增成功', 'data': ser.data})
        return Response({"code": 101, 'msg': '新增失敗', 'err': ser.errors})


class BookDetailView(APIView):

    # 查詢單條數據
    def get(self, request, pk):
        book = Book.objects.all().filter(pk=pk).first()
        ser = BookSerializer(instance=book)
        return Response(ser.data)

    # 修改數據
    def put(self, request, pk):
        book = Book.objects.all().filter(pk=pk).first()
        ser = BookSerializer(instance=book, data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({"code": 100, 'msg': '修改成功', 'data': ser.data})
        return Response({"code": 101, 'msg': '修改出錯', 'err': ser.errors})

    # 刪除數據
    def delete(self, request, pk):
        Book.objects.filter(pk=pk).delete()
        return Response({"code": 100, 'msg': '刪除成功'})

路由 urls.py中:

from django.contrib import admin
from django.urls import path

from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),

    path('books/', views.BookView.as_view()),
    path('books/<int:pk>', views.BookView.as_view()),
]

image

2、請求與相應

2.1 請求

# 請求就是指:Request 類的對象
	>>> 新的request對象
    
# 導入:
	from rest_framework.request import Request

# 需要記住的源碼:
	__getattr__
	request.data
	request.query_parmas--->self._request.GET
		restful規範里,請求地址中帶過濾(查詢)條件
		get請求地址中提交的數據在GET中,
		query_parmas:查詢參數
        
        
# 了解
	默認情況下,可以解析 urlencoded,formdata,json
    
    
# 案例:
	如果我們寫了一個介面,想只能處理json格式,或者只能處理formdata
    
1.局部配置 在views.py中:
from rest_framework.parsers import JSONParser, FormParser, MultiPartParser

class PublishView(APIView):
    # 局部使用,只針對當前視圖類有效
    # 只想處理json格式
    # parser_classes = [JSONParser,FormParser,MultiPartParser]  # 默認下 是處理三種格式數據
    parser_classes = [JSONParser]  # 只允許處理 JSONParser格式

    def post(self, request):
        print(request.data)
        return Response('post---publish')
	
  
2.全局配置-->要在配置文件中添加:
# REST_FRAMEWORK  以後是drf的配置
# 所有介面都只能解析json格式
REST_FRAMEWORK = {
    'DEFAULT_PARSER_CLASSES': [
        'rest_framework.parsers.JSONParser',
    ],
}

3.全局配置解析json,局部某個視圖函數想能解析formdata格式
	視圖類中配置一下即可 就是局部配置(按照使用順序)
    
    
# 如果局部配置如下,會怎麼樣
	parser_classes = []  # 所有格式都補不能解析了

# 使用順序:
	即使我們沒有配置局部或者全局,也有默認配置:3個數據模式都能解析
    
	視圖類中配的(優先用)
	項目配置文件的配置(其次)
	drf有默認配置(最後)
	
	drf的默認配置:from rest_framework import settings
  

# 總結:
	一般情況下,都使用默認即可,不用配置(三種格式數據都能解析)

image

2.2 響應

# 其實就是:Respone 返回給前端的

# 導入:
	from rest_framework.response import Response
    
# 源碼分析
1.屬性:
	data=None,  # 返回給前端的數據:可以是 字元串,字典,列表 就是給http響應body體中內容-->也可以是response對象中取出數據並 處理
    
	status=None,  # 響應狀態碼:1xx,2xx,3xx,默認是200

	headers=None,      # 響應頭 字典
  
	了解:
		template_name=None,  # 模板名字(不用),用瀏覽器訪問時,可以改
		exception=False,    # 異常處理
		content_type=None   # 響應編碼格式
        
    
	from rest_framework.status import HTTP_201_CREATED
	Response(ser.data,status=HTTP_201_CREATED)
    
2.響應格式 跟解析數據格式類似
# 局部配置 在視圖類 views.py中配置:
from rest_framework.renderers import JSONRenderer, BrowsableAPIRenderer
class BookDetailView(APIView):
    renderer_classes = [JSONRenderer, ]

# 全局設置 在配置文件中配置:
REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': (  # 默認響應渲染類
        'rest_framework.renderers.JSONRenderer',  # json渲染器
        'rest_framework.renderers.BrowsableAPIRenderer',  # 瀏覽API渲染器
    )
}

image

3、視圖組件

# APIView  
	from rest_framework.views import APIView
    
	類屬性 renderer_classes,parser_classes...
	get方法,post方法,delete方法 寫法跟之前的View一樣,只不過request對象變成了新的request
	比之前的View多了三大認證和全局異常處理
  
  
# GenericAPIView  繼承了APIView 但是多了屬性和方法
	from rest_framework.generics import GenericAPIView
    
	屬性(先記兩個):
		queryset = None
		serializer_class = None
        
	方法:
		get_queryset
		get_object
		get_serializer
    
    
    
# 5個視圖擴展類(不是視圖類,沒有集成APIView,需要配合GenericAPIView)
	from rest_framework.mixins import 
		CreateModelMixin,
		ListModelMixin,
		DestroyModelMixin,
		RetrieveModelMixin,
		UpdateModelMixin
  
  
  
# 9個視圖子類 
	from rest_framework.generics import 
		CreateAPIView,
		ListAPIView,
		DestroyAPIView,
		RetrieveAPIView,
		UpdateAPIView,
		ListCreateAPIView,
		RetrieveUpdateAPIView,
		RetrieveUpdateDestroyAPIView,
		RetrieveDestroyAPIView


# 視圖集
	from rest_framework.viewsets import 
		# 兩個視圖類
		ModelViewSet, ReadOnlyModelViewSet,
		# 視圖類
		ViewSet, GenericViewSet,
		# 魔法類
		ViewSetMixin

繼承GenericAPIView 重寫視圖類

# 添加路由:
    path('publishs/<int:pk>', views.PublishDetailView.as_view()),
    
    
# 視圖類複製過來並做修改:
# 第一層:繼承APIView寫視圖類

# 第二層:繼承GenericAPIView寫視圖類
from rest_framework.generics import GenericAPIView

class PublishView(GenericAPIView):
    queryset = Publish.objects.all()
    serializer_class = PublishSerialzier

    # 查詢所有圖書
    def get(self, request):
        # obj = self.queryset
        obj = self.get_queryset()  # 等同於上面,obj = self.queryset 並且更好一些

        # ser = self.serializers(instance=obj, many=True)
        # ser=self.get_serializer_class()(instance=obj,many=True) # 等同於上面
        ser = self.get_serializer(instance=obj, many=True)  # 等同於上面
        return Response(ser.data)

    # 新增圖書數據
    def post(self, request):
        # ser = BookSerializer(data=request.data)
        ser = self.get_serializer(data=request.data)  # 等同於上面
        if ser.is_valid():
            ser.save()
            return Response({"code": 100, 'msg': '新增成功', 'data': ser.data})
        return Response({"code": 101, 'msg': '新增失敗', 'err': ser.errors})


class PublishDetailView(GenericAPIView):
    queryset = Publish.objects.all()
    serializer_class = PublishSerialzier

    # 查詢單條數據
    def get(self, request, *args, **kwargs):
        # book = Book.objects.all().filter(pk=pk).first()
        obj = self.get_object()  # 等同於上面

        # ser = BookSerializer(instance=book)
        ser = self.get_serializer(instance=obj)  # 等同於上面
        return Response(ser.data)

    # 修改數據
    def put(self, request, *args, **kwargs):
        # book = Book.objects.all().filter(pk=pk).first()
        obj = self.get_object()  # 等同於上面

        # ser = BookSerializer(instance=book, data=request.data)
        ser = self.get_serializer(instance=obj, data=request.data)  # 等同於上面
        if ser.is_valid():
            ser.save()
            return Response({"code": 100, 'msg': '修改成功', 'data': ser.data})
        return Response({"code": 101, 'msg': '修改出錯', 'err': ser.errors})

    # 刪除數據
    def delete(self, request, *args, **kwargs):
        # Book.objects.filter(pk=pk).delete()
        self.get_object().delete()
        return Response({"code": 100, 'msg': '刪除成功'})

image

4、通過GenericAPIView + 5個視圖擴展類 重寫視圖類

# 第三層:GenericAPIView+5個視圖擴展類 重寫視圖類
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import CreateModelMixin, ListModelMixin, DestroyModelMixin, RetrieveModelMixin, UpdateModelMixin

class PublishView(GenericAPIView, CreateModelMixin, ListModelMixin):
    queryset = Publish.objects.all()
    serializer_class = PublishSerialzier

    # 查詢所有圖書
    def get(self, request):
        return super().list(request)  # list(request)ListModelMixin的方法

    # 新增圖書數據
    def post(self, request):
        return super().list(request)  # create(request)ListModelMixin的方法


class PublishDetailView(GenericAPIView, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin):
    queryset = Publish.objects.all()
    serializer_class = PublishSerialzier

    # 查詢單條數據
    def get(self, request, *args, **kwargs):
        return super().retrieve(request, *args, **kwargs)

    # 修改數據
    def put(self, request, *args, **kwargs):
        return super().update(request, *args, **kwargs)

    # 刪除數據
    def delete(self, request, *args, **kwargs):
        return super().destroy(request, *args, **kwargs)

image