当前位置: 首页 > 工具软件 > bs framework > 使用案例 >

python rest framework_python - Django - restframework 简单使用 和 组件

辛可人
2023-12-01

FBV 和 CBV

CBV 通过函数调用方法

FBV 通过类调用方法

其本质上都是 CBV

但是 FBV 内部封装了关于 method 的方法,由于基本上都是前端的请求,所有像GET,POST等方法用的频繁,

而CBV将这些方法封装了起来,使得开发时更便捷了许多,所以CBV更适合写接口

######  标准的  ######

2.1 fbv方式请求的过程

用户发送url请求,Django会依次遍历路由映射表中的所有记录,一旦路由映射表其中的一条匹配成功了,

就执行视图函数中对应的函数名,这是fbv的执行流程

2.2 cbv方式请求的过程

当服务端使用cbv模式的时候,用户发给服务端的请求包含url和method,这两个信息都是字符串类型

服务端通过路由映射表匹配成功后会自动去找dispatch方法,然后Django会通过dispatch反射的方式找到类中对应的方法并执行

类中的方法执行完毕之后,会把客户端想要的数据返回给dispatch方法,由dispatch方法把数据返回经客户端

一:下载

pip install djangorestframewrok

二:Views

#restframework 常用的类

from rest_framework.views importAPIViewfrom rest_framework.generics importGenericAPIViewfrom rest_framework.viewsets importGenericViewSetfrom rest_framework.viewsets importModelViewSetfrom rest_framework.response import Response

写法1:

--

from rest_framework importserializers

(1)和 models 表中的字段对应 (使用模块:serializers.Serializer)

(2)全部字段直接写(使用模块:serializers.ModelSerializer)classMeta:

model=models.Book

fields= '__all__'(3)使用时需要调用 BookModelSerializers(queryset/data,many=True/False)

注:当需要返回一个 queryset 的时候必须加 many=True 这个参数,单条数据则不用--

----------Url----------

from app01 importviews

re_path('book/$',views.BookView.as_view())----------View----------

from rest_framework importserializersclassBookModelSerializers(serializers.ModelSerializer):

title=serializers.CharField()

price=serializers.CharField()

publish=serializers.CharField()from rest_framework.views importAPIViewfrom rest_framework.views importResponse#更新操作:

defput(self,request,pk):

shop= models.Shop.objects.filter(pk=pk).first()

bs= ShopSerializers(shop,data=request.data)if bs.is_valid(): #判断数据是否有误

print('bs:',bs)

bs.save()#相当于调用了 updata方法

return Response(bs.data) #返回 数据

else:returnResponse(bs.errors)#添加操作:

ps = PublishSerializers(data=request.data)ifps.is_valid():

ps.save()#create

#查询操作:

classBookView(APIView):defget(self,request):

book_list=models.Book.objects.all()

serializers= BookModelSerializers(book_list,many=True)returnResponse(serializers.data)#删除操作:

defdelete(self,request,pk):

models.Shop.objects.filter(pk=pk).delete()return Response()

写法2:

--(a)

(1)mixins 模块中有 List,Create,Put...方法可以直接使用

(2)generics 主要作用还是调用 APIView 中的--

----------Url----------

from app01 importviews

re_path('book/$',views.BookView.as_view())----------View (a)----------

from rest_framework importmixinsfrom rest_framework importgenericsfrom rest_framework importserializersfrom rest_framework importserializersclassBookModelSerializers(serializers.ModelSerializer):

title=serializers.CharField()

price=serializers.CharField()

publish=serializers.CharField()classAuthorView(mixins.ListModelMixin,generics.GenericAPIView):

queryset= models.Author.objects.all() #必须有的参数 :queryset

serializer_class = AuthorModelSerializers #必须有的参数 :serializer_class

def get(self,request,*args,**kwargs):return self.list(request,*args,**kwargs)--(b)

(1)继承 generics.RetrieveUpdateDestroyAPIView

将上面的 mixins generics 全部封装成了一个模块--

----------View (b)----------比上面简单一点classUserView(generics.RetrieveUpdateDestroyAPIView):

queryset=models.User.objects.all()

serializer_class= UserModelSerializers

写法三:

--(1) as_view({参数})

中传的参数是必须的,参数的名称还是固定的,

可根据需求来限定哪个url配定哪个参数

(2) view 中 的变量名也是固定的,不能改变,

当执行到某个父类的方法的时候,就会需要这两个参数

queryset--queryset

serializer_class--

----------Url----------

from app01 importviews

re_path('book/$', views.Book.as_view({'get': 'list', 'post': 'create'})),

re_path('book/(?P\d+)/$', views.Book.as_view({'get': 'retrieve', 'put': 'update','delete':'destroy'})),----------View----------

from rest_framework importviewsetsclassBook(viewsets.ModelViewSet):

queryset=models.Book.objects.all()

serializer_class= BookModelSerializers

四:认证组件

---------- View(局部认证) ----------

--(1) BaseAuthentication 模块中 有俩个方法(authenticate , authenticate_header)

注:这俩个方法也是固定名字,两个必须写上,一个都不能少,否则报错 !

模块中这两个方法都是返回空的,但是执行的时候当前函数就将

两个方法覆盖了,也就是少些一个 authenticate_header

(2) 创建一个 返回 随机字符的 token

(3) update_or_create --如果有就更新,如果没有就创建--

#认证 组件

from rest_framework importexceptionsfrom rest_framework.authentication importBaseAuthenticationfrom app01 importmodelsclassTokenAuth(BaseAuthentication): # 这个方法直接写在一个文件中defauthenticate(self,request):

token= request.GET.get('token') #获取 token

token_obj = models.Token.objects.filter(token=token).first() #验证 token 是否匹配

if nottoken_obj:raise exceptions.AuthenticationFailed('验证失败')else:returntoken_obj.user.name,token_obj.token#返回一个 登陆校验判断 的随机字符串

defget_random_str(user):importhashlib,time

ctime= str(time.time()) #当前时间字符串

md5= hashlib.md5(bytes(user,encoding='utf8')) #md5 加密,加盐

md5.update(bytes(ctime,encoding='utf8')) #将字符串进行拼接

#md5.digest() 二进制

#md5.hexdigest() 十六进制

return md5.hexdigest() #返回一个 十六进制 的加密随机字符

#登陆验证

classLoginView(APIView):

authentication_classes= [TokenAuth]

defpost(self,request):

name= request.data.get('name') #获取用户名

pwd = request.data.get('pwd') #获取密码

user = models.User.objects.filter(name=name,pwd=pwd).first() #数据库校验

res = {'code':0,'msg':None}ifuser:

random_str=get_random_str(user.name)

token= models.Token.objects.update_or_create(user=user,defaults={'token':random_str}) #在数据库生成 token

res['token'] =random_str

res['code'] = 1res['msg'] = '验证成功'

else:

res['msg'] = '验证失败'

importjsonreturnResponse(json.dumps(res))---------- View(全局认证) ----------(1) settings 中配置 认证组件位置:#全局认证组件

REST_FRAMEWORK ={"DEFAULT_AUTHENTICATION_CLASSES": ["app01.utils.TokenAuth",]

}

(2) 这样就不用写 authentication_classes =[TokenAuth]

(3) 如果哪个方法不需要认证的话 只需要 authentication_classes = [] 将列表设为空

五:权限组件

#权限组件

classSvipPermission(object):  #这个方法直接写在一个文件中

message= "只有超级用户才能访问"

defhas_permission(self,request,view):

username=request.user

user_type= models.User.objects.filter(name=username).first().user_typeif user_type == 3:return True #返回True 则验证通过

else:return False #返回False 则验证不通过

# 只需类下面添加permission_classes = [SvipPermission] # 权限组件 -- 局部

# 全局认证

REST_FRAMEWORK = {

"DEFAULT_PERMISSION_CLASSES":['app01.utils.SvipPermission'], # 全局权限组件

}

六:解析器 (用于将解析字符格式)

from rest_framework.parsers importJSONParser,FormParser

parser_classes= [JSONParser, FormParser] #局部(用于将解析字符格式)

七:频率组件:

- 自定义:

#定义一个频率认证类 - 之后在视图配置

importtimefrom rest_framework.throttling importBaseThrottleclassMyThrottle(BaseThrottle):

visited_record={}def __init__(self):

self.history=Nonedefallow_request(self, request, my_cbv):#这个my_cbv是源码中传的我们的视图类,这里我们也要传进去

#print(self.get_ident(request)) # 可以获取本次请求的ip

ip = request.META.get("REMOTE_ADDR")if ip not inself.visited_record:

self.visited_record[ip]=[]

current_time=time.time()

history=self.visited_record[ip]

self.history=historyprint(history)while history and current_time - history[-1] > 60: #把大于60秒的时间都删掉

history.pop()if len(history) > 2: #第三次访问,列表中只有2个值,也满足条件

returnFalse

history.insert(0, current_time)returnTruedefwait(self):"""用于返回还剩多少时间访问;

本次访问时间:9:50:55

[09:50:30, 09:50:20, 09:50:10] 剩余 60 - (9:50:55 - 09:50:10)秒才能访问

:return:"""c_time=time.time()return 60 - (c_time - self.history[-1])#### 局部使用 ####

from rest_framework importgenericsfrom rest_framework importmixinsfrom app01.utils.frequency importMyThrottleclassListView(generics.GenericAPIView, mixins.ListModelMixin, mixins.CreateModelMixin):

throttle_classes=[MyThrottle]def get(self, request, *args, **kwargs):return Response('ok')#### 全局使用 ####

REST_FRAMEWORK ={'DEFAULT_PARSER_CLASSES': ('rest_framework.parsers.JSONParser','rest_framework.parsers.FormParser','rest_framework.parsers.MultiPartParser'),'DEFAULT_THROTTLE_CLASSES': ('app01.utils.frequency.MyThrottle',

),

}

- 内置

#### 定义类 ####

from rest_framework.throttling importSimpleRateThrottleclassMyThrottle(SimpleRateThrottle):

scope= "visit_rate" #这个值决定了在配置时使用那个变量描述限制的频率

def get_cache_key(self, request, view): #这个方法也是必须要有

returnself.get_ident(request)#### 只能在全局使用 ####

REST_FRAMEWORK ={'DEFAULT_THROTTLE_CLASSES': ('app01.utils.throttle_class.MyThrottle',

),"DEFAULT_THROTTLE_RATES": {"visit_rate": "10/m",#这个参数就是频率类中定义的那个参数scope, 其中第一个数字10表示10次,后面的m表示一分钟,还有s,一秒, h, 一小时, d, 一天

}

}

八:分页器 -- 用于 restframework 内置的调试页面

# 要使用 restframework 自带的调试数据网页 需要在 settings 中配置

INSTALLED_APPS = [

'django.contrib.admin',

'django.contrib.auth',

'django.contrib.contenttypes',

'django.contrib.sessions',

'django.contrib.messages',

'django.contrib.staticfiles',

'app01.apps.App01Config',

'rest_framework',  # 配置 restframework 组件

]#分页器

from rest_framework.pagination importPageNumberPaginationclassBookPageNumberPagination(PageNumberPagination):

page_size= 1 #每页显示个数

page_query_param = 'page'page_size_query_param= 'size' #修改当前页显示个数

#max_page_size = 2 # 每页显示个数限制

classBookView(APIView):defget(self,request):

book_list=models.Book.objects.all()#分页器

pnp =BookPageNumberPagination()

book_page=pnp.paginate_queryset(book_list,request,self)

bs= BookModelSerializers(book_page,many=True,context={'request': request})return Response(bs.data)

 类似资料: