python 全栈开发,Day96(Django REST framework 视图,django logging配置,django-debug-toolbar使用指南)
昨日内容回顾
1. Serializer(序列化)
1. ORM对应的query_set和ORM对象转换成JSON格式的数据
1. 在序列化类中定义自定义的字段:SerializerMethodField
在类中定义 get_自定义字段名(self, obj)方法
2. read_only 只在显示(查询)时才会有效。 2. 对前端POST过来的数据做有效性的校验
1. 一定要将数据以data=的形式传递到序列化类中!!!
ser_obj = CommentSerializer(data=comment_data)
2. 判断数据是否有效
ser_obj.is_valid(): 欠一个源码
ser_obj.validated_data 中保存经过校验的有效数据 3. 局部钩子
定义一个validate_字段名(self, value)
4. 全局钩子
定义一个validate方法 3. .save()方法将符合要求的数据存入数据库
1. 本质上还是调用ORM的create()方法
类名.objects.create(**ser_obj.validated_data) 2. 超链接的序列化
1. 超连接字段的三个参数
# 文章超链接序列化
class ArticleHyperLinkedSerializer(serializers.HyperlinkedModelSerializer):
# view_name参数 默认使用 表名-detail
# lookup_url_kwarg参数 默认使用pk,指的是反向生成URL的时候 路由中的分组命名匹配的key
# lookup_field参数 默认使用的pk, 指的是反向生成URL的时候, 路由中分组命名匹配的value
school = serializers.HyperlinkedIdentityField(
view_name='school-detail111',
lookup_url_kwarg='name',
lookup_field='school_name'
)
2. 想要生成完整的超链接API,在序列化的时候还要传入 context={'request': request}
ser_obj = app01_serializers.ArticleHyperLinkedSerializer(all_article, many=True, context={'request': request})
1. 想要生成相对路径
context={'request': None}
一、Django REST framework 视图
DRF中的Request
在Django REST Framework中内置的Request类扩展了Django中的Request类,实现了很多方便的功能--如请求数据解析和认证等。
比如,区别于Django中的request从request.GET中获取URL参数,从request.POST中取某些情况下的POST数据。
在APIView中封装的request,就实现了请求数据的解析:
一般来说,GET请求的参数,通过request.query_params来获取。POST、PUT通过request.data来获取
但这也不是绝对的,提交类型不同,获取参数的方式也是不一样的。详情请参考:
https://www.cnblogs.com/xiao987334176/p/9401486.html#autoid-3-3-3
面向对象三大特性
封装
1. 把共有的数据当成一类物体的属性
2. 把共有的功能当成一类物体的方法
继承
1. 把共有的属性或方法抽离出来放到一个基类(父类)中
多态
1. 不同的物体调用同一个方法有不同的效果
比如:Python中数字的+和字符串的+,结果是不一样的。前者是计算,后者是拼接!
葫芦娃的故事
先来列举前5个娃,为啥是5个呢?到最后,你就知道了!
class Wa1(object):
name = "红娃" def f1(self):
print("力大无穷!") class Wa2(object):
name = '橙娃' def f2(self):
print('千里眼顺风耳!') class Wa3(object):
name = '黄娃' def f3(self):
print('钢筋铁骨!') class Wa4(object):
name = '绿娃' def f4(self):
print("会喷火!") class Wa5(object):
name = '青蛙' def f5(self):
print("会喷水!")
奇数娃,它继承了一娃,三娃,五娃的技能
偶数娃,它继承了二娃,四娃的技能
套娃,它继承了奇数娃,偶数娃的技能。也就是说,它拥有5个娃的技能
实例化3个角色,分别调用奇数娃,偶数娃,套娃的info方法
完整代码如下:
class Wa1(object):
name = "红娃" def f1(self):
print("力大无穷!") class Wa2(object):
name = '橙娃' def f2(self):
print('千里眼顺风耳!') class Wa3(object):
name = '黄娃' def f3(self):
print('钢筋铁骨!') class Wa4(object):
name = '绿娃' def f4(self):
print("会喷火!") class Wa5(object):
name = '青蛙' def f5(self):
print("会喷水!") class Jishuwa(Wa1, Wa3, Wa5):
name = '奇数娃' def info(self):
print("我是%s,我会:" %self.name)
self.skill() def skill(self): # 技能
self.f1()
self.f3()
self.f5() class Oushuwa(Wa2, Wa4):
name = '偶数娃' def info(self):
print("我是%s,我会:" % self.name)
self.skill() def skill(self): # 技能
self.f2()
self.f4() class Taowa(Jishuwa, Oushuwa):
name = '套娃' def info(self):
print("我是{}, 我会:".format(self.name))
self.skill() def skill(self): # 技能
Jishuwa.skill(self)
Oushuwa.skill(self) print('奇数娃'.center(20, '❆'))
role1 = Jishuwa()
role1.info() print('偶数娃'.center(20, '❆'))
role2 = Oushuwa()
role2.info() print('套娃'.center(20, '❆'))
role3 = Taowa()
role3.info()
执行输出:
❆❆❆❆❆❆❆❆奇数娃❆❆❆❆❆❆❆❆❆
我是奇数娃,我会:
力大无穷!
钢筋铁骨!
会喷水!
❆❆❆❆❆❆❆❆偶数娃❆❆❆❆❆❆❆❆❆
我是偶数娃,我会:
千里眼顺风耳!
会喷火!
❆❆❆❆❆❆❆❆❆套娃❆❆❆❆❆❆❆❆❆
我是套娃, 我会:
力大无穷!
钢筋铁骨!
会喷水!
千里眼顺风耳!
会喷火!
从结果上来看,可套娃是最牛B的!
通过这个例子,慢慢来引申下面的内容。
前提
序列化
修改app01(应用名)目录下的app01_serializers.py,完整代码如下:
from app01 import models
from rest_framework import serializers # 序列化评论的类
class CommentSerializer(serializers.ModelSerializer):
class Meta:
model = models.Comment # Comment表
fields = "__all__" # 序列化所有字段
# 定义额外的参数
extra_kwargs = {
"content": {
"error_messages": {
"required": '内容不能为空',
}
},
"article": {
"error_messages": {
"required": '文章不能为空'
}
}
} # 学校的序列化
class SchoolSerializer(serializers.ModelSerializer):
class Meta:
model = models.School # School表
fields = "__all__"
路由
urls.py代码如下:
from django.conf.urls import url,include
from django.contrib import admin
from app01 import app01_urls urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'api/', include(app01_urls)),
]
app01_urls.py代码如下:
from django.conf.urls import url
from app01 import views urlpatterns = [
# 学校
url(r'school/$', views.SchoolView.as_view()),
url(r'school/(?P<pk>\d+)/$', views.SchoolDetail.as_view()),
]
初生牛犊之徒手垒代码阶段
视图
修改views.py,完整代码如下:
from django.shortcuts import render, HttpResponse
from app01 import models
from rest_framework.views import APIView
from app01 import app01_serializers # 导入自定义的序列化
from rest_framework.response import Response # Create your views here. class SchoolView(APIView): # 所有记录
def get(self, request, *args, **kwargs): # GET请求
queryset = models.School.objects.all()
# 使用自定义序列化类。当返回结果不止一条时,要指定many=True参数
serializers_class = app01_serializers.SchoolSerializer(queryset, many=True)
return Response(serializers_class.data) class SchoolDetail(APIView): # 单条记录
def get(self, request, pk, *args, **kwargs):
queryset = models.School.objects.filter(pk=pk).first()
serializers_class = app01_serializers.SchoolSerializer(queryset)
return Response(serializers_class.data)
浏览器访问url: http://127.0.0.1:8000/api/school/
效果如下:
访问详情:http://127.0.0.1:8000/api/school/1/
这个时候,需要增加评论表,它也需要上面2个功能:展示所有记录和单条记录
将2个视图函数的代码复制一遍,修改表名和序列化类名
from django.shortcuts import render, HttpResponse
from app01 import models
from rest_framework.views import APIView
from app01 import app01_serializers # 导入自定义的序列化
from rest_framework.response import Response # Create your views here. class SchoolView(APIView): # 所有记录
def get(self, request, *args, **kwargs): # GET请求
queryset = models.School.objects.all()
# 使用自定义序列化类。当返回结果不止一条时,要指定many=True参数
serializers_class = app01_serializers.SchoolSerializer(queryset, many=True)
return Response(serializers_class.data) class SchoolDetail(APIView): # 单条记录
def get(self, request, pk, *args, **kwargs):
queryset = models.School.objects.filter(pk=pk).first()
serializers_class = app01_serializers.SchoolSerializer(queryset)
return Response(serializers_class.data) class CommentView(APIView): # 所有记录
def get(self, request, *args, **kwargs): # GET请求
queryset = models.Comment.objects.all()
# 使用自定义序列化类。当返回结果不止一条时,要指定many=True参数
serializers_class = app01_serializers.CommentSerializer(queryset, many=True)
return Response(serializers_class.data) class CommentDetail(APIView): # 单条记录
def get(self, request, pk, *args, **kwargs):
queryset = models.Comment.objects.filter(pk=pk).first()
serializers_class = app01_serializers.CommentSerializer(queryset)
return Response(serializers_class.data)
修改app01_urls.py,增加2个路径
from django.conf.urls import url
from app01 import views urlpatterns = [
# 学校
url(r'school/$', views.SchoolView.as_view()),
url(r'school/(?P<pk>\d+)/$', views.SchoolDetail.as_view()),
# 评论
url(r'comment/$', views.CommentView.as_view()),
url(r'comment/(?P<pk>\d+)/$', views.CommentDetail.as_view()),
]
访问所有评论url: http://127.0.0.1:8000/api/comment/
访问单条评论url: http://127.0.0.1:8000/api/comment/1/
那么问题来了,再来一个表呢?再复制2个视图函数,修改表名和序列化类名?
这不符合编程习惯,得需要将相同的代码,封装成一个类。那么其他表就可以继承了!
那么接下来的GenericAPIView就展示了它强大的功能
小试牛刀之使用混合类阶段
GenericAPIView
GenericAPIView对APIView再次封装,实现了强大功能:
- 加入queryset属性,可以直接设置这个属性,不必再将实例化的courses,再次传给seriliazer,系统会自动检测到。除此之外,可以重载get_queryset(),这样就不必设置’queryset=*’,这样就变得更加灵活,可以进行完全的自定义。
- 加入serializer_class属性与实现get_serializer_class()方法。两者的存在一个即可,通过这个,在返回时,不必去指定某个serilizer
- 设置过滤器模板:filter_backends
- 设置分页模板:pagination_class
- 加入 lookup_field=”pk”,以及实现了get_object方法: 这个用得场景不多,但十分重要。它们两者的关系同1,要么设置属性,要么重载方法。它们的功能在于获取某一个实例时,指定传进来的后缀是什么。
GenericAPIView的五个扩展类给我们提供了五个方法分别进行增删改查的不同操作,这样我们就不用写那么多函数啦!!
五个扩展类(为啥是5个?答:增删改查,查有两个)
搭配GenericAPIView使用
1.ListModelMixin: 提供list方法快速实现列表视图(多条数据)
2.CreateModelMixin: 提供create方法快速实现创建资源的视图
3.RetrieveModelMixin 提供retrieve方法,可以快速实现返回一个存在的数据对象(需要传入pk)
4.UpdateModelMixin 提供update方法,可以快速实现更新一个存在的数据对象。 提供partial_update方法,可以实现局部更新
5.DestroyModelMixin 提供destroy方法,可以快速实现删除一个存在的数据对象
注意:GenericAPIView不能单独使用,它需要和上面的5个扩展类配合使用才行
源码分析,请参考文章:
https://blog.csdn.net/u013210620/article/details/79869661
ListModelMixin
它返回数据列表,也就是多条数据
使用时,需要导入模块
from rest_framework.mixins import ListModelMixin
RetrieveModelMixin
它负责单条数据的获取、更新、删除
使用时,需要导入模块
from rest_framework.mixins import RetrieveModelMixin
举例:将上面4个视图函数改成GenericAPIView+ListModelMixin+RetrieveModelMixin
使用前,需要导入模块
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import ListModelMixin
GenericAPIView只需要配置queryset和serializer_class
修改views.py,完整代码如下:
from django.shortcuts import render, HttpResponse
from app01 import models
from rest_framework.views import APIView
from app01 import app01_serializers # 导入自定义的序列化
from rest_framework.response import Response
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import ListModelMixin, RetrieveModelMixin # Create your views here. class SchoolView(GenericAPIView, ListModelMixin):
queryset = models.School.objects.all()
serializer_class = app01_serializers.SchoolSerializer def get(self, request, *args, **kwargs): # GET请求
return self.list(request, *args, **kwargs) # RetrieveModelMixin 表示查询单条数据,需要传入pk参数
class SchoolDetail(GenericAPIView, RetrieveModelMixin):
queryset = models.School.objects.all()
serializer_class = app01_serializers.SchoolSerializer def get(self, request, pk, *args, **kwargs): # GET请求
return self.retrieve(request, pk, *args, **kwargs) class CommentView(GenericAPIView, ListModelMixin):
queryset = models.Comment.objects.all()
serializer_class = app01_serializers.CommentSerializer def get(self, request, *args, **kwargs): # GET请求
return self.list(request, *args, **kwargs) # RetrieveModelMixin 表示查询单条数据,需要传入pk参数
class CommentDetail(GenericAPIView, RetrieveModelMixin):
queryset = models.Comment.objects.all()
serializer_class = app01_serializers.CommentSerializer def get(self, request, pk, *args, **kwargs): # GET请求
return self.retrieve(request, pk, *args, **kwargs)
访问不同的url,效果和上面是一样的!
http://127.0.0.1:8000/api/comment/
http://127.0.0.1:8000/api/comment/1/
http://127.0.0.1:8000/api/school/
http://127.0.0.1:8000/api/school/1/
JsonResponse和Response的区别
JsonResponse和Response都可以返回json对象。不同之处在于:
使用Response时,如果是浏览器访问,就会返回一个页面,效果就是上面的图片。
但是使用postman工具时,返回json数据,并不会有页面。
而JsonResponse则没有这个功能,始终都是json对象
CreateModelMixin
它负责增加一条记录
使用时,需要导入模块
from rest_framework.mixins import CreateModelMixin
举例:增加一条评论
修改views.py,完整代码如下:
from django.shortcuts import render, HttpResponse
from app01 import models
from rest_framework.views import APIView
from app01 import app01_serializers # 导入自定义的序列化
from rest_framework.response import Response
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import ListModelMixin, RetrieveModelMixin,CreateModelMixin # Create your views here. class SchoolView(GenericAPIView, ListModelMixin):
queryset = models.School.objects.all()
serializer_class = app01_serializers.SchoolSerializer def get(self, request, *args, **kwargs): # GET请求
return self.list(request, *args, **kwargs) # RetrieveModelMixin 表示查询单条数据,需要传入pk参数
class SchoolDetail(GenericAPIView, RetrieveModelMixin):
queryset = models.School.objects.all()
serializer_class = app01_serializers.SchoolSerializer def get(self, request, pk, *args, **kwargs): # GET请求
return self.retrieve(request, pk, *args, **kwargs) class CommentView(GenericAPIView, ListModelMixin,CreateModelMixin):
queryset = models.Comment.objects.all()
serializer_class = app01_serializers.CommentSerializer def get(self, request, *args, **kwargs): # GET请求
return self.list(request, *args, **kwargs) def post(self, request, *args, **kwargs): # POST请求
return self.create(request, *args, **kwargs) # RetrieveModelMixin 表示查询单条数据,需要传入pk参数
class CommentDetail(GenericAPIView, RetrieveModelMixin):
queryset = models.Comment.objects.all()
serializer_class = app01_serializers.CommentSerializer def get(self, request, pk, *args, **kwargs): # GET请求
return self.retrieve(request, pk, *args, **kwargs)
json数据
{
"content": "噗嗤",
"article": 2
}
指定格式为JSON
查看返回结果,它会增加的数据
查看app01_comment表
DestroyModelMixin
删除单条数据
使用时,需要导入模块
from rest_framework.mixins import DestroyModelMixin
举例:删除一条评论,那么在删除之前,可以打印一句话
from django.shortcuts import render, HttpResponse
from app01 import models
from rest_framework.views import APIView
from app01 import app01_serializers # 导入自定义的序列化
from rest_framework.response import Response
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import ListModelMixin, RetrieveModelMixin
from rest_framework.mixins import CreateModelMixin, DestroyModelMixin # Create your views here. class SchoolView(GenericAPIView, ListModelMixin):
queryset = models.School.objects.all()
serializer_class = app01_serializers.SchoolSerializer def get(self, request, *args, **kwargs): # GET请求
return self.list(request, *args, **kwargs) # RetrieveModelMixin 表示查询单条数据,需要传入pk参数
class SchoolDetail(GenericAPIView, RetrieveModelMixin):
queryset = models.School.objects.all()
serializer_class = app01_serializers.SchoolSerializer def get(self, request, pk, *args, **kwargs): # GET请求
return self.retrieve(request, pk, *args, **kwargs) class CommentView(GenericAPIView, ListModelMixin,CreateModelMixin):
queryset = models.Comment.objects.all()
serializer_class = app01_serializers.CommentSerializer def get(self, request, *args, **kwargs): # GET请求
return self.list(request, *args, **kwargs) def post(self, request, *args, **kwargs): # POST请求
return self.create(request, *args, **kwargs) # RetrieveModelMixin 表示查询单条数据,需要传入pk参数
class CommentDetail(GenericAPIView, RetrieveModelMixin,DestroyModelMixin):
queryset = models.Comment.objects.all()
serializer_class = app01_serializers.CommentSerializer def get(self, request, pk, *args, **kwargs): # GET请求
return self.retrieve(request, pk, *args, **kwargs) def delete(self, request, pk, *args, **kwargs): # DELETE请求
return self.destroy(request, pk, *args, **kwargs) def perform_destroy(self, instance):
print("你真的真的确定要删除了吗?...")
instance.delete()
使用postman发送delete请求,注意:数字后面一定要有 / ,否则不没有效果
因为路由规则定义,必须以 / 结尾!
它的返回结果为空
查看Pycharm控制台输出:
你真的真的确定要删除了吗?...
UpdateModelMixin
更新单条数据
使用时,需要导入模块
from rest_framework.mixins import UpdateModelMixin
举例:更新一条评论
from django.shortcuts import render, HttpResponse
from app01 import models
from rest_framework.views import APIView
from app01 import app01_serializers # 导入自定义的序列化
from rest_framework.response import Response
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import ListModelMixin, RetrieveModelMixin
from rest_framework.mixins import CreateModelMixin, DestroyModelMixin,UpdateModelMixin # Create your views here. class SchoolView(GenericAPIView, ListModelMixin):
queryset = models.School.objects.all()
serializer_class = app01_serializers.SchoolSerializer def get(self, request, *args, **kwargs): # GET请求
return self.list(request, *args, **kwargs) # RetrieveModelMixin 表示查询单条数据,需要传入pk参数
class SchoolDetail(GenericAPIView, RetrieveModelMixin):
queryset = models.School.objects.all()
serializer_class = app01_serializers.SchoolSerializer def get(self, request, pk, *args, **kwargs): # GET请求
return self.retrieve(request, pk, *args, **kwargs) class CommentView(GenericAPIView, ListModelMixin,CreateModelMixin):
queryset = models.Comment.objects.all()
serializer_class = app01_serializers.CommentSerializer def get(self, request, *args, **kwargs): # GET请求
return self.list(request, *args, **kwargs) def post(self, request, *args, **kwargs): # POST请求
return self.create(request, *args, **kwargs) # RetrieveModelMixin 表示查询单条数据,需要传入pk参数
class CommentDetail(GenericAPIView, RetrieveModelMixin,DestroyModelMixin,UpdateModelMixin):
queryset = models.Comment.objects.all()
serializer_class = app01_serializers.CommentSerializer def get(self, request, pk, *args, **kwargs): # GET请求
return self.retrieve(request, pk, *args, **kwargs) def delete(self, request, pk, *args, **kwargs): # DELETE请求
return self.destroy(request, pk, *args, **kwargs) def perform_destroy(self, instance):
print("你真的真的确定要删除了吗?...")
instance.delete() def put(self, request, pk, *args, **kwargs): # PUT请求
return self.update(request, pk, *args, **kwargs)
json数据
{
"id": 6,
"content": "从前的日色变得慢",
"article": 1
}
使用put发送,选择JSON
如果返回结果是:
415(Unsupported Media Type)不支持的类型异常
请查看Headers,一定要勾选
再次发送,查看返回结果
查看表app01_comment,发现记录更新了!
牛气冲天之使用通用类
Django REST framework提供了9个通用视图,详情请参考以下链接中的《混凝土视图类》
https://www.cnblogs.com/yangxiaoling/p/6914880.html
RetrieveUpdateDestroyAPIView
用于读写删除端点来表示单个模型实例。
提供get
,put
,patch
和delete
方法处理。
扩展:GenericAPIView,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
它相当于上面葫芦娃例子中的奇数娃
使用需要导入模块
from rest_framework.generics import RetrieveUpdateDestroyAPIView
举例:将CommentDetail改造成RetrieveUpdateDestroyAPIView
它拥有get,put,patch和delete方法处理,所以之前的那些方法,都可以干掉了!
from django.shortcuts import render, HttpResponse
from app01 import models
from rest_framework.views import APIView
from app01 import app01_serializers # 导入自定义的序列化
from rest_framework.response import Response
from rest_framework.generics import GenericAPIView,RetrieveUpdateDestroyAPIView
from rest_framework.mixins import ListModelMixin, RetrieveModelMixin
from rest_framework.mixins import CreateModelMixin, DestroyModelMixin,UpdateModelMixin # Create your views here. class SchoolView(GenericAPIView, ListModelMixin):
queryset = models.School.objects.all()
serializer_class = app01_serializers.SchoolSerializer def get(self, request, *args, **kwargs): # GET请求
return self.list(request, *args, **kwargs) # RetrieveModelMixin 表示查询单条数据,需要传入pk参数
class SchoolDetail(GenericAPIView, RetrieveModelMixin):
queryset = models.School.objects.all()
serializer_class = app01_serializers.SchoolSerializer def get(self, request, pk, *args, **kwargs): # GET请求
return self.retrieve(request, pk, *args, **kwargs) class CommentView(GenericAPIView, ListModelMixin,CreateModelMixin):
queryset = models.Comment.objects.all()
serializer_class = app01_serializers.CommentSerializer def get(self, request, *args, **kwargs): # GET请求
return self.list(request, *args, **kwargs) def post(self, request, *args, **kwargs): # POST请求
return self.create(request, *args, **kwargs) class CommentDetail(RetrieveUpdateDestroyAPIView):
queryset = models.Comment.objects.all()
serializer_class = app01_serializers.CommentSerializer
测试GET
测试PUT
查看返回结果
查看表app01_comment
测试DELETE
它的返回结果是空的
查看表记录,发现少了一条记录
注意:它没有POST,否则会返回"detail": "Method \"POST\" not allowed."
ListCreateAPIView
用于读写端点来表示模型实例的集合。
提供get
和post
方法处理程序。
扩展:GenericAPIView,ListModelMixin,CreateModelMixin
它相当于上面葫芦娃例子中的偶数娃
使用需要导入模块
from rest_framework.generics import ListCreateAPIView
举例:将CommentView改造成ListCreateAPIView
它拥有get,post方法处理,所以之前的那些方法,都可以干掉了!
from django.shortcuts import render, HttpResponse
from app01 import models
from rest_framework.views import APIView
from app01 import app01_serializers # 导入自定义的序列化
from rest_framework.response import Response
from rest_framework.generics import GenericAPIView,RetrieveUpdateDestroyAPIView,ListCreateAPIView
from rest_framework.mixins import ListModelMixin, RetrieveModelMixin
from rest_framework.mixins import CreateModelMixin, DestroyModelMixin,UpdateModelMixin # Create your views here. class SchoolView(GenericAPIView, ListModelMixin):
queryset = models.School.objects.all()
serializer_class = app01_serializers.SchoolSerializer def get(self, request, *args, **kwargs): # GET请求
return self.list(request, *args, **kwargs) # RetrieveModelMixin 表示查询单条数据,需要传入pk参数
class SchoolDetail(GenericAPIView, RetrieveModelMixin):
queryset = models.School.objects.all()
serializer_class = app01_serializers.SchoolSerializer def get(self, request, pk, *args, **kwargs): # GET请求
return self.retrieve(request, pk, *args, **kwargs) class CommentView(ListCreateAPIView):
queryset = models.Comment.objects.all()
serializer_class = app01_serializers.CommentSerializer class CommentDetail(RetrieveUpdateDestroyAPIView):
queryset = models.Comment.objects.all()
serializer_class = app01_serializers.CommentSerializer
测试GET
测试POST,注意后面没有数字
查看返回结果
查看表app01_comment,发现多了一条记录
牛牛牛牛之使用视图集
ModelViewSet
ModelViewSet视图集会自动提供list,create, retrieve, update & destroy这些行为,
查看源代码:它有6个功能
也就说它具有5个葫芦娃的能力,也就是上面面向对象讲到的套娃
使用时,需要导入模块
from rest_framework.viewsets import ModelViewSet
处理器方法只有在定义了URLConf的时候才会绑定这些行为。
在urls.py文件中,我们把ViewSet绑定到一些具体的视图上
修改app01_urls.py
from django.conf.urls import url
from app01 import views urlpatterns = [
# 学校
url(r'school/$', views.SchoolView.as_view()),
url(r'school/(?P<pk>\d+)/$', views.SchoolDetail.as_view()), # 评论
url(r'comment/$', views.CommentViewSet.as_view({
'get': "list",
'post': 'create'
})), url(r'comment/(?P<pk>\d+)/$', views.CommentViewSet.as_view({
'get': 'retrieve',
'put': 'update',
'delete': 'destroy'
})),
]
参数解释:
get,post,put,delete分别表示不同的请求方式
后面对应的值分别是ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
修改views.py,增加一个视图函数,注释多余的代码
from django.shortcuts import render, HttpResponse
from app01 import models
from rest_framework.views import APIView
from app01 import app01_serializers # 导入自定义的序列化
from rest_framework.response import Response
from rest_framework.generics import GenericAPIView,RetrieveUpdateDestroyAPIView,ListCreateAPIView
from rest_framework.mixins import ListModelMixin, RetrieveModelMixin
from rest_framework.mixins import CreateModelMixin, DestroyModelMixin,UpdateModelMixin
from rest_framework.viewsets import ModelViewSet # Create your views here. class SchoolView(GenericAPIView, ListModelMixin):
queryset = models.School.objects.all()
serializer_class = app01_serializers.SchoolSerializer def get(self, request, *args, **kwargs): # GET请求
return self.list(request, *args, **kwargs) # RetrieveModelMixin 表示查询单条数据,需要传入pk参数
class SchoolDetail(GenericAPIView, RetrieveModelMixin):
queryset = models.School.objects.all()
serializer_class = app01_serializers.SchoolSerializer def get(self, request, pk, *args, **kwargs): # GET请求
return self.retrieve(request, pk, *args, **kwargs) # class CommentView(ListCreateAPIView):
# queryset = models.Comment.objects.all()
# serializer_class = app01_serializers.CommentSerializer
#
#
# class CommentDetail(RetrieveUpdateDestroyAPIView):
# queryset = models.Comment.objects.all()
# serializer_class = app01_serializers.CommentSerializer class CommentViewSet(ModelViewSet):
queryset = models.Comment.objects.all()
serializer_class = app01_serializers.CommentSerializer
一个视图函数,就搞定了5种请求方式,惊叹不已!
测试GET
后面的几种请求方式,大家可以自行测试!
再来一牛之高级路由
视图
同上,还是使用ModelViewSet
路由
因为我们正在使用ViewSet
代替View
,实际上已经不再需要自己来设计URL的配置了。将资源和视图、URL绑定到一起是一个可以自动完成的过程,只需要使用Router
即可。我们需要做的就是将视图集注册到Router上去而已。
修改app01_urls.py
from django.conf.urls import url
from app01 import views urlpatterns = [
# 学校
url(r'school/$', views.SchoolView.as_view()),
url(r'school/(?P<pk>\d+)/$', views.SchoolDetail.as_view()), # 评论
# url(r'comment/$', views.CommentViewSet.as_view({
# 'get': "list",
# 'post': 'create'
# })),
#
# url(r'comment/(?P<pk>\d+)/$', views.CommentViewSet.as_view({
# 'get': 'retrieve',
# 'put': 'update',
# 'delete': 'destroy'
# })),
] from rest_framework.routers import DefaultRouter router = DefaultRouter()
# 注册路由,表示路径comment对应视图函数CommentViewSet
router.register(r'comment', views.CommentViewSet)
urlpatterns += router.urls
将ViewSets注册到Routers的过程实际上类似于提供一个urlpattern。我们引入了两个参数,一个是views的URL prefix,另一个是viewset本身。
我们使用的DefaultRouter
也会自动地帮我们创建API root视图,多余路由可以注释掉了!
赠图一张,祝君好运
二、django logging配置
做开发开不开日志,以下是我在工作中写Django项目常用的logging配置。
配置
修改settings.py,最后一行添加
BASE_LOG_DIR = os.path.join(BASE_DIR, 'log')
# 日志相关配置
LOGGING = {
'version': 1, # 保留字段
'disable_existing_loggers': False, # 不要禁用已经存在的logger实例 'formatters': { # 定义三种日志显示的格式
'standard': {
'format': '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]'
'[%(levelname)s][%(message)s]'
},
'simple': {
'format': '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
},
'collect': {
'format': '%(message)s'
}
}, 'filters': { # 定义一个过滤规则
'require_debug_true': {
'()': 'django.utils.log.RequireDebugTrue',
},
}, 'handlers': { # 日志流的处理方式
'console': { # 把日志打印到终端
'level': 'DEBUG',
'filters': ['require_debug_true'], # 只有在Django debug为True时才在屏幕打印日志
'class': 'logging.StreamHandler',
'formatter': 'simple'
},
'default': {
'level': 'INFO',
'class': 'logging.handlers.RotatingFileHandler', # 保存到文件,自动切
'filename': os.path.join(BASE_LOG_DIR, "info.log"), # 日志文件
'maxBytes': 1024 * 1024 * 500, # 日志大小 500M
'backupCount': 3, #
'formatter': 'standard',
'encoding': 'utf-8',
},
'error': {
'level': 'ERROR',
'class': 'logging.handlers.RotatingFileHandler', # 保存到文件,自动切
'filename': os.path.join(BASE_LOG_DIR, "err.log"), # 日志文件
'maxBytes': 1024 * 1024 * 500, # 日志大小 500M
'backupCount': 5,
'formatter': 'standard',
'encoding': 'utf-8',
},
'collect': {
'level': 'INFO',
'class': 'logging.handlers.RotatingFileHandler', # 保存到文件,自动切
'filename': os.path.join(BASE_LOG_DIR, "collect.log"),
'maxBytes': 1024 * 1024 * 500, # 日志大小 500M
'backupCount': 5,
'formatter': 'collect',
'encoding': "utf-8"
}
},
'loggers': { # 默认的logger应用如下配置
'': {
'handlers': ['default', 'console', 'error'], # 上线之后可以把'console'移除
'level': 'DEBUG',
'propagate': True, # 是否向父级logger实例传递日志信息
}, # 名为 'collect'的logger还单独处理
'collect': {
'handlers': ['console', 'collect'],
'level': 'INFO',
}
},
}
注意要手动创建log目录,目录里面创建3个文件err.log,info.log,collect.log
使用
在视图函数中使用时,先导入模块,并声明变量
import logging
# 生成一个以当前文件名为名字的 logger实例
logger = logging.getLogger(__name__)
# 生成一个名字为collect的日志实例
collect_logger = logging.getLogger('collect')
然后在逻辑代码中加入
logger.warning('找不到记录...')
或者
collect_logger.info(name)
Python logger流示图
附:Python logger流示图
三、django-debug-toolbar使用指南
介绍
django-debug-toolbar 是一组可配置的面板,可显示有关当前请求/响应的各种调试信息,并在单击时显示有关面板内容的更多详细信息。
安装
pip3 install django-debug-toolbar
配置
1. settings.py中
将 debug_toolbar 添加到 INSTALL_APPS 中,最后一行添加
INSTALLED_APPS = [
…
'debug_toolbar',
]
2. urls.py中
from django.conf import settings
from django.conf.urls import include, url if settings.DEBUG:
import debug_toolbar
urlpatterns = [
url(r'^__debug__/', include(debug_toolbar.urls)),
] + urlpatterns
3. settings.py中
在中间件中加入DebugToolbarMiddleware,最后一行添加
MIDDLEWARE = [
# ...
'debug_toolbar.middleware.DebugToolbarMiddleware',
]
4.加入 INTERNAL_IPS
如果是本机调试,还在将127.0.0.1加入 INTERNAL_IPS
在settings.py中加入以下配置项:
INTERNAL_IPS = ['127.0.0.1', ]
5. 配置jQuery的URL
django-debug-toolbar 默认使用的是Google的地址,默认配置如下:
JQUERY_URL = '//ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js'
国内用不了的话可以在settings.py中配置一下,例如(我这里特意选用了和原作者相同版本的jQuery):
修改settings.py,最后一行添加
DEBUG_TOOLBAR_CONFIG = {
"JQUERY_URL": '//cdn.bootcss.com/jquery/2.2.4/jquery.min.js',
}
或者你如果在Django项目中使用了jquery的话就可以直接将这一项置为空,那么django-debug-toolbar 就会使用你项目中用到的jquery:
DEBUG_TOOLBAR_CONFIG = {
"JQUERY_URL": '',
}
使用
访问具体路径的时候在页面右侧有各项配置面板,点击即可查看各种调试信息。
python 全栈开发,Day96(Django REST framework 视图,django logging配置,django-debug-toolbar使用指南)的更多相关文章
- python 全栈开发,Day111(客户管理之 编辑权限(二),Django表单集合Formset,ORM之limit_choices_to,构造家族结构)
昨日内容回顾 1. 权限系统的流程? 2. 权限的表有几个? 3. 技术点 中间件 session orm - 去重 - 去空 inclusion_tag filter 有序字典 settings配置 ...
- python 全栈开发,Day72(昨日作业讲解,昨日内容回顾,Django多表创建)
昨日作业讲解 1.图书管理系统 实现功能:book单表的增删改查 1.1 新建一个项目bms,创建应用book.过程略... 1.2 手动创建static目录,并在目录里面创建css文件夹,修改set ...
- python 全栈开发,Day26(hashlib文件一致性,configparser,logging,collections模块,deque,OrderedDict)
一.hashlib文件一致性校验 为何要进行文件一致性校验? 为了确保你得到的文件是正确的版本,而没有被注入病毒和木马程序.例如我们经常在网上下载软件,而这些软件已经被注入了一些广告和病毒等,如果不进 ...
- python 全栈开发,Day99(作业讲解,DRF版本,DRF分页,DRF序列化进阶)
昨日内容回顾 1. 为什么要做前后端分离? - 前后端交给不同的人来编写,职责划分明确. - API (IOS,安卓,PC,微信小程序...) - vue.js等框架编写前端时,会比之前写jQuery ...
- python全栈开发目录
python全栈开发目录 Linux系列 python基础 前端~HTML~CSS~JavaScript~JQuery~Vue web框架们~Django~Flask~Tornado 数据库们~MyS ...
- Python全栈开发相关课程
Python全栈开发 Python入门 Python安装 Pycharm安装.激活.使用 Python基础 Python语法 Python数据类型 Python进阶 面向对象 网络编程 并发编程 数据 ...
- Python 全栈开发【第0篇】:目录
Python 全栈开发[第0篇]:目录 第一阶段:Python 开发入门 Python 全栈开发[第一篇]:计算机原理&Linux系统入门 Python 全栈开发[第二篇]:Python基 ...
- Python全栈开发【面向对象进阶】
Python全栈开发[面向对象进阶] 本节内容: isinstance(obj,cls)和issubclass(sub,super) 反射 __setattr__,__delattr__,__geta ...
- Python全栈开发【面向对象】
Python全栈开发[面向对象] 本节内容: 三大编程范式 面向对象设计与面向对象编程 类和对象 静态属性.类方法.静态方法 类组合 继承 多态 封装 三大编程范式 三大编程范式: 1.面向过程编程 ...
- Python全栈开发【模块】
Python全栈开发[模块] 本节内容: 模块介绍 time random os sys json & picle shelve XML hashlib ConfigParser loggin ...
随机推荐
- switchyomega插件的基本使用
switchyomega插件的基本使用 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 作为一名合格的开发工程师,使用插件本应该就是手到擒来的事情,可能刚刚入开发门槛的人,在使用插件 ...
- java keytool证书工具使用小结【转】
java keytool证书工具使用小结 keytool导入导出多条目对比 在Security编程中,有几种典型的密码交换信息文件格式: DER-encoded certificate: .cer, ...
- golang数组排序算法
冒泡排序 图 https://www.cnblogs.com/onepixel/articles/7674659.html package main import ( "fmt" ...
- C++字符串(srtring)反转
对称平方数 题目描述 打印所有不超过n(n<256)的,其平方具有对称性质的数.如11*11=121. 分析: 1.首先使用函数to_string将int转化为string: 2.然后将字符串反 ...
- 二、Internet地址结构
IP路由器实现的转发程序使用IP地址来识别流量去向.IP地址也表示流量来源. 2.1 IP地址的表示 IPV4地址通常采用点分四组或点分十进制表示法,如192.168.1.1. 点分四组表示法由四个用 ...
- vue单页应用中 返回列表记住上次滚动位置、keep-alive缓存之后更新列表数据 那点事
实践场景需求 产品列表中,滚动到一定位置的时候,点击查看产品信息,后退之后,需要回到原先的滚动位置,这是常见的需求 所有页面均在router-view中,暂时使用了keep-alive来缓存所有页面, ...
- python之functools partial
from functools import partial def aa(a,b,c): print ('a :',a) print ('b :',b) print ('c :',c) bb=part ...
- C - Portals Gym - 102006C (网络流最小割)
题目链接:https://cn.vjudge.net/contest/283918#problem/C 题目大意:T个测试数据,然后给你一个字符串,每一个字符串包括‘s’,‘t’,‘o’,‘#’,‘. ...
- AJAX请求 $.ajaxSetup方法的使用:设置AJAX请求的默认参数选项,当程序中需要发起多个AJAX请求时,则不用再为每一个请求配置请求的参数
定义和用法ajaxSetup() 方法为将来的 AJAX 请求设置默认值.语法$.ajaxSetup({name:value, name:value, ... }) 该参数为带有一个或多个名称/值对的 ...
- Udacity并行计算课程 CS344 编程作业答案
Problem set 1 // Homework 1 // Color to Greyscale Conversion //A common way to represent color image ...