ModelViewSet+ModelSerializer使用

ModelViewSet+ModelSerializer使用[Python基础]

1.DRF初始化

  • DRF框架的8个核心功能

1.认证(用户登录校验用户名密码或者token是否合法)

2.权限(根据不同的用户角色,可以操作不同的表)

3.限流(限制接口访问速度)

4.序列化(返回json)

5.分页

6.版本(接口版本号,用 v1/v2/v3)

# api.example.com/v1/login # 只有用户名密码登录

# api.example.com/v2/login # 手机号,微信 登录

7.过滤(username=zhangsan)

8.排序(ordering=-id)

  • 相关包

"""1.序列化相关"""

serializer

ModelSerializer

"""2.DRF视图函数继承"""

APIView

ModelViewSet

1.1 安装DjangoRestFramework

pip install djangorestframework==3.11.1

pip install django-filter==2.3.0 # 过滤器

pip install markdown # Markdown support for the browsable API.

1.2 在settings.py中注册

INSTALLED_APPS = [

"django_filters",

"rest_framework",

]

1.3 settings.py配置DRF(全局)

REST_FRAMEWORK = {

# 文档报错: AttributeError: ‘AutoSchema’ object has no attribute ‘get_link’

# 用下面的设置可以解决

"DEFAULT_SCHEMA_CLASS": "rest_framework.schemas.AutoSchema",

# 默认设置是:

# "DEFAULT_SCHEMA_CLASS": "rest_framework.schemas.openapi.AutoSchema",

# 异常处理器

# "EXCEPTION_HANDLER": "user.utils.exception_handler",

# Base API policies

"DEFAULT_RENDERER_CLASSES": [

"rest_framework.renderers.JSONRenderer",

"rest_framework.renderers.BrowsableAPIRenderer",

],

"DEFAULT_PARSER_CLASSES": [

"rest_framework.parsers.JSONParser",

"rest_framework.parsers.FormParser",

"rest_framework.parsers.MultiPartParser"

],

# 1.认证器(全局):用户登录校验用户名密码或者token是否合法

"DEFAULT_AUTHENTICATION_CLASSES": [

"rest_framework_jwt.authentication.JSONWebTokenAuthentication", # 在DRF中配置JWT认证

# "rest_framework.authentication.SessionAuthentication", # 使用session时的认证器

# "rest_framework.authentication.BasicAuthentication" # 提交表单时的认证器

],

#2.权限配置(全局): 顺序靠上的严格(根据不同的用户角色,可以操作不同的表)

"DEFAULT_PERMISSION_CLASSES": [

# "rest_framework.permissions.IsAdminUser", # 管理员可以访问

# "rest_framework.permissions.IsAuthenticated", # 认证用户可以访问

# "rest_framework.permissions.IsAuthenticatedOrReadOnly", # 认证用户可以访问, 否则只能读取

# "rest_framework.permissions.AllowAny", # 所有用户都可以访问

# "user.utils.VipPermission", #自定义权限

],

#3.限流(防爬虫)

"DEFAULT_THROTTLE_CLASSES": [

"rest_framework.throttling.AnonRateThrottle",

"rest_framework.throttling.UserRateThrottle",

],

#3.1限流策略

# "DEFAULT_THROTTLE_RATES": {

# "user": "100/hour", # 认证用户每小时100次

# "anon": "10/day", # 未认证用户每天能访问3次

# },

"DEFAULT_CONTENT_NEGOTIATION_CLASS": "rest_framework.negotiation.DefaultContentNegotiation",

"DEFAULT_METADATA_CLASS": "rest_framework.metadata.SimpleMetadata",

"DEFAULT_VERSIONING_CLASS": None,

#4.分页(全局):全局分页器, 例如 省市区的数据自定义分页器, 不需要分页

"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",

# 每页返回数量

# "PAGE_SIZE": 3, # 默认 None

#5.过滤器后端

"DEFAULT_FILTER_BACKENDS": [

"django_filters.rest_framework.DjangoFilterBackend",

# "django_filters.rest_framework.backends.DjangoFilterBackend", 包路径有变化

"rest_framework.filters.OrderingFilter",

],

#5.1过滤排序(全局):Filtering 过滤排序

# "SEARCH_PARAM": "search",

# "ORDERING_PARAM": "ordering",

#

# "NUM_PROXIES": None,

#6.版本控制:Versioning 接口版本控制

"DEFAULT_VERSION": None,

"ALLOWED_VERSIONS": None,

"VERSION_PARAM": "version",

# Authentication 认证

# 未认证用户使用的用户类型

"UNAUTHENTICATED_USER": "django.contrib.auth.models.AnonymousUser",

# 未认证用户使用的Token值

"UNAUTHENTICATED_TOKEN": None,

# View configuration

"VIEW_NAME_FUNCTION": "rest_framework.views.get_view_name",

"VIEW_DESCRIPTION_FUNCTION": "rest_framework.views.get_view_description",

"NON_FIELD_ERRORS_KEY": "non_field_errors",

# Testing

"TEST_REQUEST_RENDERER_CLASSES": [

"rest_framework.renderers.MultiPartRenderer",

"rest_framework.renderers.JSONRenderer"

],

"TEST_REQUEST_DEFAULT_FORMAT": "multipart",

# Hyperlink settings

"URL_FORMAT_OVERRIDE": "format",

"FORMAT_SUFFIX_KWARG": "format",

"URL_FIELD_NAME": "url",

# Encoding

"UNICODE_JSON": True,

"COMPACT_JSON": True,

"STRICT_JSON": True,

"COERCE_DECIMAL_TO_STRING": True,

"UPLOADED_FILES_USE_URL": True,

# Browseable API

"HTML_SELECT_CUTOFF": 1000,

"HTML_SELECT_CUTOFF_TEXT": "More than {count} items...",

# Schemas

"SCHEMA_COERCE_PATH_PK": True,

"SCHEMA_COERCE_METHOD_NAMES": {

"retrieve": "read",

"destroy": "delete"

},

}

settings.py

2.代码实践

from django.urls import include, path

from user import views

from rest_framework.routers import SimpleRouter, DefaultRouter

# 自动生成路由方法, 必须使用视图集

# router = SimpleRouter() # 没有根路由 /user/ 无法识别

router = DefaultRouter() # 1.有根路由

router.register(r"user", views.UserViewSet) # 2.配置路由

urlpatterns = [

path("index/", views.index),

path("api-auth/", include("rest_framework.urls", namespace="rest_framework")) # 认证地址

]

urlpatterns += router.urls # 3.模块地址

user/urls.py

from django.http import HttpResponse

from django_filters.rest_framework import DjangoFilterBackend

from rest_framework import viewsets

from rest_framework.authentication import BasicAuthentication, SessionAuthentication

from rest_framework.decorators import action

from rest_framework.filters import OrderingFilter

from rest_framework.permissions import AllowAny, IsAdminUser, IsAuthenticated, IsAuthenticatedOrReadOnly

from rest_framework.response import Response

from rest_framework.throttling import UserRateThrottle

from rest_framework.pagination import PageNumberPagination

from rest_framework.views import APIView

from rest_framework.permissions import BasePermission, SAFE_METHODS

from user.models import User

from user.serializers import UserSerializer, UserUnActiveSerializer

# 分页(局部):自定义分页器 局部

class PageNum(PageNumberPagination):

# 查询字符串中代表每页返回数据数量的参数名, 默认值: None

page_size_query_param = "page_size"

# 查询字符串中代表页码的参数名, 有默认值: page

# page_query_param = "page"

# 一页中最多的结果条数

max_page_size = 2

# 自定义权限(局部)

class MyPermission(BasePermission):

# has_permission 是用户对这个视图有没有 GET POST PUT PATCH DELETE 权限的分别判断

def has_permission(self, request, view):

print("has_perm")

# print(view.kwargs.get("pk"), request.user.id)

"""判断用户对模型有没有访问权"""

# 任何用户对使用此权限类的视图都有访问权限

if request.user.is_superuser:

# 管理员对用户模型有访问权

return True

elif view.kwargs.get("pk") == str(request.user.id):

# 携带的id和用户的id相同时有访问权

return True

return False

# has_object_permission 是用户过了 has_permission 判断有权限以后,再判断这个用户有没有对一个具体的对象有没有操作权限

# 这样设置以后,即使是django admin管理员也只能查询自己user标的信息,不能查询其他用户的单条信息

def has_object_permission(self, request, view, obj):

print("has_object_perm")

"""获取单个数据时,判断用户对某个数据对象是否有访问权限"""

if request.user.id == obj.id:

return True

return False

class UserViewSet(viewsets.ModelViewSet):

"""

完成产品的增删改查

"""

queryset = User.objects.all()

serializer_class = UserSerializer # 优先使用 get_serializer_class 返回的序列化器

# # 1.认证:自定义认证类, 自定义会覆盖全局配置

# authentication_classes = (BasicAuthentication, SessionAuthentication)

# # 2.权限:自定义权限类

# permission_classes = (MyPermission,)

# 3.分页:自定义分页器 覆盖全局配置

pagination_class = PageNum

# 4.限流:自定义限流类

throttle_classes = [UserRateThrottle]

# 5.过滤:指定过滤方法类, 排序方法类, 一个或多个

filter_backends = (DjangoFilterBackend, OrderingFilter) # 同时支持过滤和排序

# 5.1指定排序字段, 不设置, 排序功能不起效

ordering_fields = ("date_joined", "id") # ?ordering=-id

# 5.2指定过滤字段, 不设置, 过滤功能不起效

filter_fields = ("username", "phone", "is_active") # ?username=tom&phone=&is_active=true

# 根据不同的请求, 获得不同的序列化器

def get_serializer_class(self):

if self.action == "unactived":

return UserUnActiveSerializer

else:

return UserSerializer

@action(methods=["get"], detail=False)

def unactived(self, request, *args, **kwargs):

# 获取查询集, 过滤出未激活的用户

qs = self.queryset.filter(is_active=False)

# 使用序列化器, 序列化查询集, 并且是

ser = self.get_serializer(qs, many=True)

return Response(ser.data)

@action(methods=["get"], detail=False)

def actived(self, request, *args, **kwargs):

# 获取查询集, 过滤出未激活的用户

qs = self.queryset.filter(is_active=True)

# 使用序列化器, 序列化查询集, 并且是

ser = self.get_serializer(qs, many=True)

return Response(ser.data)

user/views.py

from rest_framework import serializers

from user.models import User

def address_validate(data):

# data:是用户提交的地址这个字段的数据(河南省 郑州市)

# 独立校验器

# raise serializers.ValidationError("请填写实际地址") # 有错就抛出异常

# 没错就返回数据

return data

class UserSerializer(serializers.ModelSerializer):

# 1.独立校验器:重新设定字段, 替换掉模型中的设定, 重新设定地址的长度为5

# address_validate是自定义的数据校验函数

address = serializers.CharField(max_length=255, min_length=5, validators=[address_validate])

# 2.单一字段验证(validate_字段名), 验证地址

def validate_address(self, data):

if data == "测试":

raise serializers.ValidationError("请填写实际地址") # 有错就抛出异常

return data # 没错就返回结果

def validate_phone(self, data):

# 不符合手机号格式

# raise serializers.ValidationError("手机号格式不正确")

model = self.root.Meta.model

num = model.objects.filter(phone=data).count()

if num > 0:

raise serializers.ValidationError("手机号已存在")

return data

# 3.所有属性验证器

def validate(self, attrs):

# attrs:{"username":"zhangsan", "phone":"18538752511", ....}

# 所有属性验证器

# self.context 中有request和view上下文

# self.context["view"].action 可以取到动作

# attrs 是需要序列化的数据

# raise serializers.ValidationError("xxx错误") # 有问题报错

return attrs # 没问题返回数据

class Meta:

model = User # 具体对哪个表进行序列化

fields = "__all__"# 所有字段

# fields = ("id", ) # 临时添加字段也需要写在这里

# exclude = ["id"] # 排除 id 字段

# read_only_fields = ("",) # 指定字段为 read_only,

# depth = 1 # 深度(序列化外键字段,外键字段有几层就=于几)

class UserUnActiveSerializer(serializers.ModelSerializer):

class Meta:

model = User

fields = ("id", "username", "is_active") # 临时添加字段也需要写在这里

# fields = "__all__" # 所有字段

user/serializers.py

3.postman测试接口

  • 查询路由

#1.查询所有用户

http://192.168.56.100:8888/user/user/

#2.查询id=1的用户

http://192.168.56.100:8888/user/user/1/

#3.查询 用户名(tom),激活的用户

http://192.168.56.100:8888/user/user/?username=tom&phone=&is_active=true

#4.查询所有用户 用id 反向排序

http://192.168.56.100:8888/user/user/?ordering=-id

#5.查询用户表中第一页,每页显示一条数据

http://192.168.56.100:8888/user/user/?page=1&page_size=1

  • 增加(POST)

http://192.168.56.100:8888/user/user/

  • 修改(PUT)

http://192.168.56.100:8888/user/user/1/

  • 删除(DELETE)

http://192.168.56.100:8888/user/user/1/

以上是 ModelViewSet+ModelSerializer使用 的全部内容, 来源链接: utcz.com/z/537917.html

回到顶部