Django---drf, books系列表介面、分頁器、根據ip進行頻率限制
阿新 • • 發佈:2020-07-13
目錄
回顧
# 1 web開發模型,混合開發和前後端分離 # 2 web api:介面 # 3 postman的使用 # 4 restful規範:10條 # 5 djangorestframework,django的第三方外掛(app) # 6 drf幾大元件 請求(APIView原始碼,Requset物件)和響應(Response,自己封裝Response), 序列化, 檢視, 路由, 解析器(DEFAULT_PARSER_CLASSES,全域性配置,區域性配置), 響應器(DEFAULT_RENDERER_CLASSES,全域性配,區域性配), 認證:校驗是否登入(有內建,自定義,全域性配置,區域性配置) 許可權:是否有許可權訪問某些介面(有內建,自定義,全域性配置,區域性配置) 頻率:限制訪問頻次(有內建,自定義,全域性配置,區域性配置),根據使用者ip,根據使用者id限制 過濾:篩選,查詢出符合條件的 排序:結果進行排序 異常:全域性異常(自定義,全域性配置) 版本控制(不講) 分頁器 文件生成 jwt認證 Xadmin的使用 路飛專案 git redis 簡訊 支付寶支付
今日內容
1 books系列表介面
# 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()),
]
# views.py 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): #查詢單個和查詢所有,合到一起 # 查所有 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) #查一個 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) # 增多條 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': '沒有要刪除的資料'})
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=serializers.CharField(source='publish.name') # 第二種方案,models中寫方法 class Meta: list_serializer_class=BookListSerializer model=models.Book # fields='__all__' # 用的少 # depth=0 fields = ('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} }
# models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
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):
id=models.AutoField(primary_key=True)
# verbose_name admin中顯示中文
name=models.CharField(max_length=32,verbose_name='書名',help_text='這裡填書名')
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)
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
2 分頁器
#views.py
# 查所有,才需要分頁
from rest_framework.generics import ListAPIView
# 內建三種分頁方式
from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination,CursorPagination
'''
PageNumberPagination
page_size:每頁顯示的條數
'''
class MyPageNumberPagination(PageNumberPagination):
#http://127.0.0.1:8000/api/books2/?aaa=1&size=6
page_size=3 #每頁條數
page_query_param='aaa' #查詢第幾頁的key
page_size_query_param='size' # 每一頁顯示的條數
max_page_size=5 # 每頁最大顯示條數
# class MyLimitOffsetPagination(LimitOffsetPagination):
# default_limit = 3 # 每頁條數
# limit_query_param = 'limit' # 往後拿幾條
# offset_query_param = 'offset' # 標杆
# max_limit = 5 # 每頁最大幾條
class MyCursorPagination(CursorPagination):
cursor_query_param = 'cursor' # 每一頁查詢的key
page_size = 2 #每頁顯示的條數
ordering = '-id' #排序欄位
# class BookView(ListAPIView):
# # queryset = models.Book.objects.all().filter(is_delete=False)
# queryset = models.Book.objects.all()
# serializer_class = BookModelSerializer
# #配置分頁
# pagination_class = MyCursorPagination
# 如果使用APIView分頁
from utils.throttling import MyThrottle
class BookView(APIView):
# throttle_classes = [MyThrottle,]
def get(self,request,*args,**kwargs):
book_list=models.Book.objects.all()
# 例項化得到一個分頁器物件
page_cursor=MyPageNumberPagination()
book_list=page_cursor.paginate_queryset(book_list,request,view=self)
next_url =page_cursor.get_next_link()
pr_url=page_cursor.get_previous_link()
# print(next_url)
# print(pr_url)
book_ser=BookModelSerializer(book_list,many=True)
return Response(data=book_ser.data)
#settings.py
REST_FRAMEWORK={
'PAGE_SIZE': 2,
}
2 根據ip進行頻率限制
# 寫一個類,繼承SimpleRateThrottle,只需要重寫get_cache_key
from rest_framework.throttling import ScopedRateThrottle,SimpleRateThrottle
#繼承SimpleRateThrottle
class MyThrottle(SimpleRateThrottle):
scope='luffy'
def get_cache_key(self, request, view):
print(request.META.get('REMOTE_ADDR'))
return request.META.get('REMOTE_ADDR') # 返回
# 區域性使用,全域性使用
REST_FRAMEWORK={
'DEFAULT_THROTTLE_CLASSES': (
'utils.throttling.MyThrottle',
),
'DEFAULT_THROTTLE_RATES': {
'luffy': '3/m' # key要跟類中的scop對應
},
}
# python3 manage.py runserver 0.0.0.0:8000 你們區域網就可以相互訪問
# 內網穿透