django rest framework 中的三种视图写法

本文详细介绍了Django Rest Framework(DRF)中的视图概念,包括基本视图类(APIView和@api_view)、通用视图(Generic views)以及视图集合(ViewSets)。在基本视图中,讨论了APIView的API策略属性、方法以及调度方法,以及函数基础视图@api_view的使用。通用视图提供了快速构建API的途径,而视图集合则允许将相关逻辑视图组合在一起,提供更灵活的API设计方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、基本视图类 (APIView/@api_view)

1、类基础视图(APIView)

DRF不同于django常规的view类,他有如下几点优点:
* 提供了更好用的request对象,不同于普通的django HttpRequest更好用。
* 封装了Response对象,代替了原有的django HttpResponse,视图将管理内容协商并设置正确的渲染器的响应。
* 任何APIException异常将会被捕捉,并做适当的响应。
* 传入的请求将身份验证和适当的权限和节流检查将之前运行调度请求处理程序的方法。
一个小例子:

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import authenication, permissions

class ListUser(APIView):
“””

展示系统中所有的用户
* 需要令牌认证。
* 只有admin用户能够访问这一个视图

"""
authentication_classes = (authentication.TokenAuthentication,)  # 认证策略属性
permission_classes = (permissions.IsAdminUser,) # 权限策略属性

def get(self, requeset, format=None):
"""
返回一个用户列表
"""
usernames = [user.username for user in  User.objects.all()]
return Response(usernames)
1) API策略属性

以下的API策略属性应用于APIView,控制视图的策略:
renderer_classes: 渲染器类
parser_classes: 解释器类
authentication_classes: 权限类
throttle_classes:节流类
permission_classes: 权限类
content_negotiation_class: 内容协商类

2)API 策略方法

以下的策略方法用在API的策略,通常不用重写它:
get_renderers(self): 获取渲染器方法
get_parsers(self): 获取解释器方法
get_authenticators(self): 或缺认证方法
get_throttles(self): 获取节流方法
get_permissions(self): 获取权限方法
get_content_negotiator(self): 获取内容协商方法

3)API策略实施方法

下列方法之前被称为调度处理程序方法:
check_permissions(self, request): 检查权限
check_throttles(self, request): 检查节流
check_content_negotiation(self, request, force=False): 检查内容协商

4)调度方法

这些执行任何操作,需要发生之前或之后调用处理程序方法等.
initial(self, request, *args, **kwargs): 执行任何操作,需要发生在处理程序方法之前被调用。这个方法是用来执行权限和节流,并执行内容协商。
handle_exception(self, exc):抛出的任何异常处理程序方法将被传递给这个方法,而返回响应实例,或者re-raises异常。
initialize_request(self, request, *args, **kwargs):确保请求对象传递给处理程序方法是request的一个实例,而不是django的HttpRequest
finalize_response(self, request, response, *args, **kwargs):确保任何响应处理程序方法返回的对象将被呈现到正确的内容类型

2、函数基础视图(@api_view())

DRF同样提供了另外一种函数基础视图来装饰django的普通视图,我们同样可以使用request来接受请求和response响应。
一个小例子:

from rest_framework.decorators import api_view

@api_view
def hello_world(request):
return Response({“message”:”Hello world!”})
1)api_view()使用方法

这个视图将使用默认渲染器、解析器、身份验证设置中指定的类等。通常默认只有GET方法,其他请求方法会报405错误,我们可以手动添加方法为这
装饰器指定request方法。像这样:

@api_view([‘GET’, ‘POST’])
def hello_world(request):
if request.method  == ‘POST’:
return Response({“message”:”Got some data”, “data”: request.data})
return Response({“messsage”:”Hello world!”})
2)API策略装饰器

DRF提供了很多附加的装饰器,我们可以添加到@api_view()后面,例如要加入一个节流的装饰器来确保特定用户每天只能一次通过这个视图,我
我们就要用到@throttle_classes装饰器:

from rest_framework.decorators import api_view, throttle_classes
from rest_framework.throttling import UserRateThrottle

class OncePerDayUserThrottle(UserRateThrottle):
rate = “1/day”

@api_view([‘GET’])
@throttle_classes([OncePerDayUserThrottle])
def view(request):
return Response({“message”:”Hello for to day! see you tomorrow!”})

其他可用API的装饰器:
@renderer_classes(…)
@parser_classes(…)
@authentication_classes(…)
@throttle_classes(…)
@permission_classes(…)

二、 通用视图(Generic views)

基于类视图的主要好处之一是他们允许您编写可重用的行为.
REST框架提供的通用视图允许您快速构建API观点紧密地映射到您的数据库模型.
如果通用视图不适合你的需要API,您可以使用常规APIView类,或重用mixin和基类使用的通用视图来组成自己的组可重用通用视图。

1、通用视图

同样我们可以设置一些类属性在通用视图内,也可以根据特殊要写重写它的内部视图方法。一个小例子:

from django.contrib.auth.models import User
from myapp.serializers import UserSerializer
from rest_framework import generics
from rest_framework.permissions import IsAdminUser

class UserList(generics.ListCreateAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = (IsAdminUser,)

def list(self, request):
# Note the use of get_queryset() instead of self.queryset
queryset = self.get_queryset()
serializer = UserSerializer(queryset, many=True)
return Response(serializer.data)

在urls配置中,我们可以使用.as_views()来转换成视图函数,当然也可以配置一些属性

url(r’^/users/’, ListCreateAPIView.as_view(queryset=User.objects.all(), serializer_class=UserSerializer), name=’user-list’)
2、GenericAPIView通用视图API参考:

GenericAPIView继承了DRF的APIView类,为list和detail视图增加了一些一般需求行为方法(提供queryset)。

1)属性

基本属性:
queryset: 用于返回query对象集合,也可以使用get_queryset()方法。
serializer_class: 序列化器类,应该用于输入进行验证和反序列化,并用于序列化输出。通常情况下,你必须设置这个属性,或重写get_serializer_class()方法。
lookup_field: 模型的字段应该用于执行对象查找个别的模型实例
lookup_url_kwarg:URL应该用于对象查找关键字参数

分页属性:
pagination_class: 用于返回一个分页列表视图的分页类,默认与settings中设置的DEFAULT_PAGINATION_CLASS 值相同,
可以通过’rest_framework.pagination.PageNumberPagination’设置分页数
过滤器属性:
filter_backends: 过滤queryset的类列表,和在settings中设置DEFAULT_FILTER_BACKENDS 一样

2)方法

基本方法:
get_queryset(): 返回queryset。(详情见官网http://www.django-rest-framework.org/api-guide/generic-views/
get_object():获取某一个具体的model实例对象。
保存与删除挂钩方法:
以下方法是mixins类提供,提供简单的对象保存和删除的行为重写:
perform_create(self, serializer): CreateModelMixin 当要保存对象时候会被调用
perform_update(self, serializer):UpdateModelMixin 当要更新对象时候会被调用
perform_destroy(self, instance): DestoryModelMixin 当药删除对象时候会被调用

3)、Mixins

mixin类提供用于提供基础视图的操作行为。注意,mixin类提供操作方法而不是定义处理程序方法,比如. get()和. post(),直接。这允许更灵活的组合的行为。
通过rest_framework.mixins引用。
ListModelMixin:提供list方法,列出queryset
CreateModelMixin: 提供create方法,创建和保存一个Model对象
RetrieveModelMixin:提供retrieve方法,检索一个存在的model对象
UpdateModelMixin: 提供Update方法,更改一个模型对象
DestroyModelMixin:提供destroy方法,删除一个模型对象

4)Generic

Generic通用视图类提供具体操作的通用视图类,可以理解为Generic.GenericAPIView和mixin类的合体,通过rest_framework.generic.调用

.CreateAPIView:

创建一个模型实例
提供post方法的处理器
继承于:GenericAPIView,CreateModelMixin

.ListAPIView:

模型实例的集合
提供get方法处理器
继承于:GenericAPIView,ListModelMixin

.RetrieveAPIView:

一个模型实例
提供get方法处理器
继承于:GenericAPIView,RetrieveModelMixin

.DestoryAPIView:

删除一个模型实例
提供delete方法处理器
继承于:GenericAPIView,DestroyModelMixin

.UpdateAPIView:

修改模型实例,
提供put和patch方法处理器
继承于:GenericAPIView,UpdateModelMixin

.ListCreateAPIView:

创建和展示一个模型实例集合
提供get和post处理器
继承于:GenericAPIView,ListModelMixin,CreateModelMixin

.RetrieveUpdateAPIView:

读和改一个模型实例
提供get,put,patch处理器
继承于:GenericAPIView,RetrieveModelMixin,UpdateModelMixin

.RetrieveDestoryAPIView:

读和删除一个模型实例
提供get和delete处理器
继承于:GenericAPIView,RetrieveModelMixin,DestroyModelMixin

.RetrieveUpdateDestroyAPIView:

读、改和删一个模型实例
get, put, patch,delete处理器
继承于:GenericAPIView,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin

三、视图集合ViewSets

Django REST框架允许您将一组相关的逻辑视图在一个类,ViewSet类是一个简单类型的基于类的观点,没有提供任何方法处理程序如.get()或. post(),
而代替提供方法比如.list()和create()。
一个小例子:

from django.contrib.auth.models import User
from django.shortcuts import get_object_or_404
from myapps.serializers import UserSerializer
from rest_framework import viewsets
from rest_framework.response import Response

class UserViewSet(viewsets.ViewSet):
“””
A simple ViewSet for listing or retrieving users.
“””
def list(self, request):
queryset = User.objects.all()
serializer = UserSerializer(queryset, many=True)
return Response(serializer.data)

def retrieve(self, request, pk=None):
queryset = User.objects.all()
user = get_object_or_404(queryset, pk=pk)
serializer = UserSerializer(user)
return Response(serializer.data)
1).关于ViewSets

如果我们需要,我们需要为两个GET请求分开绑定视图:
user_list = UserViewSet.as_view({“GET”:’list’})
user_detail = UserViewSet.as_view({‘GET’:’retrieve’})

但是通常我们不会这样做,而是通过注册路由来配置url:

from myapp.views import UserViewSet
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r’users’, UserViewSet)
urlpatterns = router.urls

或许你会经常用到自己模型数据,而不是手动写视图集合,这样就要用到模型视图集合ModelViewSet:

class UserViewSet(viewsets.ModelViewSet):
“””
A viewset for viewing and editing user instance
“””
serializer_class = UserSerializer
queryset = User.objects.all()

其他路由函数方法:

class UserViewSet(viewsets.ViewSet):
“””
Example empty viewset demonstrating the standard
actions that will be handled by a router class.

If you’re using format suffixes, make sure to also include
the format=None keyword argument for each action.
“””

def list(self, request):
pass

def create(self, request):
pass

def retrieve(self, request, pk=None):
pass

def update(self, request, pk=None):
pass

def partial_update(self, request, pk=None):
pass

def destroy(self, request, pk=None):
pass
如果你有特别的需要被路由到的方法,可以将它们标记为需要路由使用@detail_route或@list_route修饰符。
@detail_route(methods=[‘post’], permission_classes=[IsAdminOrIsSelf])
def set_password(self, request, pk=None):
…
可以通过访问^users/{pk}/set_password/$来访问改视图
2)ViewSets的API参考
.ViewSet:

继承了APIView,你可以使用一些标准的属性例如permission_class,authentication_classes去对视图做一些策略。ViewSet同样不提供具体
行为方法的实现,你可以重写和定义一些请求处理方法。而代替了原来APIVIew的POST,GET等方法,取而代之的是list,create等方法。

.GenericViewSet:

继承了GenericAPIView,提供了默认的get_queryset()和get_object()等方法来获取model数据,但不提供任何请求处理方法。

.ModelViewSet:

继承了GenericAPIView,增加了一些请求处理方法,如list(), retrieve(),create()等。

例子:

class AccountViewSet(viewsets.ModelViewSet):
“””
A simple ViewSet for viewing and editing accounts
“””
queryset = Account.objects.all()
serializer_class = AccountSerializer
permissions_classes = [IsAccountAdminOrReadOnly]
.ReadOnlyModelViewSet:

继承了GenericAPIView,只增加了只读的请求处理方法list()和retrieve()

自定义View类:

只需要继承GenericAPIView, 增加mixins的相关处理方法。如:

class CreatListRetrieveViewSet(mixins.CreateModelMixin,
mixins.ListModelMixin,
mixins.RetrieveModelMixin,
View.GenericViewSet):
pass
<think>我们正在讨论Django框架中的动态路由定义。根据Django的URL配置,动态路由通常通过包含转换器的路径转换器(path converters)或正则表达式(使用re_path)来实现。动态部分被尖括号<>包围,并可以指定转换器类型(如int, str, slug, uuid, path)来匹配特定类型的数据。 参考引用[2]中提到了使用正则表达式匹配URL,这是Django中定义动态路由的一种方式。在较新的Django版本中,推荐使用path()和转换器,但也可以使用re_path()来使用正则表达式。 下面我将分步骤说明如何在Django中定义动态路由: ### 1. 使用path转换器 在Django 2.0及以上版本中,引入了`path`和转换器,使得定义动态路由更加简洁。 例如,我们想要匹配一个整数id的URL,可以这样写: ```python from django.urls import path from . import views urlpatterns = [ path('articles/<int:article_id>/', views.article_detail, name='article_detail'), ] ``` 这里: - `articles/`是静态部分。 - `<int:article_id>`是动态部分,`int`转换器确保只匹配整数,并将该部分作为关键字参数`article_id`传递给视图函数。 ### 2. 使用re_path(正则表达式) 如果需要更复杂的匹配,可以使用`re_path`(相当于Django1.x中的`url`函数)。 例如,匹配四位数的年份和两位数的月份: ```python from django.urls import re_path from . import views urlpatterns = [ re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive), ] ``` 这里: - 使用正则表达式捕获组,并命名捕获组(`?P<year>`和`?P<month>`),这样视图函数就可以通过关键字参数`year`和`month`来获取值。 ### 3. 自定义路径转换器 如果内置的转换器(int, str, slug, uuid, path)不能满足需求,还可以自定义转换器。 例如,自定义一个转换器,只匹配1到12的整数(月份): ```python # 在urls.py中定义 class MonthConverter: regex = '1[0-2]|[1-9]' # 匹配1-12 def to_python(self, value): return int(value) def to_url(self, value): return '%02d' % value # 注册转换器 from django.urls import register_converter register_converter(MonthConverter, 'month') # 使用自定义转换器 urlpatterns = [ path('articles/<int:year>/<month:month>/', views.month_archive), ] ``` ### 4. 在视图中获取动态参数 在视图函数中,动态部分将作为关键字参数传入。 例如,对于上面的`article_detail`视图: ```python def article_detail(request, article_id): # 通过article_id获取文章 ... ``` 对于`month_archive`视图: ```python def month_archive(request, year, month): # 根据year和month查询 ... ``` ### 总结 在Django中定义动态路由主要有两种方式: 1. 使用`path()`和内置或自定义的转换器(推荐,更简洁)。 2. 使用`re_path()`和正则表达式(更灵活)。 这些动态参数会被传递给视图函数,从而可以根据URL中的不同部分来呈现不同的内容。 [^1]: 引用1中展示了在Django中如何使用`DefaultRouter`来注册视图集,并自动生成URL模式,但这通常用于DRF(Django REST Framework)中,而不是一般的动态路由。 [^2]: 引用2解释了Django的URL配置,包括使用`include`和`url`(现在为`re_path`)来匹配URL,这涉及到动态路由的正则表达式方式。 §§相关问题§§ 1. Django中有哪些内置的路径转换器? 2. 如何在Django中使用正则表达式定义动态路由? 3. 如何自定义路径转换器? 4. 在Django视图中如何获取动态路由传递的参数? 5. 动态路由在Django REST Framework中有什么不同?</think>在 Django 中定义动态路由是通过 URL 模式中的路径转换器实现的,允许在 URL 中包含变量部分。以下是详细实现方法: ### 1. 基本动态路由(使用路径转换器) ```python # urls.py from django.urls import path from . import views urlpatterns = [ # 静态路由 path('about/', views.about), # 动态路由示例 path('articles/<int:article_id>/', views.article_detail), # 匹配 /articles/123/ path('users/<str:username>/', views.user_profile), # 匹配 /users/john/ path('category/<slug:category_slug>/', views.category), # 匹配 /category/python-tips/ ] ``` - **`<int:article_id>`**:捕获整数参数 - **`<str:username>`**:捕获字符串参数(不含斜杠) - **`<slug:category_slug>`**:捕获字母数字连字符参数 - 其他内置转换器:`uuid`, `path`(含斜杠的字符串) ### 2. 视图函数接收参数 ```python # views.py def article_detail(request, article_id): # 通过 article_id 查询数据库 article = Article.objects.get(id=article_id) return render(request, 'detail.html', {'article': article}) def user_profile(request, username): # 使用 username 获取用户数据 user = User.objects.get(username=username) return render(request, 'profile.html', {'user': user}) ``` ### 3. 正则表达式路由(复杂匹配) ```python # urls.py from django.urls import re_path urlpatterns = [ # 匹配 /posts/2023/08/15/sample-post/ re_path(r'^posts/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/(?P<slug>[\w-]+)/$', views.post_detail), ] ``` ### 4. 包含其他 URLconf(模块化路由) ```python # 主 urls.py from django.urls import include, path urlpatterns = [ path('blog/', include('blog.urls')), # 包含子应用的路由 ] # blog/urls.py urlpatterns = [ path('<int:post_id>/', views.post_detail), # 实际路径为 /blog/123/ ] ``` ### 关键特性说明 1. **路径转换器类型**: - `int`:匹配 0 或正整数 - `str`:匹配非空字符串(不含 `/`) - `slug`:匹配字母、数字、连字符和下划线 - `uuid`:匹配 UUID 格式字符串 - `path`:匹配包含 `/` 的完整路径 2. **参数传递规则**: - 视图函数参数名必须与 URL 模式中的变量名一致 - 支持多个动态参数:`/archive/<int:year>/<int:month>/` 3. **路由优先级**: - Django 从上到下匹配 URL 模式 - 将更具体的路由放在通用路由前面 ### 示例:电商产品详情页 ```python # urls.py path('products/<int:category_id>/<slug:product_slug>/', views.product_detail) # views.py def product_detail(request, category_id, product_slug): product = Product.objects.get( category__id=category_id, slug=product_slug ) return render(request, 'product.html', {'product': product}) ``` 访问路径:`/products/5/awesome-wireless-headphones/` [^1]: 引用1展示了 Django 中 URLconf 的基本结构,包含 `path` 和 `include` 的使用方法。 [^2]: 引用2解释了 URL 匹配机制和正则表达式的应用场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值