Django Rest Framework(DRF)框架搭建步骤,包含部分错误解决

一、初步搭建项目

1.使用PyCharm 2021创建Djiango项目,配置如下(假设应用名叫djiango_python)

  • Python (3.6, 3.7, 3.8, 3.9, 3.10, 3.11)==> 当前版本 3.8.6
  • Django (3.0, 3.1, 3.2, 4.0, 4.1, 4.2)==> 当前版本 4.2.8

在这里插入图片描述

简单看看项目的配置

INSTALLED_APPS = ['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','snippets.apps.SnippetsConfig',"rest_framework"
]MIDDLEWARE = ['django.middleware.security.SecurityMiddleware','django.contrib.sessions.middleware.SessionMiddleware','django.middleware.common.CommonMiddleware','django.middleware.csrf.CsrfViewMiddleware','django.contrib.auth.middleware.AuthenticationMiddleware','django.contrib.messages.middleware.MessageMiddleware','django.middleware.clickjacking.XFrameOptionsMiddleware',
]

从上面我们可以看到 admin(管理)、auth(权限)、session(会话)、messages(消息)、csrf等等基本的都有了,这时候我们可以把“rest_framework”加入到INSTALLED_APPS里面,如果没有配置当我们在第二章节包装Api视图时可能会出现这样的错误:
在这里插入图片描述

2.安装相关包

pip install djangorestframework  ##必须
pip install pygments
pip install markdown       # 对可浏览API的markdown格式的支持。
pip install django-filter  # Filtering support以下包是可选的:
PyYAML, uritemplate (5.1+3.0.0+- 架构生成支持。
Markdown (3.0.0+- Markdown 对可浏览 API 的支持。
Pygments (2.4.0+- 在 Markdown 处理中添加语法高亮显示。
django-filter1.0.1+- 过滤支持.
django-guardian (1.1.1+- 对象级权限支持.

3.首次同步数据库并创建初始用户

python manage.py migrate

我们还将创建一个使用密码命名的初始用户(“admin”)。稍后在示例中,我们将以该用户的身份进行身份验证。

python manage.py createsuperuser --username admin --email admin@example.com

4.创建model类-(Model)

from django.db import models
from pygments.lexers import get_all_lexers
from pygments.styles import get_all_stylesLEXERS = [item for item in get_all_lexers() if item[1]]
LANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS])
STYLE_CHOICES = sorted([(item, item) for item in get_all_styles()])class Snippet(models.Model):created = models.DateTimeField(auto_now_add=True)title = models.CharField(max_length=100, blank=True, default='')code = models.TextField()linenos = models.BooleanField(default=False)language = models.CharField(choices=LANGUAGE_CHOICES, default='python', max_length=100)style = models.CharField(choices=STYLE_CHOICES, default='friendly', max_length=100)class Meta:ordering = ['created']

5.接着我们需要为这个模型创建“初始迁移”,并首次同步数据库。

python manage.py makemigrations snippets
python manage.py migrate snippets

在这里插入图片描述
在这里插入图片描述

6.序列化程序

在(应用 djiango_python)项目下创建serializers.py

这个里面的class类名一般是模型类名+Serializer 。例如:SnippetSerializer,简单的demo如下:

class SnippetSerializer(serializers.ModelSerializer):class Meta:model = Snippetfields = ['id', 'title', 'code', 'linenos', 'language', 'style']

当然有教程是使用了SnippetSerializer序列化并存储了几条数据到这个新模型所在的表里面

7.编写我们的视图(View)

在views.py里面编写代码,如下的风格是Forms API 这种风格

from django.http import HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_exempt
from rest_framework.parsers import JSONParser
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer@csrf_exempt
def snippet_list(request):"""List all code snippets, or create a new snippet."""if request.method == 'GET':snippets = Snippet.objects.all()serializer = SnippetSerializer(snippets, many=True)return JsonResponse(serializer.data, safe=False)elif request.method == 'POST':data = JSONParser().parse(request)serializer = SnippetSerializer(data=data)if serializer.is_valid():serializer.save()return JsonResponse(serializer.data, status=201)return JsonResponse(serializer.errors, status=400)@csrf_exempt
def snippet_detail(request, pk):"""Retrieve, update or delete a code snippet."""try:snippet = Snippet.objects.get(pk=pk)except Snippet.DoesNotExist:return HttpResponse(status=404)if request.method == 'GET':serializer = SnippetSerializer(snippet)return JsonResponse(serializer.data)elif request.method == 'PUT':data = JSONParser().parse(request)serializer = SnippetSerializer(snippet, data=data)if serializer.is_valid():serializer.save()return JsonResponse(serializer.data)return JsonResponse(serializer.errors, status=400)elif request.method == 'DELETE':snippet.delete()return HttpResponse(status=204)

8.视图写好后,需要连接视图,需要在urls里面配置

配置文件为urls.py,添加进去(原有的别删)

from django.urls import path
from snippets import viewsurlpatterns = [path('snippets/', views.snippet_list),path('snippets/<int:pk>/', views.snippet_detail),
]

由于这个搭建的项目使用SnippetConfig,这边我们就不用在文件中连接根 (wire up the root urlconf )

9.debug模式下报错(can’t find ‘main’ module in ‘’)解决方法:

勾选 “No reload” 选项
在这里插入图片描述

二. 进一步了解

1.请求和响应

请求对象 => Request / HttpRequest

请求的数据:request.data

请求方式:request.POST

响应对象:Response/TemplateResponse

Response.status ==>响应状态码 status.HTTP_400_BAD_REQUEST(这就是请求400)

2.包装 API 视图

REST 框架提供了两个包装器,可用于编写 API 视图。

  1. 用于处理基于函数的视图的修饰器。@api_view
  2. 用于处理基于类的视图的类。APIView

这些包装器提供了一些功能,例如确保在视图中接收实例,以及向对象添加上下文以便可以执行内容协商。

包装器还提供行为,例如在适当的时候返回响应,以及处理使用格式错误的输入进行访问时发生的任何异常。

将之前的代码进行整合:

(ps:这里我们操作的是view层 相当于是java/c#的controller层)

需要导入

​ 1.api_view=》from rest_framework.decorators import api_view

​ 2.Response=》from rest_framework.response import Response

​ 3.status => from rest_framework import status

完整代码如下:

from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer@api_view(['GET', 'POST'])
def snippet_list(request):"""List all code snippets, or create a new snippet."""if request.method == 'GET':snippets = Snippet.objects.all()serializer = SnippetSerializer(snippets, many=True)return Response(serializer.data)elif request.method == 'POST':serializer = SnippetSerializer(data=request.data)if serializer.is_valid():serializer.save()return Response(serializer.data, status=status.HTTP_201_CREATED)return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)@api_view(['GET', 'PUT', 'DELETE'])
def snippet_detail(request, pk):"""Retrieve, update or delete a code snippet."""try:snippet = Snippet.objects.get(pk=pk)except Snippet.DoesNotExist:return Response(status=status.HTTP_404_NOT_FOUND)if request.method == 'GET':serializer = SnippetSerializer(snippet)return Response(serializer.data)elif request.method == 'PUT':serializer = SnippetSerializer(snippet, data=request.data)if serializer.is_valid():serializer.save()return Response(serializer.data)return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)elif request.method == 'DELETE':snippet.delete()return Response(status=status.HTTP_204_NO_CONTENT)

从里面看 风格就很像我们现在的(JAVA/C#)通用的Controller层 ,此时我们再来访问一次接口(如下图所示)

在这里插入图片描述

如果我们想要这样的格式支持:

​ =>127.0.0.1:8000/snippets/1.json(以json格式进行返回 如果没有在Setting里 INSTALLED_APPS添加 “rest_framework”,也可通过这种方式来访问我们的接口,不会报xx.html找不到的错误)

​ ==>http://127.0.0.1:8000/snippets/1.api (这种方式也能访问接口只不过是以api的方式在界面展示,参考Swagger界面)

​ => 127.0.0.1:8000/snippets.json

​ => 127.0.0.1:8000/snippets.abc (当然这个是找不到的,页面不会报错 只会告诉我们没找到)

​ => 127.0.0.1:8000/snippets/2/?format=json

​ => 127.0.0.1:8000/snippets/2/?format=api

我们用这个链接来访问:127.0.0.1:8000/snippets/1.json

在这里插入图片描述

此时告诉我们这个详情接口 少了个format参数,我们再我们的接口上都加上这个参数

在这里插入图片描述

然后在urls.py里面加上 =》 urlpatterns = format_suffix_patterns(urlpatterns)

再来访问:
在这里插入图片描述

3. 精简代码

基于类的视图,我们写个“查改删”的示例,如下面的代码块,像按主键查询(get请求)、修改(put请求)、删除(delete请求),好处就是不用像上面那样要写多个分支

class SnippetDetail(APIView):"""检索,更新或删除一个snippet示例。"""def get_object(self, pk):try:return Snippet.objects.get(pk=pk)except Snippet.DoesNotExist:raise Http404def get(self, request, pk, format=None):snippet = self.get_object(pk)serializer = SnippetSerializer(snippet)return Response(serializer.data)def put(self, request, pk, format=None):snippet = self.get_object(pk)serializer = SnippetSerializer(snippet, data=request.data)if serializer.is_valid():serializer.save()return Response(serializer.data)return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)def delete(self, request, pk, format=None):snippet = self.get_object(pk)snippet.delete()return Response(status=status.HTTP_204_NO_CONTENT)

这时候如果要访问接口,需要对原来的url进行重构(可以看出我们我们需要把这些类作为视图==》 因为都调用了as_view函数):

urlpatterns = [path('snippets/', views.SnippetList.as_view()),path('snippets/<int:pk>/', views.SnippetDetail.as_view()),
]

下面是mixins的常用api,其实里面已经封装了常用的增删改查的逻辑:

//新增
class CreateAPIView(mixins.CreateModelMixin,GenericAPIView):"""Concrete view for creating a model instance."""def post(self, request, *args, **kwargs):return self.create(request, *args, **kwargs)//列表
class ListAPIView(mixins.ListModelMixin,GenericAPIView):"""Concrete view for listing a queryset."""def get(self, request, *args, **kwargs):return self.list(request, *args, **kwargs)//检索 相当按id查询
class RetrieveAPIView(mixins.RetrieveModelMixin,GenericAPIView):"""Concrete view for retrieving a model instance."""def get(self, request, *args, **kwargs):return self.retrieve(request, *args, **kwargs)//删除
class DestroyAPIView(mixins.DestroyModelMixin,GenericAPIView):"""Concrete view for deleting a model instance."""def delete(self, request, *args, **kwargs):return self.destroy(request, *args, **kwargs)//更新
class UpdateAPIView(mixins.UpdateModelMixin,GenericAPIView):"""Concrete view for updating a model instance."""def put(self, request, *args, **kwargs):return self.update(request, *args, **kwargs)def patch(self, request, *args, **kwargs):return self.partial_update(request, *args, **kwargs)//列表和新增
class ListCreateAPIView(mixins.ListModelMixin,mixins.CreateModelMixin,GenericAPIView):"""Concrete view for listing a queryset or creating a model instance."""def get(self, request, *args, **kwargs):return self.list(request, *args, **kwargs)def post(self, request, *args, **kwargs):return self.create(request, *args, **kwargs)//检索(如:id查询) 更新  删除
class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin,mixins.UpdateModelMixin,mixins.DestroyModelMixin,GenericAPIView):"""Concrete view for retrieving, updating or deleting a model instance."""def get(self, request, *args, **kwargs):return self.retrieve(request, *args, **kwargs)def put(self, request, *args, **kwargs):return self.update(request, *args, **kwargs)def patch(self, request, *args, **kwargs):return self.partial_update(request, *args, **kwargs)def delete(self, request, *args, **kwargs):return self.destroy(request, *args, **kwargs)

如果我们这个接口可以用通用的,可以继承对应的类,如ListAPIView,所以精简代码后我们的代码可以是这样的:

使用通用的基于类的视图
REST框架提供了一组已经混合好(mixed-in)的通用视图,我们可以使用它来简化我们的views.py模块。from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from rest_framework import genericsclass SnippetList(generics.ListCreateAPIView):queryset = Snippet.objects.all()serializer_class = SnippetSerializerclass SnippetDetail(generics.RetrieveUpdateDestroyAPIView):queryset = Snippet.objects.all()serializer_class = SnippetSerializer

4.身份认证和权限验证

1、在models.py 里面Snippet 种添加如下代码:

##models.py from pygments.lexers import get_lexer_by_name
from pygments.formatters.html import HtmlFormatter
from pygments import highlightowner = models.ForeignKey('auth.User', related_name='snippets', on_delete=models.CASCADE)
highlighted = models.TextField()def save(self, *args, **kwargs):"""Use the `pygments` library to create a highlighted HTMLrepresentation of the code snippet."""lexer = get_lexer_by_name(self.language)linenos = 'table' if self.linenos else Falseoptions = {'title': self.title} if self.title else {}formatter = HtmlFormatter(style=self.style, linenos=linenos,full=True, **options)self.highlighted = highlight(self.code, lexer, formatter)super().save(*args, **kwargs)

2.添加对象级别的权限(教程里面这个是最好一步,但我觉得放在第一步比较好 本身就是为了设置权限):

#创建一个新文件 permissions.py,如果有 直接在里面把这些代码站过去from rest_framework import permissionsclass IsOwnerOrReadOnly(permissions.BasePermission):"""自定义权限,只允许对象的所有者对其进行编辑。"""def has_object_permission(self, request, view, obj):# Read permissions are allowed to any request,# so we'll always allow GET, HEAD or OPTIONS requests.if request.method in permissions.SAFE_METHODS:return True# Write permissions are only allowed to the owner of the snippet.return obj.owner == request.user

3.添加用户序列化器(此处增加SnippetSerializer里面owner字段并使其只读,这意味着Snippet表和用户表相关联 ):

##serializers.pyfrom django.contrib.auth.models import Userclass SnippetSerializer(serializers.ModelSerializer):# 注意:请确保同时添加到内部类的字段列表中。'owner',Meta 在查询会映射usernameowner = serializers.ReadOnlyField(source='owner.username')class Meta:model = Snippetfields = ['id', 'title', 'code', 'linenos', 'language', 'style', 'owner'] #这里的owner就是新增的字段class UserSerializer(serializers.ModelSerializer):snippets = serializers.PrimaryKeyRelatedField(many=True, queryset=Snippet.objects.all())class Meta:model = Userfields = ['id', 'username', 'snippets'] #这个snipperts是user的映射

4.添加用户视图:

## views.py
from django.contrib.auth.models import User
from snippets.serializers import UserSerializerclass UserList(generics.ListAPIView):queryset = User.objects.all()serializer_class = UserSerializerclass UserDetail(generics.RetrieveAPIView):queryset = User.objects.all()serializer_class = UserSerializer

ps: 在序列化是导入User所在包

正确: from django.contrib.auth.models import User

错误: from rest_framework.authtoken.admin import User

使用下方会报错,未注册"admin"

##add auth lib
from pygments.lexers import get_lexer_by_name
from pygments.formatters.html import HtmlFormatter
from pygments import highlight##省略相关字段class Snippet(models.Model):##省略其他字段## 增加auth_user表(主键)作为外键  这个字段是owner在数据库会映射成owner_id存放的是用户idowner = models.ForeignKey('auth.User', related_name='snippets', on_delete=models.CASCADE)highlighted = models.TextField()## def save(self, *args, **kwargs):"""使用“pygments”库创建高亮显示的HTML代码段的表示形式。"""lexer = get_lexer_by_name(self.language)linenos = 'table' if self.linenos else Falseoptions = {'title': self.title} if self.title else {}formatter = HtmlFormatter(style=self.style, linenos=linenos,full=True, **options)self.highlighted = highlight(self.code, lexer, formatter)super().save(*args, **kwargs)class Meta:##省略....

5.然后我们手动删除 db.sqlite(文件) 和snippets/migrations(文件夹)

##重新创建(迁移)数据库和表信息
python manage.py makemigrations snippets
python manage.py migrate
## 创建一个超级管理员
python manage.py createsuperuser
用户名:administrator
邮箱:1244@qq.com
密码:123456

6.添加url:

path('users/', views.UserList.as_view()),
path('users/<int:pk>/', views.UserDetail.as_view()),

7.将代码段与用户关联

如果我们需要具体业务跟用户绑定,意味着就是只能这个用户操作(增删改),我们可以在操作里面加上这个:

##这个加到SnippetList这个类视图,我们修改实例保存会记录这个用户信息
def perform_create(self, serializer):serializer.save(owner=self.request.user)

这时候我们再来访问接口,发现权限没啥用啊 能看到这个删除和修改操作

在这里插入图片描述

这时候不用慌,我们把这个行代码加入就行了:permission_classes = [permissions.XX]

放在哪儿呢?这个房子类视图的里面作为一级字段就行了,示例:

class SnippetList(generics.ListCreateAPIView):permission_classes = [permissions.IsAuthenticated]

形式如下:

permission_classes = [permissions.NOT] #无权限访问
permission_classes = [permissions.IsAuthenticated] #有权限
permission_classes = [permissions.IsAuthenticatedOrReadOnly]#有权限但是只读状态(做不了修改删除操作)
permission_classes = [permissions.IsAuthenticatedOrReadOnly,IsOwnerOrReadOnly]#有权限但是只读状态(做不了修改删除操作,IsOwnerOrReadOnly是我们最开始定义的只读类)
permission_classes = [permissions.IsAdminUser] #必须管理员权限

登录前(只有只读权限):

在这里插入图片描述

登录后:

在这里插入图片描述

通过下方的数据库表snipperts_snippet我们可以看到新增highlighted和owner_id两个字段以及两条数据跟auth_user的id进行了关联

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.配置超链接

之前我们访问这个根url(http://127.0.0.1:8000/)会报错,其实这个应该是把里面的url连接放在这个并能以超链接的形式进行跳转如图所示:

在这里插入图片描述

那么需要怎么做:

第一步:在view.py 配置(常使用注解的api配置 方便把url加到下面的Response里面)

from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework.reverse import reverse@api_view(['GET'])
def api_root(request, format=None):return Response({'users': reverse('user-list', request=request, format=format),'snippets': reverse('snippet-list', request=request, format=format)})##这个就是把我们高亮代码块 渲染出来(当然没有这个也没多大事)
class SnippetHighlight(generics.GenericAPIView):queryset = Snippet.objects.all()renderer_classes = [renderers.StaticHTMLRenderer]def get(self, request, *args, **kwargs):snippet = self.get_object()return Response(snippet.highlighted)

第二步:替换原有的序列化器 增加highlight,也就是超链接,格式可以设置html或json

增加两个highlight和url,如果字段有的 Meta类的字段里面也需要增加这个字段

url字段与字段的类型相同,只不过它指向的是 url 模式,而不是 url 模式

class SnippetSerializer(serializers.HyperlinkedModelSerializer):owner = serializers.ReadOnlyField(source='owner.username')highlight = serializers.HyperlinkedIdentityField(view_name='snippet-highlight', format='html')class Meta:model = Snippetfields = ['url', 'id', 'highlight', 'owner','title', 'code', 'linenos', 'language', 'style']class UserSerializer(serializers.HyperlinkedModelSerializer):snippets = serializers.HyperlinkedRelatedField(many=True, view_name='snippet-detail', read_only=True)class Meta:model = Userfields = ['url', 'id', 'username', 'snippets']

第三步:确保我们的URL模式被命名

如果我们要使用超链接的API,那么需要确保为我们的URL模式命名。我们来看看我们需要命名的URL模式。

  • 我们API的根路径是指'user-list''snippet-list'
  • 我们的代码片段序列化器包含一个指向'snippet-highlight'的字段。
  • 我们的用户序列化器包含一个指向'snippet-detail'的字段。
  • 我们的代码片段和用户序列化程序包括'url'字段,默认情况下将指向'{model_name}-detail',在这个例子中就是'snippet-detail''user-detail'

将所有这些名称添加到我们的URLconf中后,最终我们的snippets/urls.py文件应该如下所示:

urlpatterns = [path('', views.api_root),path('snippets/', views.SnippetList.as_view() ,name='snippet-list'),path('snippets/<int:pk>/', views.SnippetDetail.as_view(),name='snippet-detail'),path('snippets/<int:pk>/highlight/', views.SnippetHighlight.as_view(), name='snippet-highlight'),#增加用户urlpath('users/', views.UserList.as_view(),name='user-list'),path('users/<int:pk>/', views.UserDetail.as_view(),name='user-detail'),
]# 可浏览API的登录和注销视图(一般配置最后,如果没有配置,访问根url时没有登录和注销的按钮)
urlpatterns += [path(r'^api-auth/', include('rest_framework.urls',  namespace='rest_framework')),
]urlpatterns = format_suffix_patterns(urlpatterns)

在这里插入图片描述

django\urls\conf.py

其实这个是来自于conf.py里面的_path 函数,对应路由 视图 视图名称(name)以及匹配模式)

6.添加分页

我们可以通过稍微修改我们的文件来更改默认列表样式以使用分页。添加以下设置:tutorial/settings.pyREST_FRAMEWORK = {'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination','PAGE_SIZE': 10
}

这边页大小我配置1,页码就是2页了,如图
在这里插入图片描述

三、ViewSet 和 Routers

我们看虽然我门在第二节里面精简了代码使用类视图的方式继承了mixins里面的一些api接口,但最少需要两个类来对应 查询以及增删改,这里我们再把这两个类合并当一个视图集合里面,也就需要ViewSet

使用ViewSet

第一步替换view.py里面的所有代码:

from snippets.models import Snippet
from snippets.permissions import IsOwnerOrReadOnly
from snippets.serializers import SnippetSerializer, UserSerializer
from django.contrib.auth.models import User
from rest_framework import viewsets
from rest_framework.decorators import api_view
from rest_framework.reverse import reverse
from rest_framework import permissions
from rest_framework import renderers
from rest_framework.decorators import action
from rest_framework.response import Responseclass UserViewSet(viewsets.ReadOnlyModelViewSet):"""这viewset自动提供“列表”和“检索”操作。"""queryset = User.objects.all()serializer_class = UserSerializerclass SnippetViewSet(viewsets.ModelViewSet):"""这ViewSet自动提供“list”、“create”、“retrieve”,'update'和'destroy'(也就是删除)操作。此外,我们还提供了一个额外的“突出显示”动作。"""queryset = Snippet.objects.all()serializer_class = SnippetSerializerpermission_classes = [permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly]##原来对应的视图类=》SnippetHighlight@action(detail=True, renderer_classes=[renderers.StaticHTMLRenderer])def highlight(self, request, *args, **kwargs):snippet = self.get_object()return Response(snippet.highlighted)def perform_create(self, serializer):serializer.save(owner=self.request.user)

第二步:将 ViewSet 显式绑定到 URL

#在urls.py替换所有代码
"""
djangoProject项目的URL配置。
“urlpatters”列表将URL路由到视图。有关更多信息,请参阅:
https://docs.djangoproject.com/en/4.2/topics/http/urls/
示例:
功能视图1.添加导入:从my_app导入视图2.将URL添加到URL模式:path('',views.home,name='home')
基于类的视图1.添加导入:from other_app.views import Home2.将URL添加到URL模式:path('',Home.as_view(),name='Home')
包括另一个URLconf1.导入include()函数:从django.url导入include,path2.将URL添加到URL模式:path('blog/',include('blog.urls'))
"""
from django.urls import path, include
from rest_framework import renderers
from rest_framework.urlpatterns import format_suffix_patternsfrom snippets.views import api_root, SnippetViewSet, UserViewSetsnippet_list = SnippetViewSet.as_view({'get': 'list','post': 'create'
})
snippet_detail = SnippetViewSet.as_view({'get': 'retrieve','put': 'update','patch': 'partial_update','delete': 'destroy'
})
snippet_highlight = SnippetViewSet.as_view({'get': 'highlight'
}, renderer_classes=[renderers.StaticHTMLRenderer])user_list = UserViewSet.as_view({'get': 'list'
})
user_detail = UserViewSet.as_view({'get': 'retrieve'
})urlpatterns = [path('', api_root),path('snippets/', snippet_list, name='snippet-list'),path('snippets/<int:pk>/', snippet_detail, name='snippet-detail'),path('snippets/<int:pk>/highlight/', snippet_highlight, name='snippet-highlight'),path('users/', user_list, name='user-list'),path('users/<int:pk>/', user_detail, name='user-detail')
]
# 可浏览API的登录和注销视图
urlpatterns += [path('api-auth/', include('rest_framework.urls',  namespace='rest_framework')),
]urlpatterns = format_suffix_patterns(urlpatterns)

访问:http://127.0.0.1:8000/,发现是平替原来的接口功能,同时代码少了不少。但是还是不够好,这边配置url很麻烦,需要对应视图的get put等请求以及方法,其实通用的东西是一样的。有没有更简单的方式?这时候我们可以使用路由。

使用路由(Routes)

因为我们使用的是类而不是类,所以我们实际上不需要自己设计 URL 配置。使用类可以自动处理将资源连接到视图和 URL 的约定。我们需要做的就是向路由器注册适当的视图集,然后让它完成剩下的工作。

##snippets/urls.pyfrom django.urls import path, include
from rest_framework.routers import DefaultRouter
from snippets import views# Create a router and register our ViewSets with it.
router = DefaultRouter()
router.register(r'snippets', views.SnippetViewSet, basename='snippet')
router.register(r'users', views.UserViewSet, basename='user')#API URL现在由路由器自动确定
urlpatterns = [path('', include(router.urls)),
]# 可浏览API的登录和注销视图
urlpatterns += [path('api-auth/', include('rest_framework.urls',  namespace='rest_framework')),
]##这边不在需要格式化 url
#urlpatterns = format_suffix_patterns(urlpatterns)

小结

使用 ViewSet 不如单独构建 API 视图明确。因为api我们对请求方式和处理细节掌握的很到位,但视图集却很抽象。

四、根据model迁移数据库

实际每次会增加一些新的model和view

python manage.py makemigrations [项目名称] 
python manage.py migrate [项目名称] ## 示例 我这个项目是snippets 我创建了TBook这个表
## 执行以下命令后 生成了snippets_tbook这个表
python manage.py makemigrations snippets
python manage.py migrate snippets

在这里插入图片描述

五、python manage.py 常用命令

Available subcommands:[auth] 创建超级管理员和修改密码changepasswordcreatesuperuser[django] 校验 刷新 dump数据 建立project或app checkdumpdataflushloaddatamakemigrationsmigratesqlmigratestartappstartproject[sessions]  清除所有sessionclearsessions[staticfiles] 运行项目等等collectstaticfindstaticrunserver

六、界面汉化与管理后台

1.汉化

# 将以下配置覆盖 settings.py 原来的 里面信息 ,如果Django 版本低于2.0 可以把LANGUAGE_CODE设置成 'zh-cn'
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_TZ = FALSE

2.访问管理后台

# 在urls.py里面增加“path('admin/', admin.site.urls)” 如图所示
urlpatterns = [path('admin/', admin.site.urls),# 其他配置不变
]

接着我们就可以访问管理后台了:

在这里插入图片描述
在这里插入图片描述

七、使用Core API(核心api)

Core API是用于描述API的文档规范。它用于提供可用路径的内部表示形式和API公开的可能的交互。它可以用于服务器端或客户端。

当使用服务器端时,coreAPI允许API支持呈现范围广泛的概要或超媒体格式。

当使用客户端时,核心API允许动态驱动的客户端库,它可以与任何公开受支持的概要或超媒体格式的API交互。

基于 coreapi-2.3.3

pip3 install coreapi
pip3 install pyyam

现在我们可以通过在URL配置中包含一个自动生成的概要视图来为API,下面是需要新添加的,不要直接覆盖你原有配置

##snippets/urls.py
#需要导入的包
from rest_framework.schemas import get_schema_view
schema_view = get_schema_view(title='Pastebin API')# API URL现在由路由器自动确定
urlpatterns = [# settings....path('schema/', schema_view),
]

访问:http://127.0.0.1:8000/schema/
在这里插入图片描述

八、自定义ViewSet

创建一个 custom/viewset.py,代码如下 这个我是让增删改都是post请求,国内你懂的 很少使用delete put patch这类的请求

#!/usr/bin/python3
# -*- coding: utf-8 -*-
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.mixins import CreateModelMixin, UpdateModelMixin, DestroyModelMixin# basename- 用于创建的 URL 名称的基础。
# action- 当前操作的名称(例如:list create)。
# detail- 布尔值,指示当前操作是否配置为列表或详细信息视图。
# suffix- 视图集类型的显示后缀 - 镜像属性。detail
# name- 视图集的显示名称。此参数与 互斥。suffix
# description- 视图集的单个视图的显示说明。
from rest_framework.settings import api_settingsclass CreateRetrieveViewSet(viewsets.ReadOnlyModelViewSet):lookup_field = 'pk'# , permission_classes=[IsAdminOrIsSelf]@action(detail=False, methods=['get', 'post'], name="addItem", description="新增")def addItem(self, request, *args, **kwargs):return CreateModelMixin.create(self, request, args, kwargs)# 需要嵌入详情里面@action(detail=True, methods=['post'], name="updateItem", description="通过主键更新")def updateItem(self, request, *args, **kwargs):return UpdateModelMixin.update(self, request, args, kwargs)# 参数“pk”放在url和放在请求体里面都可以更新@action(detail=False, methods=['post'], name="updateBypk", description="通过主键更新")def updateBypk(self, request, *args, **kwargs):self.lookup_field = 'pk'if "pk" not in request.data:pk = request.query_params.get('pk', None)kwargs = {"pk": pk}self.kwargs = {"pk": pk}else:self.kwargs = {"pk": request.data["pk"]}kwargs = {"pk": request.data["pk"]}return UpdateModelMixin.update(self, request, args, kwargs)# 参数“pk”放在url和放在请求体里面都可以删除# 如果需要后面携带参数 pk=xx 这种 detail设置为False@action(detail=False, methods=['post'], name="deleteItem", description="通过主键删除")def deleteBypk(self, request, *args, **kwargs):self.lookup_field = 'pk'pk = Noneif "pk" not in request.data:pk = request.query_params.get('pk', None)self.kwargs = {'pk': pk}else:pk = request.data["pk"]self.kwargs = {"pk": request.data["pk"]}return DestroyModelMixin.destroy(self, request, pk)@action(detail=True, methods=['post'], name="deleteByPathVar", description="通过路径携带id进行删除")def deleteItem(self, request, pk=None):return DestroyModelMixin.destroy(self, request, pk)@classmethoddef get_success_headers(self, data):try:return {'Location': str(data[api_settings.URL_FIELD_NAME])}except (TypeError, KeyError):return {}@classmethoddef perform_update(self, serializer):serializer.save()@classmethoddef partial_update(self, request, *args, **kwargs):kwargs['partial'] = Truereturn self.update(request, *args, **kwargs)@classmethoddef perform_destroy(self, instance):instance.delete()

然后在你需要的ViewSet里面改变他的实现类,换成这个CreateRetrieveViewSet

class TBookManagerViewSet(CreateRetrieveViewSet):"""这ViewSet自动提供“list”、“create”、“retrieve”,'update'和'destroy'(也就是删除)操作。"""queryset = TBookManager.objects.all()serializer_class = TBookManagerSerializerpermission_classes = [permissions.NOT]def perform_create(self, serializer):serializer.save(owner=self.request.user)
#实体 model
class TBookManager(models.Model):created = models.DateTimeField(auto_now_add=True)name = models.TextField()entry_time = models.DateTimeField()gender = models.CharField(choices=[('man','男'),('woman','女')], default='man', max_length=5)## 增加模型的权限用户owner = models.ForeignKey('auth.User', related_name='tbookmanager', on_delete=models.CASCADE)class Meta:ordering = ['created']#序列化      
class TBookSerializer(serializers.ModelSerializer):owner = serializers.ReadOnlyField(source='owner.username')class Meta:model = TBookfields = ['book_name', 'book_code', 'author', 'push_time', 'owner', 'url']

请求方式:

## 删除
> http://localhost:8000/bookmanager/10/deleteItem
> http://localhost:8000/bookmanager/deleteBypk/?pk=9
> http://localhost:8000/bookmanager/deleteBypk/ 
> (参数可放form-data里面)
> ##更新
> http://localhost:8000/bookmanager/9/updateItem
> http://localhost:8000/bookmanager/updateBypk/ ?pk=9
>  http://localhost:8000/bookmanager/updateBypk/ 
>  (参数可放form-data里面)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/312498.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

自动驾驶学习笔记(二十四)——车辆控制开发

#Apollo开发者# 学习课程的传送门如下&#xff0c;当您也准备学习自动驾驶时&#xff0c;可以和我一同前往&#xff1a; 《自动驾驶新人之旅》免费课程—> 传送门 《Apollo开放平台9.0专项技术公开课》免费报名—>传送门 文章目录 前言 控制算法 控制标定 控制协议…

【数据结构】详细剖析线性表

顺序表与链表的比较 导言一、线性表二、线性表的存储结构三、顺序表和链表的相同点四、顺序表与链表之间的差异五、存储结构的选择六、静态顺序表的基本操作七、无头结点单链表的基本操作结语 导言 大家好&#xff0c;很高兴又和大家见面啦&#xff01;&#xff01;&#xff0…

普中STM32-PZ6806L 使用FlyMcu串口烧录程序

简介 我的串口下载电路坏掉了, 所以研究了下如何通过USB转TTL进行程序的下载, 为后续Bootloader部分做准备;连接 我的板几乎是十年前买的&#xff0c; 所以电路与现有网上的资料有些差异, 所以仅供参考 USB 转 TTL线 与开发板 连接&#xff0c; 如图图中 ①, 需要去掉第一个…

Android14新特性 开启前台service服务

1. Android14新特性 1.1. 场景 在Android14&#xff08;targetSDK34&#xff09;系统手机开启前台service服务崩溃 ATAL EXCEPTION: mainProcess: com.inspur.lbrd, PID: 15634java.lang.RuntimeException: Unable to create service com.inspur.lbrd.service.KeepAliveServi…

软件工程PPT 笔记摘录(2)

分析软件需求 UML 提供了用例图来分析和描述用例视角的软件需求模型 UML 提供了交互图和状态图来描述行为视角的软件需求模型 UML 提供了类图来描述和分析业务领域的概念模型 顺序图&#xff1a;强调消息传递的时间序 通信图&#xff1a;突出对象间的合作 类图&#xff0…

使用docker build构建image

文章目录 环境步骤准备例1&#xff1a;基本用法例2&#xff1a;缓存layer例3&#xff1a;Multi-stage例4&#xff1a;Mountcache mountbind mount 例5&#xff1a;参数例6&#xff1a;Export文件例7&#xff1a;测试 参考 环境 RHEL 9.3Docker Community 24.0.7 步骤 在Dock…

Android 实现 Slots 游戏旋转效果

文章目录 前言一、效果展示二、代码实现1.UI布局2.SlotAdapter2.SlotsActivity 总结 前言 slots游戏&#xff1a; Slots游戏是一种极具流行度的赌博和娱乐形式&#xff0c;通常被称为老虎机或水果机。它们在赌场、线上游戏平台和手机应用中广泛存在。一般这类游戏都使用Unity…

硬件安全模块 (HSM)、硬件安全引擎 (HSE) 和安全硬件扩展 (SHE)的区别

术语 硬件安全模块 (HSM) &#xff1a;Hardware Security Modules硬件安全引擎 (HSE) &#xff1a;Hardware Security Engines安全硬件扩展 (SHE) &#xff1a; Secure Hardware Extensions 介绍 在汽车行业中&#xff0c;硬件安全模块 (HSM)、硬件安全引擎 (HSE) 和安全硬件…

HTML与CSS

目录 1、HTML简介 2、CSS简介 2.1选择器 2.1.1标签选择器 2.1.2类选择器 2.1.3层级选择器(后代选择器) 2.1.4id选择器 2.1.5组选择器 2.1.6伪类选择器 2.2样式属性 2.2.1布局常用样式属性 2.2.2文本常用样式属性 1、HTML简介 超文本标记语言HTML是一种标记语言&…

Spring Cloud + Vue前后端分离-第10章 基于阿里云OSS的文件上传

源代码在GitHub - 629y/course: Spring Cloud Vue前后端分离-在线课程 Spring Cloud Vue前后端分离-第10章 基于阿里云OSS的文件上传 前面介绍的文件上传是基于本地文件服务器的文件上传&#xff0c;但是自己搭文件服务器会有很多运维的问题&#xff0c;比如磁盘满了要扩容…

第一节 Linux操作系统简介

一&#xff1a;Linux的发展历史 1&#xff1a;1969年美国贝尔实验室的肯• 汤普森开发出了UNIX系统。   2&#xff1a;1973年&#xff0c;UNIX系统的绝大部分源代码用C语言重写&#xff0c;为提高UNIX系统的可移植性打下基础。   3&#xff1a;Linux系统诞生于1991年&#…

前端实现埋点监控

文章目录 一、埋点&监控二、前置知识1. 区分JS模块化2. rollup3. History3.1 history.pushState()3.2 history.replaceState()3.3 popstate事件 4. JS二进制4.1 Blob4.2 File4.3 FileReader4.4 ArrayBuffer4.5 Object URL4.6 Base644.7 格式转换 5. sendBeacon发送请求 三、…