目錄python
Model類的內部配置Meta類要設置abstract=True,這樣的Model類就是用來做爲基表git
多表:Book,Publish,Author,AuthorDetail數據庫
db_constraint=Falsedjango
一、一對多:外鍵放在多的一方
二、多對多:外鍵放在經常使用的一方
三、一對一:外鍵放在不經常使用的一方
四、外鍵字段爲正向查詢字段,related_name是反向查詢字段json
author = models.OneToOneField(to='Author', related_name='detail', db_constraint=False, on_delete=models.CASCADE)
有做者能夠沒有詳情,刪除做者,詳情必定會被級聯刪除api
外鍵字段爲正向查詢字段,related_name是反向查詢字段安全
related_name='books',反向查詢能夠直接點books,反向查詢的字段
db_constraint=False,去掉外鍵創建的關聯
on_delete=models.DO_NOTHING,不執行級聯刪除app
# ManyToManyField字段不提供設置on_delete,若是想設置關係表級聯,只能手動定義關係表 authors = models.ManyToManyField(to='Author', related_name='books', db_constraint=False)
from django.db import models from django.conf import settings # 1、基表 # Model類的內部配置Meta類要設置abstract=True,這樣的Model類就是用來做爲基表 # 多表:Book,Publish,Author,AuthorDetail class BaseModel(models.Model): is_delete = models.BooleanField(default=False) create_time = models.DateTimeField(auto_now_add=True) class Meta: # 基表必須設置abstract,基表就是給普通Model類繼承使用的, # 設置了abstract就不會完成數據庫遷移完成建表 # abstract 目的就是隻爲了繼承設置,而且告訴django,不要進行創建這個表格 abstract = True # 抽象的表 class Book(BaseModel):# 繼承表 name = models.CharField(max_length=16) price = models.DecimalField(max_digits=5, decimal_places=2) # related_name='books',反向查詢能夠直接點books,反向查詢的字段 # db_constraint=False,去掉外鍵創建的關聯 # on_delete=models.DO_NOTHING,不執行級聯刪除 publish = models.ForeignKey(to='Publish', related_name='books', db_constraint=False, on_delete=models.DO_NOTHING) # 重點:多對多外鍵實際在關係表中,ORM默認關係表中兩個外鍵都是級聯 # db_constraint=False # ManyToManyField字段不提供設置on_delete,若是想設置關係表級聯,只能手動定義關係表 authors = models.ManyToManyField(to='Author', related_name='books', db_constraint=False) # 自定義連表深度,不須要反序列化,由於自定義插拔屬性不參與反序列化 @property def publish_name(self): return self.publish.name @property def author_list(self): temp_author_list = [] for author in self.authors.all(): temp_author_list.append({ 'name': author.name, 'sex': author.get_sex_display(), 'mobile': author.detail.mobile }) return temp_author_list class Publish(BaseModel): name = models.CharField(max_length=16) address = models.CharField(max_length=64) class Author(BaseModel): name = models.CharField(max_length=16) sex = models.IntegerField(choices=[(0, '男'), (1, '女')], default=0) class AuthorDetail(BaseModel): mobile = models.CharField(max_length=11) # 有做者能夠沒有詳情,刪除做者,詳情必定會被級聯刪除 # 外鍵字段爲正向查詢字段,related_name是反向查詢字段 author = models.OneToOneField(to='Author', related_name='detail', db_constraint=False, on_delete=models.CASCADE)
返回信息組件化
格式:post
{ 'status':0, 'msg':"", 'results':'', ... }
from rest_framework.response import Response class APIResponse(Response): # 格式化data def __init__(self, status=0, msg='ok', results=None, http_status=None, headers=None, exception=False, **kwargs): data = { # json的response基礎有數據狀態碼和數據狀態信息 'status': status, 'msg': msg } if results is not None: # 後臺有數據,響應數據 data['results'] = results data.update(**kwargs) # 後臺的一切自定義響應數據直接放到響應數據data中 super().__init__(data=data, status=http_status, headers=headers, exception=exception)
from rest_framework.views import exception_handler as drf_exception_handler from rest_framework.response import Response def exception_handler(exc, context): # drf_exception_handler的執行結果就是異常信息的Response對象或None # 是Response對象能夠直接返回 # 是None能夠從exc中拿到異常信息,從context拿到是誰出現的異常,本身格式化成Response對象返回 # 重點:自定義異常模塊目的是記錄異常信息到日誌文件 - 產品階段 response = drf_exception_handler(exc, context) if response is None: response = Response({'detail': '%s' % exc}, status=500, exception=True) # logging.error(response.data) return response
REST_FRAMEWORK = { # 異常 # 'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler',#系統異常 'EXCEPTION_HANDLER': 'api.utils.exception_handler',#重寫異常 }
# 瞭解 fields = '__all__'#返回全部 exclude = ('id', )#除了id 其餘的返回 depth = 1#連表深度查詢返回 #下面倆個不能一塊兒使用 fields = '__all__'#返回全部 exclude = ('id', )#除了id 其餘的返回
from rest_framework import serializers from . import models class BookListSerializer(serializers.ListSerializer): # 一、create方法父級ListSerializer已經提供了 # def create(self, validated_data): # # 經過self.child來訪問綁定的ModelSerializer # print(self.child) # raise Exception('我不提供') # 二、父級ListSerializer沒有經過update方法的實現體,須要本身重寫 def update(self, instance, validated_data): # print(instance) # print(validated_data) return [ self.child.update(instance[i], attrs) for i, attrs in enumerate(validated_data) ] class BookModelSerializer(serializers.ModelSerializer): # 經過BookModelSerializer.Meta.list_serializer_class來訪問綁定的ListSerializer class Meta: # 關聯ListSerializer完成羣增羣改 ################################################################# list_serializer_class = BookListSerializer model = models.Book # fields = ('name', 'price', 'publish', 'authors') # fields = ('name', 'price', 'publish_name', 'author_list') # 瞭解 # fields = '__all__' # exclude = ('id', ) # depth = 1 # 序列化與反序列化整合 fields = ('name', 'price', 'publish_name', 'author_list', 'publish', 'authors') extra_kwargs = { 'publish': { 'write_only': True }, 'authors': { 'write_only': True } }
子序列化都是提供給外鍵(正向方向)完成深度查詢的,外鍵數據是惟一:many=False;不惟一:many=True
只能參與序列化,且反序列化不能寫(反序列化外鍵字段會拋異常)
# 前提:若是隻有查需求的接口,自定義深度還能夠用子序列化方式完成 class PublishModelSerializer(serializers.ModelSerializer): # 子序列化都是提供給外鍵(正向方向)完成深度查詢的,外鍵數據是惟一:many=False;不惟一:many=True # 注:只能參與序列化,且反序列化不能寫(反序列化外鍵字段會拋異常) books = BookModelSerializer(many=True) class Meta: model = models.Publish fields = ('name', 'address', 'books')
from django.conf.urls import url from . import views urlpatterns = [ url(r'^books/$', views.BookAPIView.as_view()), url(r'^books/(?P<pk>\d+)/$', views.BookAPIView.as_view()), ]
from rest_framework.views import APIView from rest_framework.response import Response from . import models, serializers from .response import APIResponse class BookAPIView(APIView):
# 單查、羣查 def get(self, request, *args, **kwargs): pk = kwargs.get('pk') if pk: book_obj = models.Book.objects.filter(pk=pk, is_delete=False).first() if not book_obj: return APIResponse(1, 'pk error', http_status=400) book_data = serializers.BookModelSerializer(book_obj).data return APIResponse(results=book_data) book_query = models.Book.objects.filter(is_delete=False).all() return APIResponse(0, 'ok', data=serializers.BookModelSerializer(book_query, many=True).data)
# 單刪、羣刪 def delete(self, request, *args, **kwargs): """ 單刪:前臺數據爲pk,接口爲 /books/(pk)/ 羣刪:前臺數據爲pks,接口爲 /books/ """ pk = kwargs.get('pk') # 將單刪羣刪邏輯整合 if pk: # /books/(pk)/的接口就不考慮羣刪,就固定爲單刪 pks = [pk] else: pks = request.data.get('pks') # 前臺數據有誤(主要是羣刪沒有提供pks) if not pks: return APIResponse(1, 'delete error', http_status=400) # 只要有操做受影響行,就是刪除成功,反之失敗 rows = models.Book.objects.filter(is_delete=False, pk__in=pks).update(is_delete=True) if rows: return APIResponse(0, 'delete ok') return APIResponse(1, 'delete failed')
# 單增、羣增 def post(self, request, *args, **kwargs): """ 單增:前臺提交字典,接口 /books/ 羣增:前臺提交列表套字典,接口 /books/ """ request_data = request.data if isinstance(request_data, dict): # 單增 book_ser = serializers.BookModelSerializer(data=request_data) if book_ser.is_valid(): book_obj = book_ser.save() return APIResponse(results=serializers.BookModelSerializer(book_obj).data) return APIResponse(1, msg=book_ser.errors) elif isinstance(request_data, list) and len(request_data) != 0 : # 羣增 book_ser = serializers.BookModelSerializer(data=request_data, many=True) book_ser.is_valid(raise_exception=True) book_obj_list = book_ser.save() return APIResponse(results=serializers.BookModelSerializer(book_obj_list, many=True).data) else: return APIResponse(1, 'data error', http_status=400)
父級ListSerializer沒有經過update方法的實現體,須要本身重寫
class BookListSerializer(serializers.ListSerializer): # 一、create方法父級ListSerializer已經提供了 # def create(self, validated_data): # # 經過self.child來訪問綁定的ModelSerializer # print(self.child) # raise Exception('我不提供') # 二、父級ListSerializer沒有經過update方法的實現體,須要本身重寫 def update(self, instance, validated_data): # print(instance) # print(validated_data) return [ self.child.update(instance[i], attrs) for i, attrs in enumerate(validated_data) ]
class BookModelSerializer(serializers.ModelSerializer): # 經過BookModelSerializer.Meta.list_serializer_class來訪問綁定的ListSerializer class Meta: # 關聯ListSerializer完成羣增羣改 list_serializer_class = BookListSerializer
instance=obj
# 修改和新增,都須要經過數據,數據依舊給data,修改與新增不一樣點,instance要被賦值爲被修改對象 book_ser = serializers.BookModelSerializer(instance=book_obj, data=request_data)
# 單總體改、羣總體改 def put(self, request, *args, **kwargs): """ 單總體改:前臺提交字典,接口 /books/(pk)/ 羣總體改:前臺提交列表套字典,接口 /books/,注每個字典均可以經過pk """ pk = kwargs.get('pk') request_data = request.data if pk: # 單改 try: book_obj = models.Book.objects.get(pk=pk) except: return APIResponse(1, 'pk error') # 修改和新增,都須要經過數據,數據依舊給data,修改與新增不一樣點,instance要被賦值爲被修改對象 book_ser = serializers.BookModelSerializer(instance=book_obj, data=request_data) book_ser.is_valid(raise_exception=True) book_obj = book_ser.save() return APIResponse(results=serializers.BookModelSerializer(book_obj).data) else: # 羣改 if not isinstance(request_data, list) or len(request_data) == 0: return APIResponse(1, 'data error', http_status=400) # [{pk:1,...}, {pk:3,...}, {pk:100,...}] => [obj1, obj3, obj100] + [{...}, {...}, {...}] # 要考慮pk對應的對象是否被刪,以及pk沒有對應的對象 # 假設pk3被刪,pk100沒有 => [obj1] + [{...}] # 注:必定不要在循環體中對循環對象進行增刪(影響對象長度)的操做 obj_list = [] data_list = [] for dic in request_data: # request_data多是list,單內部不必定是dict try: pk = dic.pop('pk') try: obj = models.Book.objects.get(pk=pk, is_delete=False) obj_list.append(obj) data_list.append(dic) except: pass except: return APIResponse(1, 'data error', http_status=400) book_ser = serializers.BookModelSerializer(instance=obj_list, data=data_list, many=True) book_ser.is_valid(raise_exception=True) book_obj_list = book_ser.save() return APIResponse(results=serializers.BookModelSerializer(book_obj_list, many=True).data)
partial=True
# 局部修改就是在總體修改基礎上設置partial=True,將全部參與反序列化字段設置爲required=False book_ser = serializers.BookModelSerializer(instance=book_obj, data=request_data, partial=True)
# 單局部改、羣局部改 def patch(self, request, *args, **kwargs): """ 單總體改:前臺提交字典,接口 /books/(pk)/ 羣總體改:前臺提交列表套字典,接口 /books/,注每個字典均可以經過pk """ pk = kwargs.get('pk') request_data = request.data if pk: try: book_obj = models.Book.objects.get(pk=pk) except: return APIResponse(1, 'pk error') # 局部修改就是在總體修改基礎上設置partial=True,將全部參與反序列化字段設置爲required=False book_ser = serializers.BookModelSerializer(instance=book_obj, data=request_data, partial=True) book_ser.is_valid(raise_exception=True) book_obj = book_ser.save() return APIResponse(results=serializers.BookModelSerializer(book_obj).data) else: # 羣改 if not isinstance(request_data, list) or len(request_data) == 0: return APIResponse(1, 'data error', http_status=400) # [{pk:1,...}, {pk:3,...}, {pk:100,...}] => [obj1, obj3, obj100] + [{...}, {...}, {...}] # 要考慮pk對應的對象是否被刪,以及pk沒有對應的對象 # 假設pk3被刪,pk100沒有 => [obj1] + [{...}] # 注:必定不要在循環體中對循環對象進行增刪(影響對象長度)的操做 obj_list = [] data_list = [] for dic in request_data: # request_data多是list,單內部不必定是dict try: pk = dic.pop('pk') try: obj = models.Book.objects.get(pk=pk, is_delete=False) obj_list.append(obj) data_list.append(dic) except: pass except: return APIResponse(1, 'data error', http_status=400) book_ser = serializers.BookModelSerializer(instance=obj_list, data=data_list, many=True, partial=True) book_ser.is_valid(raise_exception=True) book_obj_list = book_ser.save() return APIResponse(results=serializers.BookModelSerializer(book_obj_list, many=True).data)
# 單改 def _single_update(self, pk, data): try: instance = models.Worker.objects.get(pk=pk, is_delete=False) ser = serializers.WorkerModelSerializer(instance=instance, data=data, partial=True) ser.is_valid(raise_exception=True) obj = ser.save() return APIResponse(data=serializers.WorkerModelSerializer(obj).data) except: return APIResponse(1, 'pk error', http_status=400)
# 羣改 def _many_updata(self, data): instance_list = [] data_list = [] for dic in data: try: # 不是字典,數據錯誤 pk = dic.pop('pk') if len(dic) == 0: raise Exception('隨便') try: # pk沒有,對應的obj沒有,對應的obj已刪除,該數據丟棄 obj = models.Worker.objects.get(pk=pk, is_delete=False) instance_list.append(obj) data_list.append(dic) except: pass except: return APIResponse(1, 'data error', http_status=400) ser = serializers.WorkerModelSerializer(instance=instance_list, data=data_list, partial=True, many=True) ser.is_valid(raise_exception=True) obj_list = ser.save() return APIResponse(data=serializers.WorkerModelSerializer(obj_list, many=True).data)
def patch(self, request, *args, **kwargs): pk = kwargs.get('pk') request_data = request.data if pk and isinstance(request_data, dict) and len(request_data) != 0: return self._single_update(pk, request_data) elif not pk and isinstance(request_data, list) and len(request_data) != 0: return self._many_updata(request_data) else: return APIResponse(1, 'data error', http_status=400)