drf
pip install rest_framework
# 官方文档: https://q1mi.github.io/Django-REST-framework-documentation/api-guide/viewsets_zh/#readonlymodelviewset
前提条件 models.py ,views.py ,urls.py(应用模块中的 ,django项目中的) ,settings.py已经配置好了
from django.db import models
class BookInfo(models.Model):
title = models.CharField(max_length=50)
reader = models.IntegerField()
def __str__(self):
return self.title
class Meta:
db_table = "book"
class HeroInfo(models.Model):
name = models.CharField(max_length=50)
bookid = models.ForeignKey(BookInfo,on_delete=models.DO_NOTHING,related_name='bookinfo',db_constraint=False)
def __str__(self):
return self.name
class Meta:
db_table = 'hero'
'''
urls.py (django 项目同名文件夹下的)
'''
from django.contrib import admin
from django.urls import path,include
urlpatterns = [
path('admin/', admin.site.urls),
path('books/', include("books.urls")),
]
'''
urls.py (python manage.py startapp books 中的创建的 urls.py 文件夹)
'''
from books.views import home
from rest_framework.routers import DefaultRouter,SimpleRouter
urlpatterns = [
path('home/',home.BookInfoViewSet.as_view()),
]
#urlpatterns = [
# path('home/',home.BookInfoViewSet.as_view()),
#]
# 默认启动drf 自带的5条路由
# router = DefaultRouter() # 默认路由 get,post,put等增删改查路由
# router.register(
# 'books', home.BookInfoViewSet
# )
# urlpatterns += router.urls
'''
settings.py
'''
# 配置app 应用
INSTALLED_APPS = [
···
'rest_framework',
"books",
···
]
# 配置 mysql数据库
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': '数据库名字',
'HOST': 'localhost或者127.0.0.1',
"USER": "数据库登录账户",
'PASSWORD': '数据库登录密码',
"PORT": "端口号,一般都是3306",
}
}
'''
serializers.py
'''
from rest_framework import serializers
from books.models import BookInfo,HeroInfo #导入数据库模型,也就是你创建模块中的class类名
''' 序列化器的创建 '''
## 1.如果当前序列化器继承的是ModelSerializer,则需要字段转换声明
# 字段 = serializers.字段类型(选项 = 选项值 )
## 2. 如果当前序列化器继承的是ModelSerializer,则需要声明调用的模型信息
class Meta:
model = BookInfo # 必填
fields = ["id","title","reader"] # 必填 也可以是字符串和列表/元组,字符串的 值只能是"__all__"
exclued = [] # 排除,与 fields 互斥
read_only_fields = [] # 选填,只读字段列表,表示设置这里的字段只会在序列化阶段采用
extra_kwargs = { # 选填,字段额外选项声明
'字段':{
"选项":"选项值"
}
}
depth = 1 # 根据外键进行检索,数值时检索几层
## 3. 验证代码对象方法
def validate_<字段名>(self,value): # 局部数据验证
"""
局部数据验证 方法名必须是validate_<字段名> 为名称,否则序列化器不识别
会自动被is_valid() 方法调用
"""
pass
return value
def validate(self,attrs): # 全局数据验证
# 多个字段的逻辑判断
"""
验证来自客户端的所有数据
类似于会员注册的密码和确认密码,就是能在validate方法中验证
validate 是固定方法名
参数:attrs,是在序列化器实列化时的data选项数据
会自动被is_valid() 方法调用
"""
return attrs
# 还有一种验证方式 时 validators ,是在声明字段的一个选项,选项值是一个 list类型 [函数,函数...]
## 4. 模型操作方法
def update(self, instance, validated_data):
"""
添加数据操作 添加数据以后,就自动实现了从字典变成模型对象的过程
会自动被serializer.update() 或者 serializer.save()方法调用
"""
# '''修改数据'''
pass
return instance
def create(self, validated_data):
"""
会自动被serializer.create() 或者 serializer.save()方法调用
更新数据操作 更新数据以后,就自动实现了从字典变成模型对象的过程
"""
return pass
在应用模块中新建 serializers.py
'''
serializers.py
'''
from rest_framework import serializers
from books.models import BookInfo,HeroInfo #导入数据库模型,也就是你创建模块中的class类名
实例化序列化器 BookInfo1Serializer(instance=data)
BookInfo1Serializer :定义的序列化类
instance : 序列化类的参数 , 默认可以不写,为 BookInfo1Serializer(data)
data : 需要序列化的数据,放入 instance 参数中
serializers.py :
# 序列化器
class BookInfo1Serializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
title = serializers.CharField()
reader = serializers.CharField()
views.py :
from django.views import View
from django.http.response import JsonResponse
from rest_framework.viewsets import ModelViewSet
from books.serializers import BookInfo1Serializer,BookInfo2Serializer
from books.models import BookInfo
class BookInfoViewSet(View):
""" 使用django的View """
def get2(self, request):
"""序列化器, 单个"""
# 1. 获取数据源
instance = BookInfo.objects.first()
# 2. 获取序列化对象
serializer = BookInfo1Serializer(instance=instance)
# 3. 调用序列化器的data属性,获取转换之后的数据
data = serializer.data
# 4. 响应数据
return JsonResponse(data,status=200)
def get1(self,request):
"""序列化器,多个"""
# 1. 获取数据源
instance = BookInfo.objects.all()
# 1,获取序列化器实列化对象
serializer = BookInfo1Serializer(instanfe=instance,many=True) #many 设置能有多条数据,会在内部调用一个循环进行遍历 QuerySet对象 获取 id
# 3.调用序列化器对象的data属性方法获取转换后的数据
data = serializer.data
# 4.响应数据
return JsonResponse(data,status=200,safe=True) # safe 设置 对非字典对象装换成字典对象
books\urls.py :
from django.urls import path
from books.views import home
urlpatterns = [
path('home/',home.BookInfoViewSet.as_view()),
]
serializers.py :
# 反序列化器
class BookInfo2Serializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
title = serializers.CharField(max_length=20,required=True,error_messages={"allow_null":"the is not null"},allow_null=True)
reader = serializers.CharField(max_length=20)
def validate_title(self,value): #
"""
局部数据验证 方法名必须是validate_<字段名> 为名称,否则序列化器不识别
会自动被is_valid() 方法调用
"""
# print(value)
if value in ['python','django']:
raise serializers.ValidationError("题目不能包含django,python",code='validate_title')
return value
def validate(self, attrs):
# 观看python的人 等于100
if attrs['title'] =="长江七号" and int(attrs['reader']) <= 100:
raise serializers.ValidationError('长江七号观看的人太少了',code='validate')
return attrs
def create(self, validated_data):
data = BookInfo.objects.create(**validated_data)
return data
views.py :
from django.views import View
from django.http.response import JsonResponse
from rest_framework.viewsets import ModelViewSet
from books.serializers import BookInfo1Serializer,BookInfo2Serializer
from books.models import BookInfo
class BookInfoViewSet(View):
# 抛出异常
def get(self,request):
# 1. 接受用户的数据
# data = json.dumps(request.body)
# 模拟来自客户的数据
data = {
"title":"长江七号",
"reader":"110",
}
# 1.1 调用序列化进行数据验证
serializer = BookInfo2Serializer(data = data)
# 1.2 调用序列化器进行数据验证
ret = serializer.is_valid(raise_exception=True) # 抛出异常
# 1.3 获取验证以后的结果
return JsonResponse(dict(serializer.validated_data))
books\urls.py :
from django.urls import path
from books.views import home
urlpatterns = [
path('home/',home.BookInfoViewSet.as_view()),
]
serializers.py :
def create(self, validated_data):
data = BookInfo.objects.create(**validated_data)
return data
views.py :
def get(self,request): # 添加数据入库
# 1. 接受用户的数据
# data = json.dumps(request.body)
# 模拟来自客户的数据
data = {
"title":"长江七号2",
"reader":"110",
}
# 1.1 调用序列化进行数据验证
serializer = BookInfo2Serializer(data=data)
# 1.2 调用序列化器进行数据验证
ret = serializer.is_valid(raise_exception=True) # 抛出异常
# 2 获取验证以后的结果,操作数据库
serializer.save() # 会根据实例化序列器的说话,是否传入instance属性来自动调用create或者update方法,传入instance属性,自动调用updata方法。没有传入instance属性,自动调用create方法
return JsonResponse(serializer.data,status=201)
serializers.py :
def create(self, validated_data):
data = BookInfo.objects.create(**validated_data)
return data
views.py :
# 反序列化 更新数据
def get(self,request):
# 1. 根据客户端访问的url地址中,获取pk值
# books/home/2 path("/home/(?P<id>)\d+/",views.BookInfoViewSet.as_view()),
id = 6
try:
book = BookInfo.objects.get(id=id)
except Exception as e:
return JsonResponse({"errors":"该学生不存在"},status=404)
# 2. 模拟来自客户的数据
data = {
"title":"长江七号5",
"reader":"1000",
}
# 3. 修改操作中的实例化序列器对象
serializer = BookInfo2Serializer(instance=book,data=data)
# 4. 数据验证
serializer.is_valid(raise_exception=True)
# 5. 入库
serializer.save()
# 6. 数据返回
return JsonResponse(serializer.data)
ModelSerializer
继承自 Serializer
unique_together
验证程序。.create()``.update()
serializers.py :
# 模型序列化器
class BookInfoModelSerializer(serializers.ModelSerializer):
# 1. 声明字段
# 字段名 = serialzers.字段类型(选项 = 选项值)
# 也可以定义,模型里面没有的字段,需要额外声明字段
# nickname = serializers.CharField(read_only=True)
# 2. 声明模型
class Meta:
model = BookInfo # 必填
fields = ["id","title","reader"] # 必填 也可以是字符串和列表/元组,字符串的值只能是"__all__"
# exclued = [] # 排除,与 fields 互斥
# read_only_fields = [] # 选填,只读字段列表,表示设置这里的字段只会在序列化阶段采用
# extra_kwargs = { # 选填,字段额外选项声明
# '字段':{
# "选项":"选项值"
# }
# }
extra_kwargs = { # 选填,字段额外选项声明
'reader': {
"required": False,
"error_messages": {
"required": "reader字段不能为空"
}
},
}
# 3. 验证代码的对象方法
# def create(self, validated_data):
# 密码加密
# validated_data["password"] = make_password(validated_data["password"])
# super().create(validated_data)
# 4. 模型操作方法
books\urls.py
urlpatterns = [
...
path('homeModel/', home.BookInfoViewSet1.as_view()), # 模型序列化器视图API
]
views.py:
# 模型化序列化器 Api
class BookInfoViewSet1(View):
""" 使用django的View """
"""序列化器,单个"""
def get1(self, request):
# 1. 获取数据源
instance = BookInfo.objects.first()
# 2. 获取序列化对象
serializer = BookInfoModelSerializer(instance=instance)
# 3. 调用序列化器的data属性,获取转换之后的数据
data = serializer.data
# 4. 响应数据
return JsonResponse(data,status=200)
"""序列化器,多个"""
def get2(self,request):
"""序列化器,多个"""
# 1. 获取数据源
instance = BookInfo.objects.all()
# 1,获取序列化器实列化对象
serializer = BookInfoModelSerializer(instance,many=True) #many 设置能有多条数据,会在内部调用一个循环进行遍历 QuerySet对象 获取 id
# 3.调用序列化器对象的data属性方法获取转换后的数据
data = serializer.data
# 4.响应数据
return JsonResponse(data,status=200,safe=False,json_dumps_params={'ensure_ascii':False}) # safe 设置 对非字典对象装换成字典对象
# 反序列化
def get3(self,request):
# 1. 接受用户的数据
# data = json.dumps(request.body)
# 模拟来自客户的数据
data = {
"title":"django",
"reader":"",
}
# 1.1 调用序列化进行数据验证
serializer = BookInfoModelSerializer(data = data)
# 1.2 调用序列化器进行数据验证
ret = serializer.is_valid() # 不抛出异常
# 1.3 获取验证以后的结果
if ret:
return JsonResponse(dict(serializer.validated_data),json_dumps_params={'ensure_ascii':False})
else:
return JsonResponse(dict(serializer.errors),json_dumps_params={'ensure_ascii':False})
# 2. 操作数据库
# 抛出异常
def get4(self,request):
# 1. 接受用户的数据
# data = json.dumps(request.body)
# 模拟来自客户的数据
data = {
"title":"长江七号",
"reader":"",
}
# 1.1 调用序列化进行数据验证
serializer = BookInfoModelSerializer(data = data)
# 1.2 调用序列化器进行数据验证
ret = serializer.is_valid(raise_exception=True) # 抛出异常
# 1.3 获取验证以后的结果
return JsonResponse(dict(serializer.validated_data))
# 2. 操作数据库
# 反序列化 添加数据
def get5(self,request):
# 1. 接受用户的数据
# data = json.dumps(request.body)
# 模拟来自客户的数据
data = {
"title":"长江七号2",
"reader":"110",
}
# 1.1 调用序列化进行数据验证
serializer = BookInfoModelSerializer(data=data)
# 1.2 调用序列化器进行数据验证
ret = serializer.is_valid(raise_exception=True) # 抛出异常
# 2 获取验证以后的结果,操作数据库
serializer.save()
return JsonResponse(serializer.data,status=201)
# 反序列化 更新数据
def get6(self,request):
# 1. 根据客户端访问的url地址中,获取pk值
# books/home/2 path("/home/(?P<id>)\d+/",views.BookInfoViewSet.as_view()),
id = 6
try:
book = BookInfo.objects.get(id=id)
except Exception as e:
return JsonResponse({"errors":"该学生不存在"},status=404)
# 2. 模拟来自客户的数据
data = {
"title":"长江七号71",
"reader":"1000",
}
# 3. 修改操作中的实例化序列器对象
serializer = BookInfoModelSerializer(instance=book,data=data)
# 4. 数据验证
serializer.is_valid(raise_exception=True)
# 5. 入库
serializer.save()
# 6. 数据返回
return JsonResponse(serializer.data)
1) 在序列化器进行save()
保存时,可以额外传递数据,这些数据再create()
和update()
中的validated_data参数获取到
# request.user 是django中记录当前登录用户的模型对象
serializer.save(owner = request.user) # 可以再save中,传递一些不需要验证的数据到模型里面
2)默认序列化器必须传递所有required的字段,否则会抛出验证异常但是我们可以使用partial 参数来允许部分字段更新
# Update "comment" with partial data
serializer = CommentSerializer(comment,data={'content':'foo bar'},partial=True)
数据来源与mysql
也就是模型的时候使用 Modelserializer
,否则就用serializer
drf除了在数据序列化部分见写代码以外,还在视图中提供了简写操作。所以django原有的django.views.View类基础上,drf封装了多个视图子类出来提供给我们使用。
Django REST framework 提供的视图主要作用:
内容协商:drf在django原有的基础上,新增一个request对象集成到了APIView视图类并在django原有的HttpResponse响应类的基础上实现了一个子类rest_framework.response.Response响应类。这两个类,都是基于内容协商来完成数据的格式转换。
换句话说:内容协商在客户端和服务端之间的数据通信的过程中,基于协议郑家数据格式的声明,方便对端 理解本端发送的数据格式和期望放回的数据格式。
创建一个子应用req
python manange.py startapp req
在django项目中文件夹下的urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path('books/', include("books.urls")), # 序列化器的学习
path("req/",include('req.urls')), # Http请求响应的学习
]
request->parser解析类->识别客户端请求头中的Content-Type来完成数据转换成->类字典(QueryDict,字典的子类)
response->renderer渲染类->识别客户端请求头的“Accept
”来提取客户端期望的返回数据格式->转换成客户端的期望格式数据
注册子应用
settings.py
INSTALLED_APPS = [
...
'rest_framework',
"books", # 序列化器的学习
"req", # Http请求响应
]
在req\views.py
from rest_framework.views import APIView
from rest_framework.response import Response
class BookInfoAPIView(APIView):
def get(self,request):
print(f"drf.request={request}")
# rest_framework.request.Request 是属于drf单独声明的请求处理对象,与django提供的HttpRequest不是同一个,甚至没有任何继承关系
print(f"django.request={request._request}") # 拿到django 的request
return Response({'msg': "ok"})
在创建子应用urls.py
req\urls.py
from django.urls import path
from req import views
urlpatterns = [
path("book/",views.BookInfoAPIView.as_view())
]
request.data
返回解析之后的请求体数据。类似于django中标准的request.POST
和 request.FILES
属性 ,但是提供如下特性:
POST
、PUT
、PATCH
请求方式解析后的数据REST framework
的parse
r解析器,不仅支持表单类型数据,也支持json数据查询参数,也叫查询字符串。
request.query_params 与django标准request.GET 相同,只是更换了正确的名字而已。
获取django封装的Request对象
使用Postman进行接口传参
views.py
:
def get(self, request):
print(f"drf.request={request}") # rest_framework.request.Request 是属于drf单独声明的请求处理对象,与django提供的HttpRequest不是同一个,甚至没有任何继承关系
print(f"django.request={request._request}") # 拿到django 的request
return Response({'msg': "ok"})
def post(self, request):
from rest_framework import status
# 添加数据
"""获取请求体数据"""
# 获取表单提交的数据
print(f"request.data={request.data}") # 接受的数据已经被Parse解析器转换成字典数据了
# 用户传输的json数据 request.data=<QueryDict: {'name': ['1310832212'], 'password': ['123456'], 'Type': ['1']}>
# 获取地址连提交的数据 也就是get 提交的数据
print(f"request.query_params{request.query_params}")
# 地址栏数据 request.query_params<QueryDict: {'mat': ['123']}>
return Response({'msg': "ok"},status=status.HTTP_201_CREATED
drf 的 response 时django HttpResponse 的子类
REST framework
提供了一个响应类Response
,使用该类构造响应对象时,响应的具体数据会被转移(renderer
渲染器)成符合前端需求的类型。
REST framework
提供了Renderer
渲染器,用来根据请求头中的Accept
(接受数据类型声明)来自懂转换响应数据到对应格式。如果前端请求中未声明Accept
,则会采用Content-Type
方式处理响应数据,我们可以通过配置来修改默认响应格式。
可以在rest_framework.settings
查看所有的drf
默认配置项
"""
ctrl+鼠标左键 点击 drf的 Response 进入 rest_framework.settings
"""
DEFAULTS = {
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer', # json数据格式,无界面
'rest_framework.renderers.BrowsableAPIRenderer', # 默认响应的api界面
],
...
}
Response(data,status=None,template_name=None,headers=None,content_type=None)
"""
data:响应序列化处理后的数据
status:响应的状态码,如200,201... 可导入 from rest_framework import status 状态码常量文件
template_name:响应的模板,只是对默认的api模板进行改造
headers:自定应响应请求头
content_type:规定parser解析器解析的数据格式,如conten_type:"json" 解析成的数据就是json
"""
工作中很少用
(1).data
获取传给response对象的序列化后,但尚未render处理的数据
(2).status_code
获取状态码的数字
(3).content
获取经过render处理后的响应数据
Django REST framework 提供的视图主要作用
rest_framework.views.APIView
APIView
类在以下方面与常规类不同:View
Request``HttpRequest
response
对象 ,而不是 Django 的 。视图会响应数据设置(renderer)符合前端要求的格式APIException
drf的APIView或者APIView的子类会自动根据客户端的Accept进行错误信息的格式转换
重新声明一个新的as_view方法并在dispatch()进行路由分发前,会对请求的客户端进行身份认证,权限检查,流量控制。
APIView
除了继承了View原有的属性方法意外,害新增了类属性:
在APIView
中仍以常规的类视图方法来实现get()、post()或者其他请求方式的方法。
创建子应用模块
python manage.py startapp dome_views
注册子应用模块settings.py
INSTALLED_APPS = [
...
'rest_framework',
"books", # 序列化器的学习
"req", # Http请求响应
]
创建序列化器 dome_views\serializers.py
from rest_framework import serializers
from books.models import BookInfo
class BookInfoSerializers(serializers.ModelSerializer):
class Meta:
model = BookInfo
fields = "__all__"
django同名文件夹下 urls.py
:
urlpatterns = [
...
path("dome_views/",include('dome_views.urls')) # 视图学习
]
dome_views\views.py
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response
from books.models import BookInfo
from .serializers import BookInfoSerializers
"""
get 获取所有数据
post 新增一条数据
get 查看详情
put 修改数据
delete 删除数据
"""
class BookViewSerializer(APIView):
def get(self,request):
# 1. 获取数据
data = BookInfo.objects.all()
# 2. 实例化序列化器
serializer = BookInfoSerializers(data,many=True)
# 3. 返回数据
return Response(serializer.data)
def post(self,request):
# 1. 获取用户提交的数据
data = request.data
# 2. 实例化序列化器
serializer = BookInfoSerializers(data = data)
# 3. 验证数据,保存数据
serializer.is_valid(raise_exception=True)
serializer.save()
# 4. 返回数据
return Response({"msg":"添加成功"},status=status.HTTP_201_CREATED)
class BookInfoViewserializer(APIView):
def get(self,request,id):
# 1. 根据id获取模型对象数据
try:
book = BookInfo.objects.get(id=id)
except BookInfo.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
# 2. 实例化序列器
serializer = BookInfoSerializers(book)
# 3. 返回数据
return Response(serializer.data)
def put(self,request,id):
# 1. 根据id 获取模型对象
try:
book = BookInfo.objects.get(id=id)
except BookInfo.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
# 2. 获取用户提交的数据
data = request.data
# 3. 实例化序列化器
serializer = BookInfoSerializers(instance=book,data=data)
# 4. 验证数据,保存数据
serializer.is_valid(raise_exception=True)
serializer.save()
# 5. 返回数据
return Response(serializer.data,status=status.HTTP_201_CREATED)
def delete(self,request,id):
# 1. 根据id 获取模型对象
try:
BookInfo.objects.get(id=id).delete()
except BookInfo.DoesNotExist:
pass
return Response({"msg":"删除成功"},status=status.HTTP_204_NO_CONTENT)
dome_views\urls.py
from django.urls import re_path
from rest_framework.urls import path
from . import views
urlpatterns = [
path("book/",views.BookViewSerializer.as_view()),
re_path("^bookinfo/(?P<id>\d+)/$",views.BookInfoViewserializer.as_view())
]
通用视图类主要作用就是把视图中的独特的代码抽取出来,让视图方法中的代码更加的通用,方便把通用代码进行简写
rest_framework.generice.GenericAPIView
继承自APIView
,主要增加了操作序列化器和数据库查询的方法,作用时为下面Mixin
扩展类的执行提供方法支持。通常在使用时,可以搭配一个或多个Mixin扩展类。
提供的关于序列化器使用的属性与方法
属性
serializer_class 指明视图使用的序列化器
方法
get_serializer_class(self)
当出现一个视图类中调用多个序列化器时,那么可以通过条件判断在get_serializer_class方法中通过返回不同的序列化器类名就可以让视图方法执行不同的序列化器对象了。
返回序列化器,默认返回serializer_class,可以重写,例如:
例子:
```python class BookInfo2ViewSerializer(GenericAPIView): queryset = BookInfo.objects.all() # 指定数据集
# 一个视图类中,单个序列化器
# serializer_class = BookInfoSerializers
# 一个视图类中,多个序列化器
def get_serializer_class(self):
# 如果是 put 请求 返回 BookInfoSerializer1 ,否则 返回 BookInfoSerializer2
if self.request.mothed.lower() == "put":
return BookInfoSerializer1
else:
return BookInfoSerializer2
``` - get_serializer(self,args,*kwargs)
返回序列化器对象,主要用来提供给Mixin扩展类使用,如果我们在视图中想要获取序列化器对象,也可以直接调用此方法。
注意:该方法在提供序列化器对象的时候,会向序列化器独享的context属性补充三个数据:**request**、**format**、**view**、这三个数据对象可以在定义序列化器时使用。
- **request** 当前视图的请求对象
- **view ** 当前请求的类试图对象
- **format ** 当前i请求期望返回的数据格式
提供的关于数据库查询的属性与方法
属性
queryset 指明使用的数据查询集
方法
get_queryset(self)
返回视图使用的查询集,主要用来提供Mixin扩展类使用,是列表视图与详情视图获取数据的基础,默认返回queryset属性,可以重写,例如:
python
from rest_framework.generics import GenericAPIView
class Book2ViewSerializer(GenericAPIView):
queryset = BookInfo.objects.all() # 指明使用的数据查询集
serializer_class = BookInfoSerializers
def get(self,request):
# 1. 获取模型所有数据
books = self.get_queryset() ######## get_queryset(self)
# 2. 实列化序列器
serializer = self.get_serializer(books,many=True)
# 3. 返回结果
return Response(serializer.data)
get_object(self)
返回详情视图所需的模型类数据对象,主要用来提供给Mixin扩展类使用。在试图中可以调用该方法获取详情信息的模型类对象。
若详情访问的模型类对象不存在,会返回404。
该方法会默认使用APIView提供的check_object permissions方法检查当前对象是否有权限被访问。举例:
当参数为pk的时候才能使用get_object()方法 , 因为参数pk已经是在源码里面内置了,所以只能是pk
注意:urls.py
: 获取的参数也必须是pk,不让会报错,大概就是路由参数和视图类的参数不同,例如:
re_path("^bookinfo2/(?P
```python class BookInfo2ViewSerializer(GenericAPIView): queryset = BookInfo.objects.all() serializer_class = BookInfoSerializers """查询一个数据详情""" def get(self,request,pk): # 1. 通过id获取模型数据
# instance = self.get_queryset().get(id=pk)
# self.get_queryset().get(id=pk) === instance = self.get_object()
instance = self.get_object()
# 当参数为pk的时候才能使用get_object()方法 , 因为参数pk已经是在源码里面内置了,所以只能是pk
# 2. 实例化序列化器
serializer = self.get_serializer(instance)
# 3. 返回数据
return Response(serializer.data)
```
其他可以设置的属性
实列:
dome_views
/urls.py
:
from django.urls import re_path
from rest_framework.urls import path
from . import views
urlpatterns = [
# 基本是图类 APIView
....
# 通用视图类 GenericAPIView
path('book2/',views.Book2ViewSerializer.as_view()),
re_path("^bookinfo2/(?P<pk>\d+)/$",views.BookInfo2ViewSerializer.as_view())
]
dome_views
/views.py
:
""" 通用视图类 GenericAPIView"""
from rest_framework.generics import GenericAPIView
class Book2ViewSerializer(GenericAPIView):
queryset = BookInfo.objects.all() # 指明使用的数据查询集
serializer_class = BookInfoSerializers
def get(self,request):
# 1. 获取模型所有数据
books = self.get_queryset()
# 2. 实列化序列器
serializer = self.get_serializer(books,many=True)
# 3. 返回结果
return Response(serializer.data)
def post(self,request):
# 1. 获取用户提交的数据
data = request.data
# 2. 实例化序列化器
serializer = self.get_serializer(data=data)
# 3. 验证数据,保存数据
serializer.is_valid(raise_exception=True)
serializer.save()
# 4. 返回数据
return Response(serializer.data,status=status.HTTP_201_CREATED)
class BookInfo2ViewSerializer(GenericAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializers
"""查询一个数据"""
def get(self,request,pk):
# 1. 通过id获取模型数据
# instance = self.get_queryset().get(id=pk) # self.get_queryset().get(id=pk) === instance = self.get_object()
instance = self.get_object() # 当参数为pk的时候才能使用get_object()方法 , 因为参数pk已经是在源码里面内置了,所以只能是pk
# 2. 实例化序列化器
serializer = self.get_serializer(instance)
# 3. 返回数据
return Response(serializer.data)
def put(self,request,pk):
# 1. 获取用户输入的数据
data = request.data
# 2. 通过id获取模型数据
# instance = self.get_queryset().get(id=pk)
instance = self.get_object()
# 3. 实例化序列化器
serializer = self.get_serializer(instance=instance ,data=data)
# 4. 验证数据,保存数据
serializer.is_valid(raise_exception=True)
serializer.save()
# 5. 返回结果
return Response(serializer.data,status=status.HTTP_201_CREATED)
def delete(self,request,pk):
# 1. 通过id 删除数据
# self.get_queryset().get(id=id).delete()
instance = self.get_object()
# 2. 返回结果
return Response(status=status.HTTP_204_NO_CONTENT)
也叫混入类。
作用: 提供了几种后端视图(对数据资源进行增删改查)处理流程的实现,如果需要编写的视图属于这五种,则视图可以通过继承相应的扩展类来复用代码,减少自己编写的代码量。
这五个扩展类需要搭配GenericAPIMView通用视图基类,因为五个扩展类的实现需要调用GenericAPIView提供的序列化器与数据库查询的方法。
提供一个 .list(request, *args, **kwargs)
方法,实现列出结果集。
如果查询集被填充了数据,则返回 200 OK
响应,将查询集的序列化表示作为响应的主体。相应数据可以任意分页。
实例:
from rest_framework.mixins import ListModelMixin
class BookMixinSerializer(GenericAPIView,ListModelMixin):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializers
""" 查询所有数据 """
def get(self,request):
return self.list(request) # 可以进行查看源代码
提供 .create(request, *args, **kwargs)
方法,实现创建和保存一个新的model实例。
如果创建了一个对象,这将返回一个 201 Created
响应,将该对象的序列化表示作为响应的主体。如果序列化的表示中包含名为 url
的键,则响应的 Location
头将填充该值。
如果为创建对象提供的请求数据无效,将返回 400 Bad Request
,其中错误详细信息作为响应的正文。
from rest_framework.mixins import CreateModelMixin
class BookMixinSerializer(GenericAPIView,CreateModelMixin):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializers
""" 添加一个数据 """
def post(self,request):
return self.create(request) # 可以进行查看源代码
提供一个 .retrieve(request, *args, **kwargs)
方法,实现返回响应中现有模型的实例。
如果可以检索对象,则返回 200 OK
响应,将该对象的序列化表示作为响应的主体。否则将返回 404 Not Found
。
from rest_framework.mixins import RetrieveModelMixin
class BookInfoMixinSerializer(GenericAPIView,RetrieveModelMixin):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializers
""" 查看详情 """
def get(self,request,pk):
return self.retrieve(request,pk)
提供 .update(request, *args, **kwargs)
方法,实现更新和保存现有模型实例。
同时还提供了一个 .partial_update(request, *args, **kwargs)
方法,这个方法和 update
方法类似,但更新的所有字段都是可选的。这允许支持 HTTP PATCH
请求。
如果一个对象被更新,这将返回一个 200 OK
响应,将对象的序列化表示作为响应的主体。
如果为更新对象提供的请求数据无效,将返回一个 400 Bad Request
响应,错误详细信息作为响应的正文。
from rest_framework.mixins import UpdateModelMixin
class BookInfoMixinSerializer(GenericAPIView,UpdateModelMixin):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializers
""" 更新数据 """
def put(self,request,pk):
return self.update(request,pk)
提供一个 .destroy(request, *args, **kwargs)
方法,实现删除现有模型实例。
如果删除对象,则返回 204 No Content
响应,否则返回 404 Not Found
。
from rest_framework.mixins import DestroyModelMixin
class BookInfoMixinSerializer(GenericAPIView,DestroyModelMixin):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializers
""" 删除数据 """
def delete(self,request,pk):
return self.destroy(request,pk)
完整代码:views.py
"""
使用drf内置的模型扩展类[混入类]结合GenericAPIView实现通用视图方法的简写操作
from rest_framework.mixins import ListModelMixin获取多条数据,返回响应结果 list
from rest_framework.mixins import CreateModelMixin添加一条数据,返回响应结果 create
from rest_framework.mixins import RetrieveModelMixin 获取一条数据,返回响应结果 retrieve
from rest_framework.mixins import UpdateModelMixin更新一条数据,返回响应结果 update(更新全部字段)和partial_update(更新单个或部分字段,例如修改密码,修改头像)
from rest framework.mixins import DestroyModelMixin 删除一条数据,返回响应结果 destroy
"""
from rest_framework.mixins import ListModelMixin,CreateModelMixin
class BookMixinSerializer(GenericAPIView,ListModelMixin,CreateModelMixin):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializers
""" 查询所有数据 """
def get(self,request):
return self.list(request) # 可以进行查看源代码
""" 添加一个数据 """
def post(self,request):
return self.create(request) # 可以进行查看源代码
from rest_framework.mixins import RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
class BookInfoMixinSerializer(GenericAPIView,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializers
""" 查看详情 """
def get(self,request,pk):
return self.retrieve(request,pk)
""" 更新数据 """
def put(self,request,pk):
return self.update(request,pk)
""" 删除数据 """
def delete(self,request,pk):
return self.destroy(request,pk)
urls.py
urlpatterns = [
...
# 扩展视图 Mixins + GenericAPIView
path("book3/",views.BookMixinSerializer.as_view()),
re_path("^bookinfo3/(?P<pk>\d+)/$",views.BookInfoMixinSerializer.as_view()),
...
]
上面的接口代码还可以继续更加的精简,drf在使用GenericAPIView
和Mixins
进行组合以后,还提供了视图子类。视图子类是通用视图类和模型扩展类的子类,提供了各种的视图方法调用mixins操作
组合视图子类:
只是在一个类里面封装了多个方法(可以看看源码)
dome_views/urls.py
urlpatterns = [
...
# 子类视图
path("book4/",views.BookModelView.as_view()),
re_path("^bookinfo4/(?P<pk>\d+)/$",views.BookInfoModelView.as_view())
]
dome_views/views.py
"""
上面的接口代码还可以继续更加的精简,dr f在使用GenericAPIView和Mixins进行组合以后,还提供了视图子类。
视图子类是通用视图类和模型扩展类的子类,提供了各种的视图方法调用mixins操作
ListAPIView = GenericAPIView + ListModelMixin 获取多条数据的视图方法
CreateAPIView = GenericAPIView + CreateModelMixin 添加一条数据的视图方法
RetrieveAPIView = GenericAPIView + RetrieveModelMixin 获取一条数据的视图方法
UpdateAPIView = GenericAPIView + UpdateModelMixin 更新一条数据的视图方法
DestroyAPIView = GenericAPIView + DestroyModelMixin 删除一条数据的视图方法组合视图子类
组合视图子类
ListCreateAPIView = ListAPIView + CreateAPIView
RetrieveUpdateAPIView = RetrieveAPIView + UpdateAPIView
RetrieveDestroyAPIView = RetrieveAPIView + DestroyAPIView
RetrieveUpdateDestroyAPIView = RetrieveAPIView + UpdateAPIView + DestroyAPIView
"""
from rest_framework.generics import ListAPIView,CreateAPIView
class BookModelView(ListAPIView,CreateAPIView):
""" 源码内已经封装了get、post方法 """
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializers
from rest_framework.generics import RetrieveAPIView,UpdateAPIView,DestroyAPIView
class BookInfoModelView(RetrieveAPIView,UpdateAPIView,DestroyAPIView):
""" 源码内已经封装了put、get、delete方法 """
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializers
使用视图集ViewSet,可以将一系列视图相关的代码逻辑和相关的http请求动作封装到一个类中:
上面的接口在实现过程中,也存在了代码重复的情况,我们如果合并成一个接口类,则需要考虑2个问题:
1、路由的合并问题
2、get方法重复问题
drf提供了视图集可以解决上面的问题 ViewSet -->APIView中的代码重复问题
ViewSet视图集类不再限制视图方法名只允许get()、 post()等这种情况了,而是实现允许开发者根据自己的需要定
义自定义方法名,例如 list()、create()等,然后经过路由中使用http和这些视图方法名进行绑定调用。
视图集只在使用as_view()方法的时候,才会将action动作与具体请求方式对应上。如:
"""
针对视图子类这种写法写法虽然已经省略了http请求,但是在开发通用5个api接口时,还是会出现需要2个类来实现5个接口的情况。
这主要的原因是2点:
1.获取多条数据与获取一条数据的http请求重复了。在django中依赖于请求方法来响应不同的http请求
2.部分接口需要pk值作为ur1地址。
drf为了解决上面的2个问题,提供了视图集和路由集。
视图集就可以帮我们实现一个视图类响应多种重复的http请求
路由集就可以帮我们实现自动根据不同的视图方法来生成不同参数的路由地址。
from rest_framework.viewsets import ViewSet # ViewSet是APIView的子类,是所有drf中的视图集的父类
"""
对于ViewSet 视图集来说,只是改变了 类视图函数方法名和路由中的as_view()
类视图函数方法名 :可以随便写你想要的方法名
urls.py中的as_view() :需要带参数,字典类型,例如 as_view({"http请求方式":" 类视图函数方法名" }) ,{'get':'list'}
源码: ctrl + 鼠标左键 点击 as_view() --> viewsets.py 文件夹 --->ViewSetMixin类 view 方法
# actions.items() 就是as_view() 传的参数
for method, action in actions.items():
handler = getattr(self, action) # 用传进来的字符串,绑定方法名
setattr(self, method, handler) # 把该方法绑定在类方法中
实例:
dome_view/views.py
:
"""
针对视图子类这种写法写法虽然已经省略了http请求,但是在开发通用5个api接口时,还是会出现需要2个类来实现5个接口的情况。
这主要的原因是2点:
1.获取多条数据与获取一条数据的http请求重复了。在django中依赖于请求方法来响应不同的http请求
2.部分接口需要pk值作为ur1地址。
drf为了解决上面的2个问题,提供了视图集和路由集。
视图集就可以帮我们实现一个视图类响应多种重复的http请求
路由集就可以帮我们实现自动根据不同的视图方法来生成不同参数的路由地址。
from rest_framework.viewsets import ViewSet # ViewSet是APIView的子类,是所有drf中的视图集的父类
"""
from rest_framework.viewsets import ViewSet
class BookViewSet(ViewSet):
def book_list(self,request):
# 1. 获取所有数据
instance = BookInfo.objects.all()
# 2. 实例化序列化器
serializer = BookInfoSerializers(instance,many=True)
# 3. 返回结果
return Response(serializer.data)
def book_create(self,request):
# 1. 获取用户提交的数据
data = request.data
# 2. 实例化序列化器
resializer = BookInfoSerializers(data=data)
# 3. 验证数据,保存数据
resializer.is_valid(raise_exception=True)
resializer.save()
# 4. 返回数据
return Response(resializer.data,status=status.HTTP_201_CREATED)
def book_listinfo(self,request,pk):
# 1. 通过pk值获取模型数据
instance = BookInfo.objects.get(id=pk)
# 2. 实例化序列化器
serializer = BookInfoSerializers(instance)
# 3. 返回数据
return Response(serializer.data)
def book_update(self,request,pk):
# 1. 通过pk值获取模型数据
instance = BookInfo.objects.get(id=pk)
# 2. 获取用户提交的数据
data = request.data
# 3. 实例化序列化器
serializer = BookInfoSerializers(instance,data=data)
# 4. 验证数据,保存数据
serializer.is_valid(raise_exception=True)
serializer.save()
# 4. 返回数据
return Response(serializer.data,status=status.HTTP_201_CREATED)
def book_delete(self,request,pk):
# 1. 通过pk 获取模型数据
try:
BookInfo.objects.get(id=pk).delete()
except BookInfo.DoesNotExist:
pass
return Response(status=status.HTTP_204_NO_CONTENT)
dome_views/urls.py
urlpatterns = [
......
# 视图集 ViewSet
path("book5/", views.BookViewSet.as_view({
"get": "book_list",
'post': "book_create",
})),
re_path('^book5/(?P<pk>\d+)/$',views.BookViewSet.as_view({
"get": "book_listinfo",
"put": "book_update",
"delete": "book_delete",
}))
]
GenericViewSet
类继承自 GenericAPIView
,并提供了 get_object
, get_queryset
方法和其他通用视图
基本行为的默认配置,但默认情况不包括任何操作。
from rest_framework.viewsets import GenericViewSet
dome_views/views.py
""" GenericViewSet 通用视图类 """
from rest_framework.viewsets import GenericViewSet
class BookGenericViewSet(GenericViewSet):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializers
def list(self,request):
# 1. 获取所有数据
instance = self.get_queryset()
# 2. 实例化序列化器
serializer = self.get_serializer(instance,many=True)
# 3.返回数据
return Response(serializer.data)
def create(self,request):
# 1. 获取用户提交的数据
data = request.data
# 2. 实例化序列化器
serializer = self.get_serializer(data=data)
# 3. 验证数据,保存数据
serializer.is_valid(raise_exception=True)
serializer.save()
# 4. 返回数据
return Response(serializer.data,status= status.HTTP_201_CREATED)
def listinfo(self,request,pk):
# 1. 通过pk获取模型数据
instance = self.get_object()
# 2. 实例化序列化器
serializer = self.get_serializer(instance)
# 3. 返回数据
return Response(serializer.data)
def update(self,request,pk):
# 1. 获取用户提交的数据
data = request.data
# 2. 通过pk获取模型数据
instance = self.get_object()
# 3. 实例化序列化器
serializer = self.get_serializer(instance, data=data)
# 4. 验证数据,保存数据
serializer.is_valid(raise_exception=True)
serializer.save()
# 5. 返回数据
return Response(serializer.data, status=status.HTTP_201_CREATED)
def delete(self,request,pk):
# 1. 通过pk获取模型数据进行删除
self.get_object().delete()
# 2. 返回数据
return Response(status=status.HTTP_204_NO_CONTENT)
dome_views/urls.py
:
urlpatterns = [
......
# 视图集 GenericViewSet 通用视图集
path("book6/", views.BookGenericViewSet.as_view({
"get": "list",
'post': "create",
})),
re_path('^book6/(?P<pk>\d+)/$',views.BookGenericViewSet.as_view({
"get": "listinfo",
"put": "update",
"delete": "delete",
})),
]
三行代码搞定以上步骤:
Mixins 类中 已经给我们封装好了5个基础请求方式,所以可以省略,当然你也可以封装另一个类去调用,具体可以看 目录 4.1.2 5 个视图扩展类
再写路由 as_view() 中的参数时,{“http请求方式”:“对应的视图类方法名”},因为Mixins 已经封装好了,所以要写Mixins封装的方法名,你也可以自定义方法名,具体可以看 目录 4.1.2 5 个视图扩展类
Views.py
:
"""视图集 GenericViewSet 通用类 + Mixins 混入类"""
"""
from rest_framework.mixins import ListModelMixin获取多条数据,返回响应结果 list
from rest_framework.mixins import CreateModelMixin添加一条数据,返回响应结果 create
from rest_framework.mixins import RetrieveModelMixin 获取一条数据,返回响应结果 retrieve
from rest_framework.mixins import UpdateModelMixin更新一条数据,返回响应结果 update(更新全部字段)和partial_update(更新单个或部分字段,例如修改密码,修改头像)
from rest framework.mixins import DestroyModelMixin 删除一条数据,返回响应结果 destroy
"""
class bookGenericViewSetMixin(GenericViewSet,ListModelMixin,CreateModelMixin,UpdateModelMixin,RetrieveModelMixin,DestroyModelMixin):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializers
dome_views/urls.py
:
urlpatterns = [
......
# 视图集 GenericViewSet + Mixins 混入类
path('book7/',views.BookGenericViewSetMixin.as_view({
"get":"list",
"post":"create",
})),
re_path("^bookinfo7/(?P<pk>\d+)/$",views.BookGenericViewSetMixin.as_view(
{
"get": "retrieve",
"put": "update",
"delete": "destroy"
}
))
from rest_framework.viewsets import ReadOnlyModelViewSet
上面的接口类继承的父类太多了。
我们可以继续让一些合并的视图集父类让视图继承即可。
views.py
:
"""
只读模型视图集
ReadOnlyModelViewSet = mixins.RetrieveModelMixin + mixins.ListModelMixin + GenericViewSet
- 获取多条数据
- 获取一条数据
"""
from rest_framework.viewsets import ReadOnlyModelViewSet
class BookReadOnlyModelViewSet(ReadOnlyModelViewSet,UpdateModelMixin,CreateModelMixin,DestroyModelMixin):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializers
dome_views/urls.py
:
urlpatterns = [
......
# 视图集 ReadOnlyModelViewSet + Mixins 混入类
path("book8/",views.BookReadOnlyModelViewSet.as_view({
"get":"list",
"post":"create",
})),
re_path("bookinfo8/(?P<pk>\d+)/$",views.BookReadOnlyModelViewSet.as_view({
"get":"retrieve",
"put":"update",
"delete":"destroy",
})),
实现了5个API接口,因为ModelViewSet 继承了Mixins的五个扩展类
ModelViewSet 源码:
class ModelViewSet(mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
GenericViewSet):
"""
A viewset that provides default `create()`, `retrieve()`, `update()`,
`partial_update()`, `destroy()` and `list()` actions.
"""
pass
from rest_framework.viewsets import ModelViewSet
views.py
:
""" ModelViewSet 模型视图集 """
from rest_framework.viewsets import ModelViewSet
class BookModelViewSet(ModelViewSet):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializers
doem_views/urls.py
:
urlpatterns = [
......
# 视图集 ModelViewSet 模型视图集
path("book9/",views.BookModelViewSet.as_view({
"get":"list",
"post":"create",
})),
re_path("bookinfo9/(?P<pk>\d+)/$",views.BookModelViewSet.as_view({
"get":"retrieve",
"put":"update",
"delete":"destroy",
})),
]
对于视图集ViewSet,我们除了可以自己手动指明请求方式与动作action之间的对应关系外,还可以使用Routers
来帮助我们快速实现路由信息。如果是非视图集,不需要使用路由集routers
REST framework提供了两个router,使用方式一致的。结果多一个或少一个根目录ur地址的问题而已
from rest_framework.routers import DefaultRouter,SimpleRouter
dome_views/urls.py
""" 路由集 Routers """
from rest_framework.routers import DefaultRouter,SimpleRouter
# 1. 实例化 路由类
router = SimpleRouter()
# 2. 给路由注册视图集
router.register('book10',views.BookModelViewSet,basename="book10")
print(router.urls)
# 3. 把生成的路由列表 和 urlpatterns进行拼接
urlpatterns += router.urls
在视图集中,如果想要让Router自动帮助我们为自定义的动作生成路由信息,需要使用
rest_framework.decorators.action
装饰器。
以action装饰器装饰的方法名会作为action动作名,与list、retrieve等同。
action装饰器可以接收两个参数:
methods:列表,指定允许哪些http请求方法可以访问当前视图方法
detail:布尔值,告诉路由对象在生成路由信息时,是否要自动生成pk值,True表示需要,False表示不需要。
python
路由前缀/<pk> /action方法名/
True表示路径格式是 xxx/
False表示路径格式是 xxx/action方法名/
url_path:字符串,访问视图的url地址,如果不设置,则默认采用视图方法名作为访问后缀
from rest_framework.decorators import action
""" ModelViewSet 模型视图集 """
from rest_framework.viewsets import ModelViewSet
from rest_framework.decorators import action
class BookModelViewSet(ModelViewSet):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializers
@action(methods=["get"],detail=True)
def login_log(self,request,pk):
# http://127.0.0.1:8000/dome_views/book10/1/login_log/
""" 用户登录历史记录 """
# 可以通过self.action获取本次客户端请求的视图方法名[viewSet 提供的]
print(self.action) # login_log
return Response({"msg":"用户登录历史记录"})
# 路由对象绘视图集生成路由信息时.品余生成5个基杰api接口这主要呆coute.r只识别5个混入类的原因
# 而针对我们开发者自定义的视图方法,路由对象不会自动生成路由信息,
# 所以下面这个login,如果希望被外界访问到,则必须通过action装饰器告诉路由对象要给它生成一个路由信息。
# action(methods-["get","post"],detail = False,url_path="login")
# action的参数
# methods,列表,指定允许哪些http请求方法可以访问当前视图方法
# detail,布尔值,告诉路由对象在生成路由信息时,是否要自动生成pk值,True表示需要,False表示不需要。
# url_path,字符串,访问视图的url地址,如果不设置,则默认采用视图方法名作为访问后缀
@action(methods=["get"], detail=False,url_path="user/login")
def login(self, request):
# http://127.0.0.1:8000/dome_views/book10/user/login/
return Response({"msg": "登录成功"})
字段 | 字段构造方式 |
---|---|
BooleanField | BooleanField() |
NullBooleanField | NullBooleanField() |
CharField | CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True) |
EmailField | EmailField(max_length=None, min_length=None, allow_blank=False) |
RegexField | RegexField(regex, max_length=None, min_length=None, allow_blank=False) |
SlugField | SlugField(maxlength=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9-]+ |
URLField | URLField(max_length=200, min_length=None, allow_blank=False) |
UUIDField | UUIDField(format='hex_verbose') format:1)'hex_verbose'如"5ce0e9a5-5ffa-654b-cee0-1238041fb31a"2)'hex' 如 "5ce0e9a55ffa654bcee01238041fb31a"3)'int' 如:"123456789012312313134124512351145145114"4)'urn' 如:"urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a" |
IPAddressField | IPAddressField(protocol='both', unpack_ipv4=False, **options) |
IntegerField | IntegerField(max_value=None, min_value=None) |
FloatField | FloatField(max_value=None, min_value=None) |
DecimalField | DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数 decimal_palces: 小数点位置 |
DateTimeField | DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None) |
DateField | DateField(format=api_settings.DATE_FORMAT, input_formats=None) |
TimeField | TimeField(format=api_settings.TIME_FORMAT, input_formats=None) |
DurationField | DurationField() |
ChoiceField | ChoiceField(choices) choices与Django的用法相同 |
MultipleChoiceField | MultipleChoiceField(choices) |
FileField | FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) |
ImageField | ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) |
ListField | ListField(child=, min_length=None, max_length=None) |
DictField | DictField(child=) |
参数名称 | 作用 |
---|---|
max_length | 最大长度 |
min_lenght | 最小长度 |
allow_blank | 是否允许为空 |
trim_whitespace | 是否截断空白字符 |
max_value | 最大值 |
min_value | 最小值 |
参数名称 | 说明 |
---|---|
read_only | 表明该字段仅用于序列化输出,默认False |
write_only | 表明该字段仅用于反序列化输入,默认False |
required | 表明该字段在反序列化时必须输入,默认True |
default | 反序列化时使用的默认值 |
allow_null | 表明该字段是否允许传入None,默认False |
validators | 该字段使用的验证器,是一个列表类型,值是函数 |
error_messages | 包含错误编号与错误信息的字典 |
label | 用于HTML展示API页面时,显示的字段名称 |
help_text | 用于HTML展示API页面时,显示的字段帮助提示信息 |
除了使用APIView
和ViewSet
其余视图类都得使用pk作为传递参数,drf 框架 源码中已经封装了,可以变相理解为model
中的主键列
除了APIView
和ViewSet
类,其他类都继承GenericAPIView类,在简写代码封装中,都用到了get_object()方法,该方法是GenericAPIView类的内置方法,而get_object() 就定义了 pk值。
如果要调用GenericAPIView 或GenericAPIView 的子类,就必须将路由中的传递值改为 pk 。
如:re_path("^bookinfo4/(?P<pk>\d+)/$",views.BookInfoModelView.as_view())
不然会报以下错误:
Expected view BookModelViewSet to be called with a URL keyword argument named "pk". Fix your URL conf, or set the `.lookup_field` attribute on the view correctly.
翻译过来
应使用名为“pk”的URL关键字参数调用view BookModelViewSet。修复URL配置,或设置“”。视图上的lookup\u field `属性正确。
解决办法:
1.改掉源码中的 属性 lookup_field = 'pk' #(不建议)
2.修改url路由中的传递值
源码:generic.py
--> get_object()
lookup_field = 'pk' # line 39行 GenericAPIView中的属性
lookup_url_kwarg = None #line 40行 GenericAPIView中的属性
def get_object(self):
"""
Returns the object the view is displaying.
You may want to override this if you need to provide non-standard
queryset lookups. Eg if objects are referenced using multiple
keyword arguments in the url conf.
"""
queryset = self.filter_queryset(self.get_queryset())
# Perform the lookup filtering.
# 解释注释
"""
lookup_field = 'pk'
lookup_url_kwarg = None
"""
lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
# 解释注释
# lookup_url_kwarg = None or 'pk'
# lookup_url_kwarg = 'pk'
assert lookup_url_kwarg in self.kwargs, (
'Expected view %s to be called with a URL keyword argument '
'named "%s". Fix your URL conf, or set the `.lookup_field` '
'attribute on the view correctly.' %
(self.__class__.__name__, lookup_url_kwarg)
)
filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]}
# 解释注释
# filter_kwargs = {"pk":"get、put、delete中的ID值"}
obj = get_object_or_404(queryset, **filter_kwargs)
# May raise a permission denied
self.check_object_permissions(self.request, obj)
return obj
在序列化器使用过程中,一般一个序列化器对应一个模型数据。往往因为模型之间会存在外键关联,所以一般在输
出数据时不仅要获取当前模型的数据,甚至其他模型的数据也需要同时返回,这种情况下,我们可以通过序列化器
嵌套调用的方式,帮我们把当前模型数据进行转换以外还额可以同时转换外键对应的模型数据。
为了方便演示,此处我们再次创建一个新的子应用来完成这块内容的学习。
python manage.py startapp drfdome
注册子应用
INSTALLED_APPS = [
...
"drfdome", # 序列化器嵌套
]
添加路由 settings.py
同级目录下的 urls.py
:
urlpatterns = [
...
path("drfdome/",include('drfdome.urls')), # ,视图学习
]
在刚刚创建的 drfdome 子应用里 创建 urls.py 和 serializers.py 文件
bookid = BookInfoSerializers(many=True) # many = True 嵌套多个 默认是false
urls.py
from rest_framework.routers import SimpleRouter
from . import views
# 1.实例化路由集
router = SimpleRouter()
# 2.添加路
# 英雄路由
router.register('hero',views.HeroInfoModelViewSet,basename="hero")
# 3.拼接路由
urlpatterns = [
] + router.urls
serializers.py
from rest_framework import serializers
from books.models import BookInfo,HeroInfo
# 创建书本详情路由
class BookInfoSerializers(serializers.ModelSerializer):
class Meta:
model = BookInfo
fields = ['title'] # 定义所需要的字段
# 创建英雄序列化器
class HeroInfoSerializer(serializers.ModelSerializer):
# 嵌套书本的序列化器
bookid = BookInfoSerializers(many=True) # many = True 嵌套多个 默认是false
class Meta:
model = HeroInfo
fields = "__all__"
drfdome/views.py
from rest_framework.viewsets import ModelViewSet
from books.models import BookInfo,HeroInfo
from .serializers import HeroInfoSerializer
""" 英雄模型视图类"""
class HeroInfoModelViewSet(ModelViewSet):
queryset = HeroInfo.objects.all()
serializer_class = HeroInfoSerializer
urls.py
from rest_framework.routers import SimpleRouter
from . import views
# 1.实例化路由集
router = SimpleRouter()
# 2.添加路
# 英雄路由
router.register('hero',views.HeroInfoModelViewSet,basename="hero")
# 3.拼接路由
urlpatterns = [
] + router.urls
serializers.py
from rest_framework import serializers
from books.models import BookInfo,HeroInfo
# 创建书本详情路由
class BookInfoSerializers(serializers.ModelSerializer):
class Meta:
model = BookInfo
fields = ['title'] # 定义所需要的字段
# 创建英雄序列化器
class HeroInfoSerializer(serializers.ModelSerializer):
# 嵌套书本的序列化器
bookid = BookInfoSerializers()
class Meta:
model = HeroInfo
fields = "__all__"
drfdome/views.py
from rest_framework.viewsets import ModelViewSet
from books.models import BookInfo,HeroInfo
from .serializers import HeroInfoSerializer
""" 英雄模型视图类"""
class HeroInfoModelViewSet(ModelViewSet):
queryset = HeroInfo.objects.all()
serializer_class = HeroInfoSerializer
book_name = serializers.CharField (source="bookid.title")
urls.py
...
# 2.添加路由
# 第一种方法
router.register('hero',views.HeroInfoModelViewSet,basename="hero")
# 第三种方法
router.register('hero2',views.HeroInfoModelViewSet2,basename="hero2")
...
serializers.py
""" 第三种方法 """
class HeroInfoSerializer2(serializers.ModelSerializer):
# 嵌套书本的序列化器
book_name = serializers.CharField(source="bookid.title")
class Meta:
model = HeroInfo
fields = ["id", "book_name", 'name']
views.py
...
""" 第三种方法 """
class HeroInfoModelViewSet2(ModelViewSet):
queryset = HeroInfo.objects.all()
serializer_class = HeroInfoSerializer2
urls.py
...
# 第四种方法
router.register('hero3',views.HeroInfoModelViewSet3,basename="hero3")
...
serializers.py
...
""" 第四种方法 """
class HeroInfoSerializer3(serializers.ModelSerializer):
class Meta:
model = HeroInfo
fields = "__all__"
depth = 1
views.py
...
""" 第四种方法 """
class HeroInfoModelViewSet3(ModelViewSet):
queryset = HeroInfo.objects.all()
serializer_class = HeroInfoSerializer3
models.py
class HeroInfo(models.Model):
name = models.CharField(max_length=20)
bookid = models.ForeignKey(to=BookInfo,to_field="id",on_delete=models.CASCADE,related_name="bookinfo",db_constraint=False) # 定义外键
class Meta:
db_table='hero'
def __str__(self):
return self.name
@property
def bookName(self):
return self.bookinfo.values()
urls.py
...
# 第五种方法
router.register('hero4',views.HeroInfoModelViewSet4,basename="hero4")
...
serialziers.py
...
""" 第五种方法 """
class HeroInfoSerializer4(serializers.ModelSerializer):
class Meta:
model = HeroInfo
fields = ["id",'name','bookName']
views.py
...
""" 第五种方法 """
class HeroInfoModelViewSet4(ModelViewSet):
queryset = HeroInfo.objects.all()
serializer_class = HeroInfoSerializer4
id | name | description | ontime | outtime | duraiton | price |
---|---|---|---|---|---|---|
1 | python入门 | 暂无 | 13:00 | 9:00 | 90 | 1000 |
2 | python进阶 | 暂无 | 14:20 | 15:20 | 60 | 2000 |
3 | pythonwebkaifa | 暂无 | 16:20 | 17:20 | 30 | 3000 |
# **题目**:
1.给上面的表格设计一个模型
2.基于APIView编写基本的五个API接口
3.基于GenericAPIView编写5个API接口
4.基于GenericAPIView + Mixins编写5个API接口