Book系列的群CURD操作
阿新 • • 發佈:2020-07-13
Book系列群操作
表設計與關聯models.py
from django.db import models # 一、基表 # Model類的內部配置Meta類要設定abstract=True,這樣的Model類就是用來作為基表 # 基表不會在資料庫內創建出來 # 二、表斷關聯 # 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 # 三、ORM外來鍵設計 # 1、一對多:外來鍵放在多的一方 # 2、多對多:外來鍵放在常用的一方 # 3、一對一:外來鍵放在不常用的一方 # 4、外來鍵欄位為正向查詢欄位,related_name是反向查詢欄位 # 一張表有且只有一個自增欄位,有且只有一個主鍵 class BaseModel(models.Model): is_delete = models.BooleanField(default=False) # auto_now_add=True 只要記錄建立,不需要手動插入時間,自動把當前時間插入 create_time = models.DateTimeField(auto_new_add=True) # auto_now=True,只要更新,就會把當前時間插入 last_update_time = models.DateTimeField(auto_new=True) # import datetime # create_time=models.DateTimeField(default=datetime.datetime.now) class Meta: # 單個欄位,有索引,有唯一 # 多個欄位,有聯合索引,聯合唯一 abstract=True # 抽象表 class Book(BaseModel): name = models.CharField(max_length=32) price = models.DecimalField(max_digits=5, 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) @property # 將方法包成資料屬性,不參與反序列化操作 def publish_name(self): # 返回出版社名字 return self.publish.name @property def author_list(self): # 使用列表生成式生成一個個的作者名字,返回列表 return [instance.name for instance in self.authors.all()] class Author(BaseModel): name = models.CharField(max_length=32) gender = models.IntegerField(choices=((1, '男'), (2, '女')), default=1) # 作者被刪,詳情一定被刪 detail = models.OneToOneField(to='Detail', on_delete=models.CASCADE, db_constraint=False) class Detail(BaseModel): phton = models.CharField(max_length=11) class Publish(BaseModel): name = models.CharField(max_length=32) address = models.CharField(max_length=32)
序列化器編寫
# ser.py from rest_framework import serializers from api import models # 通過檢視原始碼可知,群增時父類ListSerializer已經幫我寫了create方法,但是群改的update方法需要我們自己重寫 # 我們也可以在繼承父類ListSerializer的BookListSerializer中重寫create方法實現群增,但是沒必要 class BookListSerializer(serializers.ListSerializer): def update(self, instance, validated_data): # self.child就是BookModelSerializer return [self.child.update(instance[i], item) for i, item in enumerate(validated_data)] class BookModelSerializer(serializers.ModelSerializer): class Meta: # 通過list_serializer_class關聯BookListSerializer,從而訪問繫結的ListSerializer,實現群增群改 list_serializer_class = BookListSerializer model = models.Book # 插拔式屬性,進行序列化操作,資料屬性(publish_name,author_list)不參與反序列化操作 fields = ('pk', 'name', 'price', 'author_list', 'publish_name', 'publish', 'authors') extra_kwargs = { 'publish': {'write_only': True},# 提交資料時填寫,不會展示給使用者看 'publish_name': {'read_only': True}, # 只展示,不會提交 'authors': {'write_only': True}, 'author_list': {'read_only': True} }
使用GenericAPIView實現5個介面
# views.py from rest_framework.generics import GenericAPIView from rest_framework import status from api import models from api import ser from utils.response import APIResponse # 封裝的response物件 class BooksGenericAPIView(GenericAPIView): queryset = models.Book.objects.all().filter(is_delete=False) # 篩選出所有沒被刪除的資料 serializer_class = ser.BookModelSerializer # 寫入好的序列化器 # 單查、群查 def get(self, request, *args, **kwargs): if kwargs:# 通過kwargs是否有值來判斷是查詢單個數據還是查詢所有資料 instance = self.get_object() serializer = self.get_serializer(instance=instance) else: book_list = self.get_queryset() serializer = self.get_serializer(instance=book_list, many=True) return APIResponse(message='查詢成功', result=serializer.data) # 返回自定義格式的json資料 # 單增、群增 def post(self, request, *args, **kwargs): if isinstance(request.data, list): # 規定群增,前端傳過來的必須是個列表 # save()呼叫繼承的父類LiseSerializer中的create方法 serializer = self.get_serializer(data=request.data, many=True) else: # save()呼叫BookModelSerializer的create方法 serializer = self.get_serializer(data=request.data) # 使用全域性異常處理進行異常捕獲,以json格式返回異常 serializer.is_valid(raise_exception=True) serializer.save() return APIResponse(message='建立成功', result=serializer.data, status=status.HTTP_201_CREATED) # 單改、群改 def put(self, request, *args, **kwargs): if kwargs: instance = self.get_object() # save()呼叫BookModelSerializer的update方法 serializer = self.get_serializer(instance=instance, data=request.data) # 區域性修改 # 區域性修改就是在整體修改基礎上設定partial=True,或者將所有參與反序列化欄位設定為required=False # serializer = self.get_serializer(instance=instance, data=request.data, partial=True) else: book_list = []# 用來儲存書物件 modify_list = []# 用來儲存修改的資料 for data in request.data: pk = data.pop('pk') book_list.append(models.Book.objects.get(pk=pk))# 將獲取到的書物件追加到列表 modify_list.append(data)# 將需要修改的資料追加到列表 # save()會呼叫我們自己重寫的update方法(ListSerializer沒有幫我們寫群改的update) # BookModelSerializer通過list_serializer_class來關聯BookListSerializer,從而訪問繫結的ListSerializer從而實現群改,其中的self.child就是指BookModelSerializer serializer = self.get_serializer(instance=book_list, data=modify_list, many=True) serializer.is_valid(raise_exception=True) serializer.save() return APIResponse(message='修改成功', result=serializer.data) # 單刪、群刪 def delete(self, request, *args, **kwargs): # 不管是單刪還是群刪都存入列表pks中,只需要通過__in來篩選即可 pks = [] if kwargs: pk = kwargs.get('pk') pks.append(pk) else: pks = request.data.get('pks') # 規定群刪除傳入格式{"pks":[]} res = models.Book.objects.filter(pk__in=pks, is_delete=False).update(is_delete=True) if not res: return APIResponse(code=101, message='要刪除的資料不存在', status=status.HTTP_404_NOT_FOUND) return APIResponse(message='成功刪除%s條資料' % res)
路由設定
# urls.py
# 總路由:
path('api/', include('api.urls'))
# 子路由:
path('books/', views.BooksGenericAPIView.as_view()),
re_path(r'books/(?P<pk>\d+)', views.BooksGenericAPIView.as_view()),