django rest framework
ViewSets
基础
class UserViewSet(viewsets.ViewSet):
from rest_framework import mixins
from rest_framework import viewsets
class MyViewSet(mixins.RetrieveModelMixin,
viewsets.GenericViewSet)
添加额外接口 Marking extra actions for routing
from rest_framework.decorators import action
@action(detail=True, methods=["post"], url_path='customer')
def set_password(self, request):
return
url_path
action对应的url, 默认为函数名称
def decorator(func):
...
func.url_path = url_path if url_path else func.__name__
func.url_name = url_name if url_name else func.__name__.replace('_', '-')
...
return decorator
@action(detail=True, methods=["GET"],
url_path="parameters/(?P<my_pk>[^/.]+)")
def parameters(self, request, *args, **kwargs):
print(kwargs["my_pk"])
ViewSet actions
通过self.action可以知道当前的请求的状态,根据这个状态来判断不同的序列化类
list|create|retrieve|update|partial_update|destroy
class Permission(BasePermission):
def has_permission(self, request, view):
if view.action == "destroy": # ViewSet才有action这个属性,不可用于APIView
return False
from rest_framework import viewsets
from rest_framework import mixins
class APIViewSet(mixins.CreateModalMixin, GenericViewSet):
def get_serializer_class(self):
if self.action == 'create':
return CreateSerializerClass
return self.serializer_class
def create(self, request):
def retrieve(self, request, pk=None):
Routers
from rest_framework import routers
router = routers.DefaultRouter()
router.register(r'model', ModelViewSet)
urlpatterns = router.urls
ModelSerializer
Validators
def f(x):
if x % 2 != 0:
raise serializers.ValidationError(f"{x} is not an even number")
class Greater:
def __init__(self, base):
self.base = base
def __call__(self, value):
if value < self.base:
raise serializers.ValidationError(f"{value} is too small')
field_name = models.Integer(Field validators=[f, Greater(4)])
Authentication
TokenAuthentication
安装
INSTALLED_APPS = [
...
"rest_framework.authtoken",
]
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": [
"rest_framework.authentication.BasicAuthentication",
"rest_framework.authentication.SessionAuthentication",
"rest_framework.authentication.TokenAuthentication",
]
}
Permissions权限
自定义Permission
from rest_framework.permissions import BasePermission
class MyPermission(BasePermission):
def has_permission(self, request, view):
...
def has_object_permission(self, request, view, obj):
...
可以return False 这样 response就是 {"detail": "您没有..权限"}
或者 raise PermissionDenied({"message": "账户过期"})
[ ] permission支持逻辑上的and, or, not操作
AllowAny 这个没啥用, 因为你可以直接设置成为
permission_classes=[]. 但是用了他你可以显式地生命这个view是allowany的IsAuthenticated
return bool(request.user and request.user.is_authenticated)
IsAdminUser
return bool(request.user and request.user.is_staff)
IsAuthenticatedOrReadOnly
return bool(
request.method in SAFE_METHODS or
request.user and request.user.is_authenticated
)
[ ] djangorestframework可以和django的permission结合
Filter过滤
Pagination
from rest_framework.pagination import PageNumberPagination
class MyPageNumberPagination(PageNumberPagination):
page_size = 20
request and response
throtte限速 官网
```
from rest_framework.throttling import BaseThrottle, ScopedRateThrottle
class MyThrottle(BaseThrottle):
def allow_request(self, request, view):
return True or False
def wait(self):
return 50
```
* ScopedRateThrottle:
1. view 里面加入属性 throttle_scope = "自己定义一个scope, 同一个scope共享throlle"
2. settings 里面添加这个scop的条数限制
基础
from rest_framework import permissions
class IsOwner(permissions.BasePermission):
def has_permission(self, request, view):
return True # 这个一定会执行
def has_object_permission(self, request, view, obj):
return job.user == request.user # 这个要调用self.chech
class View(GenericAPIView):
permission_classes = (IsOwner,)
def post(self, request):
self.check_object_permissions(request, obj)
Exceptions
rest_framework.exceptions.ValidationErrorrest_framework.exceptions.PermissionDeniedraise rest_framework.exceptions.Throttled(second):raise Throttled(30)
Testing
APIClient
from rest_framework.test import APIClient
client = APIClient()
res = client.post("/notes/", {"title": "new idea"}, format="json")
self.assertEqual(res.status_code, 201)
self.assertEqual(res.json()["id"], 1)
Settings
默认配置
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
'rest_framework.authentication.BasicAuthentication',
# 'rest_framework.authentication.SessionAuthentication',
"rest_extensions.authentication.SessionAuthentication",
),
"DEFAULT_RENDERER_CLASS": {
"rest_framework.renderers.JSONRenderer",
"rest_framework.renderers.TemplateHTMLRenderer",
"rest_framework.renderers.BrowsableAPIRenderer",
},
'DEFAULT_FILTER_BACKENDS': (
'django_filters.rest_framework.DjangoFilterBackend',
'rest_framework.filters.OrderingFilter',
'rest_framework.filters.SearchFilter', # 需要在viewset设置了search_fields才会生效哦
),
"DEFAULT_PERMISSION_CLASSES": (
"rest_framework.permissions.IsAuthenticated",
),
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
"PAGE_SIZE": 10,
}