認證組件 訪問某個介面 需要登陸後才能訪問 #第一步 寫一個登錄功能 用戶表 User表 UserToken表 :存儲用戶登錄狀態 【這個表可以沒有 如果沒有 把欄位直接卸載User表上也可以】 登錄介面 model.py class Books(models.Model): name = mode ...
認證組件
訪問某個介面 需要登陸後才能訪問
#第一步 寫一個登錄功能 用戶表
User表
UserToken表 :存儲用戶登錄狀態 【這個表可以沒有 如果沒有 把欄位直接卸載User表上也可以】
登錄介面
model.py
class Books(models.Model):
name = models.CharField(max_length=32)
price = models.CharField(max_length=32)
publish = models.ForeignKey(to='Publish',on_delete=models.CASCADE)
authors = models.ManyToManyField(to='Authors')
def publish_dict(self):
return {'name':self.publish.name,'addr':self.publish.addr}
def author_list(self):
l = []
for author in self.authors.all():
l.append({'name':author.name,'phone':author.phone})
return l
class Publish(models.Model):
name = models.CharField(max_length=32)
addr = models.CharField(max_length=32)
class Authors(models.Model):
name = models.CharField(max_length=32)
phone = models.CharField(max_length=32)
class User(models.Model):
username = models.CharField(max_length=32)
password = models.IntegerField()
class UserToken(models.Model):
token = models.CharField(max_length=32)
user = models.OneToOneField(to='User',on_delete=models.CASCADE,null=True)
url.py
router = SimpleRouter()
router.register('user',views.UserView,'user')
urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/', include(router.urls))
]
views.py
import uuid
from django.shortcuts import render
from .models import User, UserToken
from rest_framework.viewsets import ModelViewSet,ViewSet
from rest_framework.decorators import action
from rest_framework.response import Response
# Create your views here.
class UserView(ViewSet):
@action(methods=['POST'], detail=False)
def login(self, request):
username = request.data.get('username')
password = request.data.get('password')
user = User.objects.filter(username=username, password=password).first()
if user:
token = str(uuid.uuid4())
#用戶登陸成功隨機生成一個用不重覆的字元串
#在Usertoken表中存儲一下 :1 從來沒有登陸過 插入一條 2登陸過 修改記錄
UserToken.objects.update_or_create(user=user, defaults={'token': token})
#如果有就修改 沒有就新增
#kwargs 傳入的東西查找 能找到 使用defaults的更新 否則新增一條
return Response({'code': 100, 'msg': '登陸成功', 'token': token})
else:
return Response({'code': 101, 'msg': '用戶名或密碼錯誤'})
'''
以後 有的介面組要登錄後才能訪問 有的介面不登陸就能訪問(查詢所有不需要登錄就能訪問 查詢單個 需要登陸才能訪問)
登錄認證的限制
寫登錄介面 返回token 以後只要帶著token過來 就是登陸了 不帶就是沒有登陸
'''
認證組件使用
# 查詢所有不需要登錄就能訪問
# 查詢單個,需要登錄才能訪問
# 在查詢單個個視圖類中寫authentication_classes=[]
1.寫一個認證類 需要繼承BaseAuthentication
from rest_framework.authentication import BaseAuthentication
2.通過看源碼分析 必須重寫authenticate方法 在該方法中實現登錄認證
3.如果認證成功 返回兩個值【登錄用戶和token或None】
4.認證不通過 拋異常
from rest_framework.exceptions import AuthenticationFailed
5.局部使用和全局使用
局部:只在某視圖類中使用【當前視圖類管理的所有介面均使用過】
class BookView(ViewSetMixin,RetrieveAPIView):
queryset = Books.objects.all()
serializer_class = BooksSerializers
authentication_classes = [LoginAuth]
'''登錄以後才能查詢單個書信息'''
全局:全部介面都生效(登錄介面不需要)
REST_FRAMEWORK={
'DEFAULT_AUTHENTICATION_CLASSES': ['app01.authentication.LoginAuth']
}
'''
所有介面都需要認證 登陸不能驗證 局部禁用
'''
局部禁用:
class UserView(ViewSet):
authentication_classes = []
view.py
#查所有
class BooksView(ViewSetMixin,ListAPIView):
queryset = Books.objects.all()
serializer_class = BooksSerializers
#查單個
class BookView(ViewSetMixin,RetrieveAPIView):
queryset = Books.objects.all()
serializer_class = BooksSerializers
authentication_classes = [LoginAuth] #需要寫一個認證類
authentication.py 認證類代碼
#自己寫的認證類 需要繼承某個類
from .models import UserToken
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
class LoginAuth(BaseAuthentication):
def authenticate(self,request):
#在這裡實現用戶的驗證 如果是登錄的繼續走 不是就拋異常
#請求中是否攜帶token判斷是否登錄 地址欄中 request是新的
token = request.query_params.get('token',None)
if token: #前端傳入token 去表中查 如果查到了登錄了返回兩個值 固定的 1.當前登錄用戶 2.token
user_token=UserToken.objects.filter(token=token).first()
if user_token:
return user_token.user,token
else:
raise AuthenticationFailed('token認證失敗')#沒登陸就拋異常
else:
raise AuthenticationFailed('token沒傳')
許可權組件
即便登陸成功 有些介面 還是不能訪問 因為沒有許可權
登陸後 有的介面有訪問許可權 有的沒有
查詢單個和查詢所有 都要登錄才能訪問 -- 全局認證
查詢單個需要超級管理員
查詢所有需要登陸的用戶
許可權是一個欄位 在User表中加入user_type
欄位
許可權的使用
1.寫一個許可權類 繼承BasePermission
from rest_framework.permissions import BasePermission
2.重寫has_permission方法 在該方法實現許可權認證 在這方法中request.user就是當前登錄用戶
3.如果有許可權 返回True
4.如果沒有許可權 返回False 定製返回中文 self.message = '中文'
5.局部使用和全局使用
局部:只在某個視圖類中使用【當前視圖類管理的所有介面都使用
】
class BookView(ViewSetMixin,RetrieveAPIView):
queryset = Books.objects.all()
serializer_class = BooksSerializers
authentication_classes = [LoginAuth] #需要寫一個認證類
permission_classes = [CommonPermission] #認證和許可權都可以加多個 多層
全局:全局所有介面都生效
'DEFAULT_PERMISSION_CLASSES': ['app01.permissions.CommonPermission'],
局部禁用:
permission_classes = []
views.py
class BookView(ViewSetMixin,RetrieveAPIView):
queryset = Books.objects.all()
serializer_class = BooksSerializers
authentication_classes = [LoginAuth] #需要寫一個認證類
permission_classes = [CommonPermission] #認證和許可權都可以加多個 多層
permission.py
#許可權類 寫一個類 重寫方法 在方法中實現許可權認證
from rest_framework.permissions import BasePermission
class CommonPermission(BasePermission):
#重寫has_permission方法 有許可權返回True,沒有許可權返回False
def has_permission(self,request,view):
#實現許可權的控制 -- 要先知道當前的登錄用戶是誰 request.user 前面認證返回的登錄用戶 就是這裡的request.user
if request.user.user_type == 1:
return True
else:
#沒有許可權 可以放一個message
self.message = '您是%s 您沒有許可權' %request.user.get_user_type_display()
return False
頻率組件
控制某個介面訪問頻率(次數)
查詢所有介面 同一個ip一分鐘只能訪問5次
使用步驟
1.寫一個頻率類 繼承SimpleRateThrottle
from rest_framework.throttling import BaseThrottle,SimpleRateThrottle
2.重寫get_cache_key方法 返回什麼 就以什麼做限制 先用ip
#客戶端的ip地址 從哪裡拿 HttpRequest.META里取
return request.META.get('REMOTE_ADDR')
3.配置一個類屬性
scope = 'lzy'
4.在配置文件中配置
'DEFAULT_THROTTLE_RATES': {
'lzy': '5/m',
},
5.局部使用和全局使用
局部:只在某個視圖類中使用【當前視圖類管理的所有介面都使用
】
throttle_classes = [CommonThrottle]
全局:全局所有介面都生效
'DEFAULT_THROTTLE_CLASSES': ['app01.throttling.CommonThrottle'],
局部禁用:
throttle_classes = []
過濾排序
必須繼承GenericAPIView及其子類才能使用這種方式
只有查所有才用到過濾
內置過濾類的使用 繼承GenericAPIView
#查所有
class BooksView(ViewSetMixin,ListAPIView):
queryset = Books.objects.all()
serializer_class = BooksSerializers
#這樣就有過濾功能
filter_backends = [SearchFilter]
search_fields = ['name'] #按照名字模糊匹配 內置的 固定用法
search_fields = ['name','price'] #按照名字或價格模糊匹配 其中有一個是相同的都會被篩選出來
ulr = 127.0.0.1:8000/api/v1/books/?seach=書
使用第三方django-filter實現過濾
# 安裝:django-filter
#查所有
class BooksView(ViewSetMixin,ListAPIView):
queryset = Books.objects.all()
serializer_class = BooksSerializers
#這樣就有過濾功能
filter_backends = [DjangoFilterBackend]
filterset_fields = ['name'] #支持完整匹配 name=書
url = 127.0.0.1:8000/api/v1/books/?name=書2
url = 127.0.0.1:8000/api/v1/books/?name=書2&price=12
自己定製過濾類實現過濾
查詢價格大於100的書
url = http://127.0.0.1:8000/api/v1/books/?price_gt=100
1.定義一個過濾類 繼承BaseFilterBackend
from django_filters.rest_framework import DjangoFilterBackend
2.重寫filter_queryset方法
def filter_queryset(self,request, queryset, view):
price_gt = request.query_params.get('price_gt',None)
if price_gt:
qs=queryset.filter(price__gt=int(price_gt))
return qs
else:
return queryset
3.配置在視圖類
filter_backends = [CommentFilter]
'''可以定製多個 從左往右 依次執行'''
排序的使用
內置
from rest_framework.filters import OrderingFilter
filter_backends = [OrderingFilter,CommentFilter]
ordering_fields = ['price']
#按照價格排序
支持查詢的方法
http://127.0.0.1:8000/api/v1/books/?ordering=price
http://127.0.0.1:8000/api/v1/books/?ordering=-price
http://127.0.0.1:8000/api/v1/books/?ordering=-id,pric
分頁
只有查詢才有分頁
drf內置了三個分頁器 之前的東西一樣用
第一種:PageNumberPagination
from rest_framework.pagination import LimitOffsetPagination,CursorPagination,PageNumberPagination
class CommonPageNumberPagination(PageNumberPagination):
page_size = 1 #每頁顯示兩條
page_query_param = 'page' #page=10 查詢第10也的數據
page_size_query_param = 'size' # page=10&size=5 查詢第十頁 每頁顯示5條
max_page_size = 10 #每頁最大的顯示條數
#配置在試圖頁即可
pagination_class = CommonCursorPagination
第二種:LimitOffsetPagination
from rest_framework.pagination import LimitOffsetPagination,CursorPagination,PageNumberPagination
class CommonPageNumberPagination(LimitOffsetPagination):
default_limit = 3 #每頁顯示3條
limit_query_param = 'limit' #limit=3
offset_query_param = 'offset' #offset=1 從第一個位置開始 取limit條
max_limit = 5
#配置在試圖頁即可
pagination_class = CommonCursorPagination
app用
class CommonPageNumberPagination(CursorPagination):
cursor_query_param = 'cursor' #查詢參數
page_size = 2 #每頁多少條
ordering = 'id' #排序欄位
#配置在試圖頁即可
pagination_class = CommonCursorPagination
#游標分頁 只能下一頁 上一頁 不能跳到中間 但他的效率最高 大數據量分頁 使用這種較好