Django后端项目---- rest framework(3)
一、版本
程序也来越大时,可能通过版本不同做不同的处理
没用rest_framework之前,我们可以通过以下这样的方式去获取。
- class UserView(APIView):
- def get(self,request,*args,**kwargs):
- version = request.query_params.get('version')
- print(version)
- if version=='v1':
- #如果版本是v1
- ret = {
- 'code':111,
- 'msg':'版本一的内容'
- }
- elif version=='v2':
- # 如果是v2
- ret = {
- 'code': 112,
- 'msg': '版本二的内容'
- }
- else:
- ret = {
- 'code': 0,
- 'msg': '不支持其他版本'
- }
- return Response(ret)
现在我们来用rest_framework实现一下,有两种方式
1、基于url的方式
- #基于url传参的形式
- versioning_class = QueryParameterVersioning
- #http://127.0.0.1:8080/api/users/?version=v2
- #基于url的形式
- versioning_class = URLPathVersioning
- #http://127.0.0.1:8080/api/v1/users/
具体步骤
- REST_FRAMEWORK = {
- 'DEFAULT_VERSION': 'v1', #默认的版本
- 'ALLOWED_VERSIONS': ['v1','v2'], #允许的版本
- 'VERSION_PARAM': 'version',
- }
1、配置
- from django.conf.urls import url,include
- from django.contrib import admin
- urlpatterns = [
- url(r'^admin/', admin.site.urls),
- url(r'^api/(?P<version>[v1|v2]+)/', include('api.urls'), name='users-list'),
- ]
urls.py
- from api import views
- urlpatterns = [
- # url(r'^users/', views.UserView.as_view()),
- url(r'^users/', views.UserView1.as_view()),
- ]
urls.py
- class UserView1(APIView):
- #基于url传参的形式
- # versioning_class = QueryParameterVersioning
- #http://127.0.0.1:8080/api/users/?version=v2
- #基于url的形式
- #http://127.0.0.1:8080/api/v1/users/
- versioning_class = URLPathVersioning
- def get(self,request,*args,**kwargs):
- # self.dispatch
- print(request.version) #打印的是版本
- print(request.versioning_scheme) #打印的是对象
- if request.version=='v2':
- return Response('我是版本二')
- elif request.version=='v1':
- return Response('我是版本一')
- else:
- return Response('去去去')
views.py
注:在配置的时候
- REST_FRAMEWORK = {
- 'VERSION_PARAM':'version',
- 'DEFAULT_VERSION':'v1',
- 'ALLOWED_VERSIONS':['v1','v2'],
- # 'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.HostNameVersioning"
#如果加上这个配置就不用versioning_class = QueryParameterVersioning这样在指定了,
- 'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.URLPathVersioning" }
附加:restful提供的反向生成
#http://127.0.0.1:8080/api/v1/users/
- #urls.py
- #分发路由
- urlpatterns = [
- url(r'^admin/', admin.site.urls),
- url(r'^api/(?P<version>[v1|v2]+)/', include('api.urls')),
- ]
- #api.urls.py
- urlpatterns = [
- url(r'^users/', views.UserView1.as_view(), name='users-list'),
- ]
- #views.py
- 导入类
- from rest_framework.reverse import reverse
- url = request.versioning_scheme.reverse(viewname='users-list',request=request)
- print(url)
restfoamework反向解析
我们自己用django实现的,当前版本不一样的时候可以用这种方式
- from django.urls import reverse
- url = reverse(viewname='users-list',kwargs={'version':'v2'}) #指定的是v2就是v2,当你路径中输入v1的时候还是v2的路径
- print(url) #/api/v2/users/
2、基于子域名传参
- #分发url
- urlpatterns = [
- #url(r'^admin/', admin.site.urls),
- url(r'^api/', include('api.urls')),
- ]
- urlpatterns = [
- url(r'^users/', views.UsersView.as_view(),name='u'),
- ]
- class UsersView(APIView):
- def get(self,request,*args,**kwargs):
- self.dispatch
- print(request.version) # QueryParameterVersioning().detemiin_version()
- print(request.versioning_scheme) # QueryParameterVersioning()
- REST_FRAMEWORK = {
- 'VERSION_PARAM':'version',
- 'DEFAULT_VERSION':'v1',
- 'ALLOWED_VERSIONS':['v1','v2'],
- 'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.HostNameVersioning"
- }
- # C:\Windows\System32\drivers\etc
- # vim /etc/hosts
- 127.0.0.1 v1.luffy.com
- 127.0.0.1 v2.luffy.com
- #配置ALLOWED_HOSTS = ['*']
基于子域名传参
如果遇到这样的错误
这是由于没有允许,解决办法,在settings里面配置一下
- ALLOWED_HOSTS = ['*']
二、解析器:reqest.data取值的时候才执行
对请求的数据进行解析:是针对请求体进行解析的。表示服务器可以解析的数据格式的种类
django中的发送请求
- #如果是这样的格式发送的数据,在POST里面有值
- Content-Type: application/url-encoding.....
- request.body
- request.POST
- #如果是发送的json的格式,在POST里面是没有值的,在body里面有值,可通过decode,然后loads取值
- Content-Type: application/json.....
- request.body
- request.POST
为了这种情况下每次都要decode,loads,显得麻烦,所以才有的解析器。弥补了django的缺点
- 客户端:
- Content-Type: application/json
- '{"name":"alex","age":123}'
- 服务端接收:
- 读取客户端发送的Content-Type的值 application/json
- parser_classes = [JSONParser,FormParser] #表示服务器可以解析的数据格式的种类
- media_type_list = ['application/json','application/x-www-form-urlencoded']
- 如果客户端的Content-Type的值和 application/json 匹配:JSONParser处理数据
- 如果客户端的Content-Type的值和 application/x-www-form-urlencoded 匹配:FormParser处理数据
- 配置:
- 单视图:
- class UsersView(APIView):
- parser_classes = [JSONParser,]
- 全局配置:
- REST_FRAMEWORK = {
- 'VERSION_PARAM':'version',
- 'DEFAULT_VERSION':'v1',
- 'ALLOWED_VERSIONS':['v1','v2'],
- # 'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.HostNameVersioning"
- 'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.URLPathVersioning",
- 'DEFAULT_PARSER_CLASSES':[
- 'rest_framework.parsers.JSONParser',
- 'rest_framework.parsers.FormParser',
- ]
- }
- class UserView(APIView):
- def get(self,request,*args,**kwargs):
- return Response('ok')
- def post(self,request,*args,**kwargs):
- print(request.data) #以后取值就在这里面去取值
- return Response('...')
具体讲解
传上传文件
- from django.conf.urls import url, include
- from web.views import TestView
- urlpatterns = [
- url(r'test/(?P<filename>[^/]+)', TestView.as_view(), name='test'),
- ]
urls.py
- #!/usr/bin/env python
- # -*- coding:utf-8 -*-
- from rest_framework.views import APIView
- from rest_framework.response import Response
- from rest_framework.request import Request
- from rest_framework.parsers import FileUploadParser
- class TestView(APIView):
- parser_classes = [FileUploadParser, ]
- def post(self, request, filename, *args, **kwargs):
- print(filename)
- print(request.content_type)
- # 获取请求的值,并使用对应的JSONParser进行处理
- print(request.data)
- # application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值
- print(request.POST)
- print(request.FILES)
- return Response('POST请求,响应内容')
- def put(self, request, *args, **kwargs):
- return Response('PUT请求,响应内容')
views.py
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Title</title>
- </head>
- <body>
- <form action="http://127.0.0.1:8000/test/f1.numbers" method="post" enctype="multipart/form-data">
- <input type="text" name="user" />
- <input type="file" name="img">
- <input type="submit" value="提交">
- </form>
- </body>
- </html>
upload.html
全局使用
- REST_FRAMEWORK = {
- 'DEFAULT_PARSER_CLASSES':[
- 'rest_framework.parsers.JSONParser'
- 'rest_framework.parsers.FormParser'
- 'rest_framework.parsers.MultiPartParser'
- ]
- }
settings.py
三、序列化
序列化用于对用户请求数据进行验证和数据进行序列化(为了解决queryset序列化问题)。
那什么是序列化呢?序列化就是把对象转换成字符串,反序列化就是把字符串转换成对象
models.py
- from django.db import models
- # Create your models here.
- class Group(models.Model):
- title = models.CharField(max_length=32)
- mu = models.ForeignKey(to='Menu',default=1)
- class UserInfo(models.Model):
- name = models.CharField(max_length=32)
- pwd = models.CharField(max_length=32)
- group = models.ForeignKey(to="Group")
- roles = models.ManyToManyField(to="Role")
- class Menu(models.Model):
- name = models.CharField(max_length=21)
- class Role(models.Model):
- name = models.CharField(max_length=32)
1、基本操作
- from django.shortcuts import render,HttpResponse
- from rest_framework.views import APIView
- from rest_framework.response import Response
- from rest_framework.versioning import BaseVersioning
- from rest_framework.versioning import QueryParameterVersioning #获取version的值
- from rest_framework.versioning import URLPathVersioning #支持版本
- from rest_framework.versioning import HostNameVersioning
- from rest_framework.parsers import JSONParser #解析器
- from rest_framework import serializers
- from app03 import models
- class UsersSerializer(serializers.Serializer):
- name = serializers.CharField() #字段名字
- pwd = serializers.CharField()
- class UserView(APIView):
- def get(self,request,*args,**kwargs):
- # 方式一实现
- # user_list = models.UserInfo.objects.values('name','pwd','group__mu','group__title')
- # print(type(user_list))
- # return Response(user_list)
- # 方式二之多对象
- # user_list = models.UserInfo.objects.all() #直接这样查会报错,借助他提供的系列化
- # ser = UsersSerializer(instance=user_list,many=True) #可允许多个
- # # print(type(ser)) #<class 'rest_framework.serializers.ListSerializer'>
- # print(ser.data) #返回的是一个有序字典
- #方式三之单对象
- user = models.UserInfo.objects.all().first()
- ser = UsersSerializer(instance=user,many=False)
- return Response(ser.data)
views.py
2、跨表
- x1 = serializers.CharField(source='group.mu.name')
如果你想跨表拿你任何需要的数据,都可以用上面的这种操作,内部做判断,如果可用内部就加括号调用了
- from rest_framework.views import APIView
- from rest_framework.response import Response
- from rest_framework import serializers
- from app03 import models
- class UsersSerializer(serializers.Serializer):
- name = serializers.CharField() #字段名字
- pwd = serializers.CharField()
- # group = serializers.CharField() #会显示对象
- # group_id = serializers.CharField() #会显示id
- x1 = serializers.CharField(source='group.mu.name')
- roles = serializers.CharField(source='roles.all') #多对多关系的这样查出的是queryset对象
- class UserView2(APIView):
- '''跨表操作'''
- def get(self,request,*args,**kwargs):
- user = models.UserInfo.objects.all()
- ser = UsersSerializer(instance=user,many=True)
- return Response(ser.data)
Views.py
3、复杂序列化
解决方案一:
- class MyCharField(serializers.CharField):
- def to_representation(self, value): ##打印的是所有的数据
- data_list = []
- for row in value:
- data_list.append(row.name)
- return data_list
- class UsersSerializer(serializers.Serializer):
- name = serializers.CharField() # obj.name
- pwd = serializers.CharField() # obj.pwd
- group_id = serializers.CharField() # obj.group_id
- xxxx = serializers.CharField(source="group.title") # obj.group.title
- x1 = serializers.CharField(source="group.mu.name") # obj.mu.name
- # x2 = serializers.CharField(source="roles.all") # 多对多关系的这样查出的是queryset对象
- x2 = MyCharField(source="roles.all") # obj.mu.name
Views.py
解决方案二:
- class MyCharField(serializers.CharField):
- def to_representation(self, value):
- return {'id':value.pk, 'name':value.name}
- class UsersSerializer(serializers.Serializer):
- name = serializers.CharField() # obj.name
- pwd = serializers.CharField() # obj.pwd
- group_id = serializers.CharField() # obj.group_id
- xxxx = serializers.CharField(source="group.title") # obj.group.title
- x1 = serializers.CharField(source="group.mu.name") # obj.mu.name
- # x2 = serializers.CharField(source="roles.all") # obj.mu.name
- x2 = serializers.ListField(child=MyCharField(),source="roles.all") # obj.mu.name
Views.py
解决方案三(推荐使用)
- class UsersSerializer(serializers.Serializer):
- name = serializers.CharField() # obj.name
- pwd = serializers.CharField() # obj.pwd
- group_id = serializers.CharField() # obj.group_id
- xxxx = serializers.CharField(source="group.title") # obj.group.title
- x1 = serializers.CharField(source="group.mu.name") # obj.mu.name
- # x2 = serializers.CharField(source="roles.all") # obj.mu.name
- # x2 = serializers.ListField(child=MyCharField(),source="roles.all") # obj.mu.name
- x2 = serializers.SerializerMethodField()
- def get_x2(self,obj): #get_字段名
- print(obj) ##UserInfo object
- obj.roles.all()
- role_list = obj.roles.filter(id__gt=1)
- data_list = []
- for row in role_list:
- data_list.append({'pk':row.pk,'name':row.name})
- return data_list
Views.py
4、基于Model
- class UsersSerializer(serializers.ModelSerializer):
- x1 = serializers.CharField(source='name')
- group = serializers.HyperlinkedIdentityField(view_name='detail')
- class Meta:
- model = models.UserInfo
- # fields = "__all__"
- fields = ['name','pwd','group','x1'] #自定义字段的时候注意要指定source,scource里面的数据必须是数据库有的数据
- depth = 1 #表示深度
- class UsersView(APIView):
- def get(self,request,*args,**kwargs):
- self.dispatch
- # 方式一:
- # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title")
- # return Response(user_list)
- # 方式二之多对象
- user_list = models.UserInfo.objects.all()
- # [obj1,obj2,obj3]
- ser = UsersSerializer(instance=user_list,many=True)
- return Response(ser.data)
Views.py
5、生成URL
- class UsersSerializer(serializers.ModelSerializer): #
- group = serializers.HyperlinkedIdentityField(view_name='detail')
- class Meta:
- model = models.UserInfo
- fields = "__all__"
- fields = ['name', 'pwd','group']
- depth = 1
- class UsersView(APIView):
- def get(self,request,*args,**kwargs):
- self.dispatch
- # 方式一:
- # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title")
- # return Response(user_list)
- # 方式二之多对象
- user_list = models.UserInfo.objects.all()
- # [obj1,obj2,obj3]
- ser = UsersSerializer(instance=user_list,many=True,context={'request':request})
- return Response(ser.data)
views.py
- from django.conf.urls import url,include
- from django.contrib import admin
- from app03 import views
- urlpatterns = [
- url(r'^users4/', views.UserView4.as_view(), name='xxx'), #吧users4的group的值反向生成users5的url
- url(r'^users5/(?P<pk>.*)', views.UserView5.as_view(), name='detail'), #必须叫pk
- # url(r'^users4/(?P<pk>.*)', views.UserView4.as_view(), name='detail'),
- ]
6、全局生成URL
- class UsersSerializer(serializers.HyperlinkedModelSerializer): #继承他自动生成
- class Meta:
- model = models.UserInfo
- fields = "__all__"
- # fields = ['id','name','pwd']
- class UsersView(APIView):
- def get(self,request,*args,**kwargs):
- self.dispatch
- # 方式一:
- # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title")
- # return Response(user_list)
- # 方式二之多对象
- user_list = models.UserInfo.objects.all()
- # [obj1,obj2,obj3]
- ser = UsersSerializer(instance=user_list,many=True,context={'request':request})
- return Response(ser.data)
views.py
四、请求数据验证:
a、自己手写
- class PasswordValidator(object):
- def __init__(self, base):
- self.base = base
- def __call__(self, value):
- if value != self.base:
- message = '用户输入的值必须是 %s.' % self.base
- raise serializers.ValidationError(message)
- def set_context(self, serializer_field):
- """
- This hook is called by the serializer instance,
- prior to the validation call being made.
- """
- # 执行验证之前调用,serializer_fields是当前字段对象
- pass
- class UsersSerializer(serializers.Serializer):
- name = serializers.CharField(min_length=6)
- pwd = serializers.CharField(error_messages={'required': '密码不能为空'}, validators=[PasswordValidator('')])
views.py
b、基于model
- class PasswordValidator(object):
- def __init__(self, base):
- self.base = base
- def __call__(self, value):
- if value != self.base:
- message = '用户输入的值必须是 %s.' % self.base
- raise serializers.ValidationError(message)
- def set_context(self, serializer_field):
- """
- This hook is called by the serializer instance,
- prior to the validation call being made.
- """
- # 执行验证之前调用,serializer_fields是当前字段对象
- pass
- class UsersSerializer(serializers.ModelSerializer):
- class Meta:
- model = models.UserInfo
- fields = "__all__"
- #自定义验证规则
- extra_kwargs = {
- 'name': {'min_length': 6},
- 'pwd': {'validators': [PasswordValidator(666), ]}
- }
views.py
使用
- class UsersView(APIView):
- def get(self,request,*args,**kwargs):
- self.dispatch
- # 方式一:
- # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title")
- # return Response(user_list)
- # 方式二之多对象
- user_list = models.UserInfo.objects.all()
- # [obj1,obj2,obj3]
- ser = UsersSerializer(instance=user_list,many=True,context={'request':request})
- return Response(ser.data)
- def post(self,request,*args,**kwargs):
- ser = UsersSerializer(data=request.data)
- if ser.is_valid():
- print(ser.validated_data)
- else:
- print(ser.errors)
- return Response('...')
viewS.py
钩子函数
- def validate_字段(self,validated_value):
- raise ValidationError(detail='xxxxxx')
- return validated_value
Django后端项目---- rest framework(3)的更多相关文章
- Django后端项目---- Rest Framework(2)
一.认证(补充的一个点) 认证请求头 #!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import API ...
- Django后端项目---- rest framework(4)
一.分页 试问如果当数据量特别大的时候,你是怎么解决分页的? 方式a.记录当前访问页数的数据id 方式b.最多显示120页等 方式c.只显示上一页,下一页,不让选择页码,对页码进行加密 1.基于lim ...
- Django后端项目----restful framework 认证源码流程
一.请求到来之后,都要先执行dispatch方法,dispatch方法方法根据请求方式的不同触发get/post/put/delete等方法 注意,APIView中的dispatch方法有很多的功能 ...
- Django后端项目----RESTful API
一. 什么是RESTful REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移” REST从资源的角 ...
- Django商城项目笔记No.1项目准备工作
Django商城项目笔记No.1项目准备工作 一.本项目商城属于B2C商业模式 二.项目采用前后端分离的应用模式 前端使用Vue.js 后端使用Django REST framework 1.创建gi ...
- nginx + uwsgi 部署 Django+Vue项目
nginx + uwsgi 部署 Django+Vue项目 windows 本地 DNS 解析 文件路径 C:\Windows\System32\drivers\etc 单机本地测试运行方式,调用dj ...
- Django后端彻底解决跨域问题
最近在接一个前后端分离的项目,后端使用的django-restframework,前端使用的Vue.后端跑起来后,发现前端在访问后端API时出了了跨域的问题. 类似如下报错: 关于跨域问题,之前这篇文 ...
- Django商城项目笔记No.12用户部分-QQ登录2获取QQ用户openid
Django商城项目笔记No.12用户部分-QQ登录2获取QQ用户openid 上一步获取QQ登录网址之后,测试登录之后本该跳转到这个界面 但是报错了: 新建oauth_callback.html & ...
- Django商城项目笔记No.10用户部分-登录接口
Django商城项目笔记No.10用户部分-登录接口 添加url路由 接下来第二步,增加返回内容: 增加结果如下: 配置:上边的方法定义了返回的内容都有哪些,那这个方法jwt还不知道,需要配置: 修改 ...
随机推荐
- MSSQL查询收缩和备份进度
--查询当前数据库备份进度 SELECT DB_NAME(er.[database_id]) [DatabaseName],er.[command] AS [CommandType],er.[pe ...
- 如何卸载VMware虚拟机?
如何卸载VMware虚拟机? 1.windows + R 打开>运行-->regedit(打开编辑注册表)-->找到HKEY_LOCAL_MACHINE-->Software ...
- NancyFx-打造小型 WebAPI 與 Microservice 的輕巧利器
https://github.com/NancyFx/Nancy 在做非網站系統整合時,我很愛用一招:寫個 Process 提供 WebAPI 介面給其他系統呼叫,不管你用什麼烏語言鬼平台,怎麼可能找 ...
- Scala集合(二)
将函数映射到集合 map方法 val names = List("Peter" , "Paul", "Mary") names.map(_. ...
- (转)EOSIO开发(一)使用Docker构建本地环境
前言 一直想学习EOS开发,但是不知道怎么入门.最近从GitHub上下载了源码,发现官方已经提供了完整的EOSIO开发入门教程,既然如此赶紧开始行动.今天是系列文章的第一篇,介绍如何使用Docker搭 ...
- [LeetCode] 系统刷题1_代码风格及边界
代码风格 说自己不清楚的算法,比如KMP,如果解释不清楚或者写不出来的算法建议不提 注意代码的缩进以及空格的合理运用,使得代码看起来比较整洁有条理 注意边界的条件以及越界 误区: 算法想出来还仅仅不够 ...
- 用websploit获取管理员后台地址
1, use web/dir_scanner 2, set TARGET http://www.****.com 3, run SOURCE: https://sourceforge.net/proj ...
- 正则表达式匹配域名、网址、url
DNS规定,域名中的标号都由英文字母和数字组成,每一个标号不超过63个字符,也不区分大小写字母.标号中除连字符(-)外不能使用其他的标点符号.级别最低的域名写在最左边,而级别最高的域名写在最右边.由多 ...
- React对比Vue(05 生命周期的对比)
先来vue的吧,先上图,生命周期就好比一个人重出生到青少年再到青年再到中年在到老年到死亡的一个过程,不同的过程做不同的事情. 好了,上代码 beforeCreate :数据还没有挂载呢,只是一个空壳 ...
- vue中使用echarts来绘制世界地图和中国地图
第一步,下载echarts cnpm install echarts --save-dev 第二步,在main.js中全局引入 //引入echarts import echarts from 'ech ...