本章内容;css
1. FBV与CBVhtml
FBV: Function Base View前端
CBV:Class Base Viewpython
示例:git
from django.shortcuts import render, HttpResponse from django.http import JsonResponse # Create your views here. def index(request): if request.method == "POST": print(request.POST) # 修改数据库 return HttpResponse("OK") return render(request, "index.html") # CBV from django import views class Index(views.View): def get(self, request): return render(request, 'index.html') def post(self, request): print(request.POST) return HttpResponse("OK") # def index2(request): # if request.method == "GET": # return render(request, "index.html") # print(request.POST) # # 修改数据库 # return JsonResponse("OK") def ajax(request): return JsonResponse({"code": 0})
注意事项:github
1.CBV定义必定要继承django.views.viewajax
2. 注册路由的时候要写 类名.as_view()数据库
3.具体原理是:dispatch()方法 中利用反射 找到每一个请求执行django
1 from django import views 2 3 4 class Index(views.View): 5 def get(self, request): 6 return render(request, 'index.html') 7 8 def post(self, request): 9 print(request.POST) 10 return HttpResponse("OK")
状态码json
200 OK - [GET]:服务器成功返回用户请求的数据,该操做是幂等的(Idempotent)。 201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。 202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务) 204 NO CONTENT - [DELETE]:用户删除数据成功。 400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操做,该操做是幂等的。 401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。 403 Forbidden - [*] 表示用户获得受权(与401错误相对),可是访问是被禁止的。 404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操做,该操做是幂等的。 406 Not Acceptable - [GET]:用户请求的格式不可得(好比用户请求JSON格式,可是只有XML格式)。 410 Gone -[GET]:用户请求的资源被永久删除,且不会再获得的。 422 Unprocesable entity - [POST/PUT/PATCH] 当建立一个对象时,发生一个验证错误。 500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将没法判断发出的请求是否成功。 更多看这里:http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
错误处理,状态码是4xx时,应返回错误信息,error当作key。
{ error: "Invalid API key" }
返回结果,针对不一样操做,服务器向用户返回的结果应该符合如下规范。
GET /collection:返回资源对象的列表(数组) GET /collection/resource:返回单个资源对象 POST /collection:返回新生成的资源对象 PUT /collection/resource:返回完整的资源对象 PATCH /collection/resource:返回完整的资源对象 DELETE /collection/resource:返回一个空文档
Hypermedia API,RESTful API最好作到Hypermedia,即返回结果中提供连接,连向其余API方法,使得用户不查文档,也知道下一步应该作什么。
1
2
3
4
5
6
|
{
"link"
: {
"rel"
:
"collection https://www.example.com/zoos"
,
"href"
:
"https://api.example.com/zoos"
,
"title"
:
"List of zoos"
,
"type"
:
"application/vnd.yourformat+json"
}}
|
路由系统:
1
2
3
|
urlpatterns
=
[
url(r
'^users'
, Users.as_view()),
]
|
CBV视图:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
from
django.views
import
View
from
django.http
import
JsonResponse
class
Users(View):
def
get(
self
, request,
*
args,
*
*
kwargs):
result
=
{
'status'
:
True
,
'data'
:
'response data'
}
return
JsonResponse(result, status
=
200
)
def
post(
self
, request,
*
args,
*
*
kwargs):
result
=
{
'status'
:
True
,
'data'
:
'response data'
}
return
JsonResponse(result, status
=
200
)
|
实验案例:新闻系统
实现方式一:
1 from django.db import models 2 3 # Create your models here. 4 5 6 # 文章表 7 class Article(models.Model): 8 title = models.CharField(max_length=32) 9 # 文章发布时间 10 # auto_now每次更新的时候会把当前时间保存 11 create_time = models.DateField(auto_now_add=True) 12 # auto_now_add 第一次建立的时候把当前时间保存 13 update_time = models.DateField(auto_now=True) 14 # 文章的类型 15 type = models.SmallIntegerField( 16 choices=((1, "原创"), (2, "转载")), 17 default=1 18 ) 19 # 来源 20 school = models.ForeignKey(to='School', on_delete=models.CASCADE) 21 # 标签 22 tag = models.ManyToManyField(to='Tag') 23 24 25 # 文章来源表 26 class School(models.Model): 27 name = models.CharField(max_length=16) 28 29 30 # 文章标签表 31 class Tag(models.Model): 32 name = models.CharField(max_length=16)
执行命令:
migrate makemigrations
插入数据库数据
以上有了数据信息,而后进行json API接口的方式展现
1 from django.contrib import admin 2 from django.urls import path 3 from app01 import views 4 5 urlpatterns = [ 6 path('admin/', admin.site.urls), 7 path('article_list/',views.article_list), 8 ]
from django.shortcuts import render,HttpResponse from app01 import models import json # Create your views here. def article_list(request): #去数据库查询全部的文章数据 quest_set = models.Article.objects.all().values("id","title") #values是字典,values_list是列表 #序列化成json格式 data = json.dumps(list(quest_set),ensure_ascii=False) #返回 return HttpResponse(data)
注意:json只支持7种数据类型,ORM查询出来的结果为QuerySet类型,它是不支持的。
日期对象也是不支持的,须要转换为字符串。
启动django项目,访问URL: http://127.0.0.1/article_list/,所以每个时间,都要转换为字符串,太麻烦了。
转换方式:
1 from django.shortcuts import render,HttpResponse 2 from app01 import models 3 import json 4 5 # Create your views here. 6 def article_list(request): 7 #去数据库查询全部的文章数据 8 quest_set = models.Article.objects.all().values("id","title","create_time") #values是字典,values_list是列表 9 #序列化成json格式 10 11 #1.先把时间对象转换成字符串格式 12 for i in quest_set: 13 i["create_time"] = i["create_time"].strftime('%Y-%m-%d') 14 15 data = json.dumps(list(quest_set), ensure_ascii=False) 16 #返回 17 return HttpResponse(data)
JsonResponse 对象:
class JsonResponse
(data, encoder=DjangoJSONEncoder, safe=True, json_dumps_params=None,**kwargs)
这个类是HttpRespon的子类,它主要和父类的区别在于:
1 from django.shortcuts import render,HttpResponse 2 from django.http import JsonResponse 3 from app01 import models 4 import json 5 6 # Create your views here. 7 #第二种方式 8 def article_list(request): 9 #去数据库查询全部的文章数据,返回queryset,每个元素都是字典 10 query_set = models.Article.objects.all().values("id","title","create_time","type","school") 11 print(query_set) 12 for i in query_set: 13 print(i) 14 15 #学校对象 16 school_obj = models.School.objects.filter(id=i['school']).first() 17 #学校id 18 id = school_obj.id 19 #学校的名字 20 name = school_obj.name 21 #修改字典,key为school的值 22 i['school'] = {"id":id,"name":name} 23 24 #返回json对象,safe=False表示任何能转换为json格式的对象 25 return JsonResponse(list(query_set),safe=False)
查看JsonResponse源代码
def __init__(self, data, encoder=DjangoJSONEncoder, safe=True, json_dumps_params=None, **kwargs): if safe and not isinstance(data, dict): raise TypeError( 'In order to allow non-dict objects to be serialized set the ' 'safe parameter to False.' ) if json_dumps_params is None: json_dumps_params = {} kwargs.setdefault('content_type', 'application/json') data = json.dumps(data, cls=encoder, **json_dumps_params) super(JsonResponse, self).__init__(content=data, **kwargs)
注意:从上面的代码中,能够看出。针对查询对应的学校信息,使用了for循环。它是一个外键字段,
那若是再查询一个外键字段呢?再来一个for循环?代码太冗长了!
serializer 容许复杂数据(好比 querysets 和 model 实例)转换成python数据类型,而后能够更容易的转换成 json 或 xml 等。同时,serializer也提供了反序列化功能,容许解析数据转换成复杂数据类型。
中文文档连接:
https://q1mi.github.io/Django-REST-framework-documentation/api-guide/serializers_zh/
class DBG(serializers.Serializer): # 声明序列化器 id = serializers.IntegerField() title = serializers.CharField() create_time = serializers.DateField() type = serializers.IntegerField() school = serializers.CharField(source="school.name")
注意:source = "school.name" 表示school表中的name字段
可使用它来序列化和反序化与DBG对象相应的数据。
申明一个序列化看起来很是像申明一个form。咱们以前学习form组件时,将须要的字段类型都指定好了!
一般你会想要与Django模型相对应的序列化类。
ModelSerializer
类可以让你自动建立一个具备模型中相应字段的Serializer
类。
这个ModelSerializer
类和常规的Serializer
类同样,不一样的是:
.create()
方法和.update()
方法。
声明一个ModelSerializer
以下:
class CYM(serializers.ModelSerializer): type = serializers.CharField(source='get_type_display') class Meta: model = models.Article fields = "__all__" # ("id", "title", "type") depth = 1 # 官方推荐不超过10层
默认状况下,全部的模型的字段都将映射到序列化器上相应的字段。
模型中任何关联字段好比外键都将映射到PrimaryKeyRelatedField
字段。默认状况下不包括反向关联,除非像serializer relations文档中规定的那样显示包含。
查看官方文档
https://docs.djangoproject.com/en/dev/ref/models/instances/#django.db.models.Model.get_FOO_display
对于具备选择集的每一个字段,该对象将具备一个get_FOO_display()方法,其中FOO是该字段的名称。 此方法返回字段的“可读”值。
source='get_type_display' 表获取type字段中选择集的值。
不懂?看一下models.py中的Article表,看这一段
# 文章的类型 type = models.SmallIntegerField( choices=((1, "原创"), (2, "转载")), default=1 )
ORM是查询表的数据,那么这个type在真正存储时,是1或2。
可是我想要获得"原创"和"转载",怎么办?那就须要我上面提到的get_type_display。
注意:type的变量名和字段名必须保持一致,那么使用serializers后,结果集中type的值为"原创"和"转载",而不是1和2
model = models.Article 表示Article表
fields = "__all__" 表示全部字段,若是须要指定字段。能够写成这样fields = ("id", "title", "type")
depth = 1 表示深度为1层。有外键关联时,才须要设置depth参数!
由于Article表和School表,是一对多的关系,它们之间的关系只有一层。假设说:School表和另一个表(简称B表)有关系。Article表经过School表,要去查询B表的数据,那么层数就是2,以此类推!
def article_list(request): # 查询全部 # 去数据库查询全部的文章数据 query_set = models.Article.objects.all() xbg = CYM(query_set, many=True) print(xbg.data) # 返回 return JsonResponse(xbg.data, safe=False)
def article_list(request): # 查询全部 # 去数据库查询全部的文章数据 query_set = models.Article.objects.all() xbg = CYM(query_set, many=True) print(xbg.data) # 返回 return JsonResponse(xbg.data, safe=False)
参数解释:
many=True 表示能序列化多个对象。
什么意思?article表有多条数据,每一条数据,就是一个对象。咱们须要查询表的全部记录,因此必须指定many=True。返回一条数据时,不须要指定many=True
views.py完整代码以下:
from django.shortcuts import render,HttpResponse from django.http import JsonResponse from app01 import models import json from rest_framework import serializers # Create your views here. class DBG(serializers.Serializer): # 声明序列化器 id = serializers.IntegerField() title = serializers.CharField() create_time = serializers.DateField() type = serializers.IntegerField() school = serializers.CharField(source="school.name") class CYM(serializers.ModelSerializer): # 声明ModelSerializer # type = serializers.CharField(source='get_type_display') class Meta: model = models.Article fields = "__all__" # ("id", "title", "type") depth = 1 # 官方推荐不超过10层 def article_list(request): # 查询全部 # 去数据库查询全部的文章数据 query_set = models.Article.objects.all() xbg = CYM(query_set, many=True) print(xbg.data) # 返回 return JsonResponse(xbg.data, safe=False)
能够看到type的值不是数字,而是选择集中的值,它作了替换。是下面这一行,作了替换
type = serializers.CharField(source='get_type_display')
school的值,也能显示相关联的数据。
CYM是通用的,能够多条,也能够一条。
注意:多条的时候,须要加参数many=True。而一条,则不用!
修改urls.py,增长一个路径
urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^article_list/', views.article_list), url(r'article_detail/(\d+)', views.article_detail), ]
urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^article_list/', views.article_list), url(r'article_detail/(\d+)', views.article_detail), ]
修改views.py,增长视图函数
from django.shortcuts import render,HttpResponse from django.http import JsonResponse from app01 import models import json from rest_framework import serializers # Create your views here. class DBG(serializers.Serializer): # 声明序列化器 id = serializers.IntegerField() title = serializers.CharField() create_time = serializers.DateField() type = serializers.IntegerField() school = serializers.CharField(source="school.name") class CYM(serializers.ModelSerializer): # 声明ModelSerializer # type = serializers.CharField(source='get_type_display') class Meta: model = models.Article fields = "__all__" # ("id", "title", "type") depth = 1 # 官方推荐不超过10层 def article_list(request): # 查询全部 # 去数据库查询全部的文章数据 query_set = models.Article.objects.all() xbg = CYM(query_set, many=True) print(xbg.data) # 返回 return JsonResponse(xbg.data, safe=False) def article_detail(request, id): # 查询单条数据 article_obj = models.Article.objects.filter(id=id).first() xcym = CYM(article_obj) return JsonResponse(xcym.data)
刷新页面,访问url: http://127.0.0.1:8000/article_detail/1
使用格式化工具,效果以下:
总结:
使用ORM对象转换为json对象时,推荐使用serializers
Postman一款很是流行的API调试工具。不只能够调试简单的css、html、脚本等简单的网页基本信息,它还可以发送任何类型的HTTP 请求 (GET, HEAD, POST, PUT..),附带任何数量的参数+ headers。对于开发过程当中去调试接口,Postman确实足够的简单方便,并且功能强大。
官网地址:
使用windows安装以后,打开主程序,跳过登陆
访问文章列表 http://127.0.0.1:8000/article_list/
访问文章详情 http://127.0.0.1:8000/article_detail/1
总结:
1. 使用Django 的视图 本身序列化 1. HttpResponse 2. JsonResponse 3. serializers 2. 使用Django REST Framework 框架的序列化工具类 1. 安装 pip install djangorestframework 2. 导入 from rest_framework import serializers 3. 使用 class ArticleSerializer(serializers.Serializer): ...
有些状况下,咱们须要使用python脚原本调用django,从而方便使用django提供的一些指令!
在django项目根目录下建立文件test_orm.py,它和manage.py是同级的
import os if __name__ == "__main__": # 设置django环境 os.environ.setdefault("DJANGO_SETTINGS_MODULE", "about_drf.settings") import django django.setup() from app01 import models obj = models.Article.objects.filter(id=1).values() print(obj)
执行脚本,输出以下:
<QuerySet [{'title': 'Python三年用不上', 'id': 1, 'school_id': 1, 'type': 1, 'update_time': datetime.date(2018, 7, 31), 'create_time': datetime.date(2018, 7, 31)}]>
若是用户主动退出,session会自动清除,若是没有退出就一直保留,记录数愈来愈大,要定时清理没用的session。
django中已经提供了这个方法,推荐把它加入到crontab中自动清理过时的session,防止session表记录过大,影响访问速度。
python E:\python_script\django框架\day15\about_drf\manage.py clearsessions