1. 程式人生 > 實用技巧 >books系列表介面

books系列表介面

總路由/urls.py

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

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

api/urls.py

from django.urls import path, re_path
from api import views

urlpatterns = [
    path('books/', views.BookAPIView.as_view()),
    re_path(
'books/(?P<pk>\d+)', views.BookAPIView.as_view()), ]

models.py

from django.db import models


# Create your models here.
class BaseModel(models.Model):
    is_delete = models.BooleanField(default=False)
    # auto_now_add=True 只要記錄建立,不需要手動插入時間,自動把當前時間插入
    create_time = models.DateTimeField(auto_now_add=True)
    
# auto_now=True,只要更新,就會把當前時間插入 last_update_time = models.DateTimeField(auto_now=True) # import datetime # create_time=models.DateTimeField(default=datetime.datetime.now) class Meta: # 單個欄位,有索引,有唯一 # 多個欄位,有聯合索引,聯合唯一 abstract = True # 抽象表,不在資料庫建立出表 class Book(BaseModel):
# verbose_name admin中顯示中文 name = models.CharField(max_length=32, verbose_name='書名', help_text='這裡填書名') price = models.DecimalField(max_digits=8, decimal_places=2) # 一對多的關係一旦確立,關聯欄位寫在多的一方 # to_field 預設不寫,關聯到Publish主鍵 # db_constraint=False 邏輯上的關聯,實質上沒有外來鍵練習,增刪不會受外來鍵影響,但是orm查詢不影響 publish = models.ForeignKey(to='Publish', on_delete=models.DO_NOTHING, db_constraint=False) # 多對多,跟作者,關聯欄位寫在 查詢次數多的一方 # 什麼時候用自動,什麼時候用手動?第三張表只有關聯欄位,用自動 第三張表有擴充套件欄位,需要手動寫 # 不能寫on_delete authors = models.ManyToManyField(to='Author', db_constraint=False) class Meta: verbose_name_plural = '書表' # admin中表名的顯示 def __str__(self): return self.name @property def publish_name(self): return self.publish.name # def author_list(self): def author_list(self): author_list = self.authors.all() # ll=[] # for author in author_list: # ll.append({'name':author.name,'sex':author.get_sex_display()}) # return ll return [{'name': author.name, 'sex': author.get_sex_display()} for author in author_list] class Publish(BaseModel): name = models.CharField(max_length=32) addr = models.CharField(max_length=32) def __str__(self): return self.name class Author(BaseModel): name = models.CharField(max_length=32) sex = models.IntegerField(choices=((1, ''), (2, ''))) # 一對一關係,寫在查詢頻率高的一方 # OneToOneField本質就是ForeignKey+unique,自己手寫也可以 authordetail = models.OneToOneField(to='AuthorDetail', db_constraint=False, on_delete=models.CASCADE) class AuthorDetail(BaseModel): mobile = models.CharField(max_length=11) # 二、表斷關聯 # 1、表之間沒有外來鍵關聯,但是有外來鍵邏輯關聯(有充當外來鍵的欄位) # 2、斷關聯後不會影響資料庫查詢效率,但是會極大提高資料庫增刪改效率(不影響增刪改查操作) # 3、斷關聯一定要通過邏輯保證表之間資料的安全,不要出現髒資料,程式碼控制 # 4、斷關聯 # 5、級聯關係 # 作者沒了,詳情也沒:on_delete=models.CASCADE # 出版社沒了,書還是那個出版社出版:on_delete=models.DO_NOTHING # 部門沒了,員工沒有部門(空不能):null=True, on_delete=models.SET_NULL # 部門沒了,員工進入預設部門(預設值):default=0, on_delete=models.SET_DEFAULT

ser.py

from rest_framework import serializers
from api import models


# 寫一個類,繼ListSerializer,重寫update
class BookListSerializer(serializers.ListSerializer):
    # def create(self, validated_data):
    #     print(validated_data)
    #     return super().create(validated_data)
    def update(self, instance, validated_data):
        print(instance)
        print(validated_data)
        # 儲存資料
        # self.child:是BookModelSerializer物件
        # ll=[]
        # for i,si_data in enumerate(validated_data):
        #     ret=self.child.update(instance[i],si_data)
        #     ll.append(ret)
        # return ll
        return [
            # self.child.update(物件,字典) for attrs in validated_data
            self.child.update(instance[i], attrs) for i, attrs in enumerate(validated_data)
        ]


# 如果序列化的是資料庫的表,儘量用ModelSerializer
class BookModelSerializer(serializers.ModelSerializer):
    # publish,顯示出版社名稱
    # 一種方案(只序列化可以,反序列化有問題)
    # publish=serializers.CharField(source='publish.name')
    # 第二種方案,models中寫方法(看models.py)

    class Meta:
        list_serializer_class = BookListSerializer
        model = models.Book
        # fields='__all__'
        # 用的少
        # depth=0
        fields = ('id', 'name', 'price', 'authors', 'publish', 'publish_name', 'author_list')

        extra_kwargs = {
            'publish': {'write_only': True},
            'publish_name': {'read_only': True},
            'authors': {'write_only': True},
            'author_list': {'read_only': True}
        }

views.py

from django.shortcuts import render

# Create your views here.
from rest_framework.response import Response

from api import models
from  rest_framework.views import APIView
from rest_framework.generics import GenericAPIView
from api.ser import BookModelSerializer

class BookAPIView(APIView):
    def get(self,request,*args,**kwargs):
        #查詢單個和查詢所有,合到一起
        if not kwargs:
            # 查所有
            book_list=models.Book.objects.all().filter(is_delete=False)
            book_list_ser=BookModelSerializer(book_list,many=True)
            return Response(data=book_list_ser.data)
        #查一個
        book_list = models.Book.objects.filter(pk=kwargs.get('pk')).first()
        book_list_ser = BookModelSerializer(book_list)
        return Response(data=book_list_ser.data)

    def post(self, request, *args, **kwargs):
        # 具備增單條,和增多條的功能
        if isinstance(request.data, dict):

            book_ser = BookModelSerializer(data=request.data)
            book_ser.is_valid(raise_exception=True)
            book_ser.save()
            return Response(data=book_ser.data)
        elif isinstance(request.data, list):
            # 現在book_ser是ListSerializer物件
            from rest_framework.serializers import ListSerializer
            book_ser = BookModelSerializer(data=request.data, many=True)  # 增多條
            print('--------', type(book_ser))
            book_ser.is_valid(raise_exception=True)
            book_ser.save()
            # 新增---》ListSerializer--》create方法
            # def create(self, validated_data):
            #   self.child是BookModelSerializer物件
            #   print(type(self.child))
            #     return [
            #         self.child.create(attrs) for attrs in validated_data
            #     ]
            return Response(data=book_ser.data)

    def put(self, request, *args, **kwargs):
        # 改一個,改多個
        # 改一個
        if kwargs.get('pk', None):
            book = models.Book.objects.filter(pk=kwargs.get('pk')).first()
            book_ser = BookModelSerializer(instance=book, data=request.data, partial=True)  # 增多條
            # partial=True
            # partial 表示是否可以部分修改
            book_ser.is_valid(raise_exception=True)
            book_ser.save()
            return Response(data=book_ser.data)
        else:
            # 改多個,
            # 前端傳遞資料格式[{id:1,name:xx,price:xx},{id:1,name:xx,price:xx}]
            # 處理傳入的資料  物件列表[book1,book2]  修改的資料列表[{name:xx,price:xx},{name:xx,price:xx}]
            book_list = []
            modify_data = []
            for item in request.data:
                # {id:1,name:xx,price:xx}

                pk = item.pop('id')
                book = models.Book.objects.get(pk=pk)
                book_list.append(book)
                modify_data.append(item)
            # 第一種方案,for迴圈一個一個修改
            # 把這個實現
            # for i,si_data in enumerate(modify_data):
            #     book_ser = BookModelSerializer(instance=book_list[i], data=si_data)
            #     book_ser.is_valid(raise_exception=True)
            #     book_ser.save()
            # return Response(data='成功')
            # 第二種方案,重寫ListSerializer的update方法
            book_ser = BookModelSerializer(instance=book_list, data=modify_data, many=True)
            book_ser.is_valid(raise_exception=True)
            book_ser.save()  # ListSerializer的update方法,自己寫的update方法
            return Response(book_ser.data)
            # request.data
            #
            # book_ser=BookModelSerializer(data=request.data)

    def delete(self, request, *args, **kwargs):
        # 單個刪除和批量刪除
        pk = kwargs.get('pk')
        pks = []
        if pk:
            # 單條刪除
            pks.append(pk)
        # 不管單條刪除還是多條刪除,都用多條刪除
        # 多條刪除
        # {'pks':[1,2,3]}
        else:
            pks = request.data.get('pks')
        # 把is_delete設定成true
        # ret返回受影響的行數
        ret = models.Book.objects.filter(pk__in=pks, is_delete=False).update(is_delete=True)
        if ret:
            return Response(data={'msg': '刪除成功'})
        else:
            return Response(data={'msg': '沒有要刪除的資料'})