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.mzph.cn/news/588194.shtml

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

相关文章

【unity中使用高度图创建地图】

unity中使用高度图创建地图 插件 讲解案例为unity2022版本 这个是插件地址 也可以在资源商店中搜索 terrain-tools 介绍 Terrain Tools入门Terrain Tools是一个软件包&#xff0c;你可以选择将其添加到Unity 2019.1或更高版本中的任何项目中。要将该软件包添加到你的项目…

准备好通过 “Breakin’ B.I.G.” 在嘻哈音乐界大放异彩吧!

在 The Sandbox 推出人物化身系列后&#xff0c;是时候通过 “Breakin’ B.I.G.” 重返嘻哈音乐的黄金时代了。该体验于 12 月 20 日推出&#xff0c;一直持续到 1 月 3 日&#xff0c;让玩家回到 20 世纪 90 年代&#xff0c;体验以 Notorious B.I.G 为主角的 2D 街舞游戏。 获…

初始Web服务器

一、web服务器 1、什么是web服务器&#xff1f; web服务器就是web项目的容器&#xff0c;我们将开发好的web项目部署到web容器中&#xff0c;才能使用网络中的用户通过浏览器进行访问。 一张图带你了解web服务器有啥作用&#xff1a; 在我的电脑上有一个已经做好的项目&#…

网络通信-入门1

网口框架 100M 2. 物理层解读 2.1 同步的方法&#xff1a;编码 为了让接收方在没有外部时钟参考的情况也能确定每一位的起始、结束和中间位置&#xff0c;在传输信号时不直接采用二进制编码。在 10BASE-T 的传输方式中采用曼彻斯特编码&#xff0c;在 100BASE-T 中则采用 4B/…

分布式技术之流量控制技术

文章目录 什么是流量控制&#xff1f;分布式系统流量控制策略漏桶策略令牌桶策略两种策略对比Sentinel 流量控制工作原理 什么是流量控制&#xff1f; 流量控制&#xff0c;如果学过计算机网络的话&#xff0c;第一反应肯定是网络传输中的流量控制。网络传输中的流量控制&…

家政行业的小程序都需要具备哪些功能?

家政服务小程序&#xff0c;覆盖多城&#xff0c;在线派单 适合行业&#xff1a;家电维修、家政保洁、养生护理、美容美发、预约服务上门等 系统功能&#xff1a;服务管理、商品管理、拼团/秒杀、订单管理、会员管理、派单管理、师傅管理、商家/服务点、财务管理、城市代理、次…

arkts中@Watch监听的使用

概述 Watch用于监听状态变量的变化&#xff0c;当状态变量变化时&#xff0c;Watch的回调方法将被调用。Watch在ArkUI框架内部判断数值有无更新使用的是严格相等&#xff08;&#xff09;&#xff0c;遵循严格相等规范。当在严格相等为false的情况下&#xff0c;就会触发Watch的…

Apollo自动驾驶系统:实现城市可持续交通的迈向

前言 「作者主页」&#xff1a;雪碧有白泡泡 「个人网站」&#xff1a;雪碧的个人网站 ChatGPT体验地址 文章目录 前言引言&#xff1a;1. 什么是微服务架构&#xff1f;2. 微服务架构的组成要素3. 微服务架构的挑战和解决方案4. 微服务架构的可扩展性和弹性 第二部分&#x…

ACW741.斐波那契额数列

输入整数 N&#xff0c;求出斐波那契数列中的第 N项是多少。 斐波那契数列的第 0项是 0&#xff0c;第 1项是 1&#xff0c;从第 2 项开始的每一项都等于前两项之和。输入格式 第一行包含整数 T&#xff0c;表示共有T个测试数据。接下来 T行&#xff0c;每行包含一个整数 N。输…

LeetCode刷题--- 黄金矿工

个人主页&#xff1a;元清加油_【C】,【C语言】,【数据结构与算法】-CSDN博客 个人专栏 力扣递归算法题 http://t.csdnimg.cn/yUl2I 【C】 ​​​​​​http://t.csdnimg.cn/6AbpV 数据结构与算法 ​​​​http://t.csdnimg.cn/hKh2l 前言&#xff1a;这个专栏主要讲述…

【Proteus仿真】【STM32单片机】自动除湿器系统

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真STM32单片机控制器&#xff0c;使用按键、LCD1602液晶、DHT11温湿度、继电器除湿模块等。 主要功能&#xff1a; 系统运行后&#xff0c;LCD1602显示DHT11传感器检测的湿度值阈值…

[JS设计模式]Prototype Pattern

Prototype pattern Prototype pattern可便于同类型的多个对象共享属性。原型&#xff08;prototype&#xff09;是JS原生的对象&#xff0c;其他对象可以通过原型链&#xff08;prototype chain&#xff09;来访问原型。单独看这句描述可能还是有点儿抽象&#xff0c;下面通过…

深度解析ShardingJDBC:Java开发者的分库分表利器

一、ShardingSphere ShardingSphere 是一款起源于当当网内部的应用框架。2015年在当当网内部诞 生&#xff0c;最初就叫ShardingJDBC 。2016年的时候&#xff0c;由其中一个主要的开发人员张亮&#xff0c; 带入到京东数科&#xff0c;组件团队继续开发。在国内历经了当当网、电…

Unity 新版 Meta XR SDK 无法导入解决方法

文章目录 &#x1f4d5;教程说明&#x1f4d5;新版 SDK 说明&#x1f4d5;从 Meta 官网导入开发包⭐依赖包⭐如何导入⭐导入后包存放在哪里了&#xff1f;⭐场景样例文件去哪了&#xff1f; 此教程相关的详细教案&#xff0c;文档&#xff0c;思维导图和工程文件会放入 Spatia…

报表控件FastReport VCL 中的新 S3 传输 (Amazon)

在本文中&#xff0c;我们将探讨新的 S3 传输。从功能上来说&#xff0c;S3 与大多数人习惯使用的有很大不同&#xff0c;因此在本文的开头&#xff0c;我们将详细介绍它的主要功能。 FastReport .NET 是适用于.NET Core 3&#xff0c;ASP.NET&#xff0c;MVC和Windows窗体的全…

软件测试/测试开发丨Python内置库学习笔记

内置库 一、内置库OS 1、os概述 os: Operating Systemos 模块的常用功能跨平台的差异 2、os使用 导入 os 模块查看 os 模块使用文档 help(os)dir(os) import os# 查看os模块说明文档 help(os)# 查看os模块的属性和方法 print(dir(os))3、os 常用方法 &#xff08;1&…

全渠道客服系统推荐:选型指南与最佳实践分享

售后服务是影响客户满意度的最直接的因素。有些企业不注重产品的售后服务&#xff0c;不仅是对客户的伤害&#xff0c;更是对企业品牌的损害。所以&#xff0c;做好售后服务对于企业来讲至关重要。 企业谈到做好售后服务&#xff0c;少不了一款好用的客服系统工具。其中&#…

C# PrinterSettings修改打印机纸张类型,paperType

需求&#xff1a;直接上图&#xff0c;PrinterSettings只能改变纸张大小&#xff0c;打印质量&#xff0c;无法更改打印纸类型 爱普生打印机打印照片已经设置了最高质量&#xff0c;打印图片仍不清晰&#xff0c;需要修改打印纸类型&#xff0c;使用PrintDialog调出对话框&…

2023-12-30 AIGC-LangChain介绍

摘要: 2023-12-30 AIGC-LangChain介绍 LangChain介绍 1. https://youtu.be/Ix9WIZpArm0?t353 2. https://www.freecodecamp.org/news/langchain-how-to-create-custom-knowledge-chatbots/ 3. https://www.pinecone.io/learn/langchain-conversational-memory/ 4. https://de…

乒乓球室计时计费软件,乒乓球馆怎么计时

一&#xff0c;软件程序问答 1、软件有计时功能吗&#xff0c;有会员管理功能吗&#xff1f; 如下图&#xff0c;软件以 佳易王乒乓球馆计时计费软件 为例说明 软件既可以既可以计时计费&#xff0c;也可以会员管理&#xff0c;会员可以用卡片也可以直接用手机号即可。 2、软…