目录
一、django虚拟环境搭建
1.搭建虚拟环境virtualenv
在一般做项目中,为了项目在各版本之间可以兼容,一般都会使用虚拟环境来搭建django版本框架,目的是为了让项目更加的适应,所以今天就来教大家搭建一个虚拟环境virtualenv安装方法:
- 打开终端(cmd)
- 安装pip3 install virtualenv
- virtualenv 环境名称(
安装在哪个盘或目录可以自己指定
例如:D:) - virtualenv 环境名称(例如:env2)
- cd 环境名称(env2) scripts目录
- 终端输入activate激活
- pip3 install django(版本自行指定)
- deactivate.bat 退出虚拟环境
2.django中使用virtualenv虚拟环境
打开file->new project->django
选择安装好虚拟环境的python.exe后点OK
之后在点create即可完成
进去之后打开pycharm的终端显示:
此时如果箭头指向的是和你之前设置的虚拟环境名一样即可。
二、视图函数CBV、FBV的介绍
CBV(class base views) 就是在视图里使用类处理请求。
Python是一个面向对象的编程语言,如果只用函数来开发,有很多面向对象的优点就错失了(继承、封装、多态)
。所以Django在后来加入了Class-Based-View,可以让我们用类写View。这样做的优点主要下面两种:
- 提高了代码的复用性,可以使用面向对象的技术,比如Mixin(多继承)
- 可以用不同的函数针对不同的HTTP方法处理,而不是通过很多if判断,提高代码可读性
而且一般支持CBV视图函数操作的框架一般都是基于反射的方式做的。
FBV(function base views) 就是在视图里使用函数处理请求。
1.视图函数FBV的使用
相信看过前面文章的朋友已经知道了fbv使用方法了,类似一个视图函数处理,这里就简单展示一下即可(这里我创建的django项目名是app01)
在urls中定义:
from django.conf.urls import url
from app01 import views
urlpatterns = [
url(r'^index/', views.index),
]
app01/views.py如下:
from django.shortcuts import render, HttpResponse
from django.http import JsonResponse
from django.views import View
def index(request):
if request.method == "GET":
data_list = {'id': 1, 'title': '小编', 'age': 18}
return JsonResponse(data_list)
return HttpResponse('post的ok')
这里的JsonResponse是用于模板渲染给浏览器时使用json格式。
此时访问http://127.0.0.1:8000/index/显示:
可以看到数据通过get方式传递了过来,且通过JsonResponse渲染成了json的格式。
2.视图函数CBV的使用
CBV的使用,顾名思义就是用类方法的方式调用各种函数请求,而类就是(面向对象的理念:对同一类的方法封装到类中、将数据封装到对象中
),所以在使用CBV的时候django给我们封装好了请求函数,而我们只需要安装它的方法来将其调用即可。
为了后面方便请求之间的调用方便这里先安装一下postman,该软件是一款请求模拟工具,可以让我们很好的测试我们的数据(该工具到我们后面讲的django-rest-framwork中测试api中会使用)。
下载链接:https://pan.baidu.com/s/1Hs1-QoJipKOImuygge_8Lw
提取码:drpk
在urls中定义:
from django.conf.urls import url
from app01 import views
urlpatterns = [
url(r'^index/', views.index),
url(r'^students/', views.Students.as_view()),
]
在django中使用cbv需要调用as_view()函数
app01/views.py如下:
from django.shortcuts import render, HttpResponse
from django.http import JsonResponse
from django.views import View
def index(request):
if request.method == "GET":
data_list = {'id': 1, 'title': '小编', 'age': 18}
return JsonResponse(data_list)
return HttpResponse('post的ok')
class Students(View):
def get(self, request, *args, **kwargs):
return HttpResponse('get')
def post(self, request, *args, **kwargs):
return HttpResponse('post')
def put(self, request, *args, **kwargs):
return HttpResponse('put')
def delete(self, request, *args, **kwargs):
return HttpResponse('delete')
可以发现使用cbv时需要继承Django中的View的方法
受csrf的影响我们先把它注释掉,详细到后面在讲
在settings如下:
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',
]
此时打开postman访问http://127.0.0.1:8000/students/如下:
可以发现请求都是没问题的,且使用了类方法之后代码变的整洁了很多。
3.视图函数CBV源码分析
为了更加深层次的理解CBV视图函数,我们将对它的源码进行分析,首先我们知道CBV视图函数继承于View所以且实现方法是通过反射实现
的所以,我们可以去查看一下CBV派生类(子类)的父类方法View中的源码进行分析。
在分析源码前我们需要理解一下类之间的封装关系:
新建一个test.py进行测试:
class Reuqest(object):
def __init__(self, obj):
self.obj = obj
class Auth(object):
def __init__(self, name, age):
self.name = name
self.age = age
def authticate(self):
return True
class APIView(object):
def dispatch(self):
self.f2()
def f2(self):
a = Auth('sehun', 18)
req = Reuqest(a)
print(req.obj)
print(req.obj.name, req.obj.age)
if __name__ == '__main__':
api = APIView()
api.dispatch()
此时我们通过APIView类的方法调用了dispatch函数,函数中调用其他函数的类,所以此时在执行f2函数中调用了Request类传入了参数a,而参数a继承了Auth类,所以参数a参数传入给了Request的obj对象,使得obj对象为Auth类
,所以打印的参数为:
<__main__.Auth object at 0x000001D111D97948>
sehun 18
明白这些后我们在继续改进
test.py如下:
class Reuqest(object):
def __init__(self, obj):
self.obj = obj
@property
def user(self):
return self.obj.authticate()
class Auth(object):
def __init__(self, name, age):
self.name = name
self.age = age
def authticate(self):
return True
class APIView(object):
def dispatch(self):
self.f2()
def f2(self):
a = Auth('sehun', 18)
req = Reuqest(a)
print(req.user)
if __name__ == '__main__':
api = APIView()
api.dispatch()
打印参数为
True
此时执行后能发现在调用类方法ApIView中的dispatch函数中一步一步的嵌套函数最终执行了Auth中的authticate函数(@property为装饰器,其目的是为了调用函数时无需传括号)
理解了这些后,我们来看一下django中View的源码
如下:
class View(object):
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
def __init__(self, **kwargs):
"""
Constructor. Called in the URLconf; can contain helpful extra
keyword arguments, and other things.
"""
# Go through keyword arguments, and either save their values to our
# instance, or raise an error.
for key, value in six.iteritems(kwargs):
setattr(self, key, value)
@classonlymethod
def as_view(cls, **initkwargs):
"""
Main entry point for a request-response process.
"""
for key in initkwargs:
if key in cls.http_method_names:
raise TypeError("You tried to pass in the %s method name as a "
"keyword argument to %s(). Don't do that."
% (key, cls.__name__))
if not hasattr(cls, key):
raise TypeError("%s() received an invalid keyword %r. as_view "
"only accepts arguments that are already "
"attributes of the class." % (cls.__name__, key))
def view(request, *args, **kwargs):
self = cls(**initkwargs)
if hasattr(self, 'get') and not hasattr(self, 'head'):
self.head = self.get
self.request = request
self.args = args
self.kwargs = kwargs
return self.dispatch(request, *args, **kwargs)
view.view_class = cls
view.view_initkwargs = initkwargs
# take name and docstring from class
update_wrapper(view, cls, updated=())
# and possible attributes set by decorators
# like csrf_exempt from dispatch
update_wrapper(view, cls.dispatch, assigned=())
return view
def dispatch(self, request, *args, **kwargs):
# Try to dispatch to the right method; if a method doesn't exist,
# defer to the error handler. Also defer to the error handler if the
# request method isn't on the approved list.
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
抛开后面那些函数,我们只看as_view函数
可以看到之前我们在urls中调用了as_view的函数,当请求进来后会执行view函数
,所以我们从view函数中看,可以发现函数view内部调用且返回了dispatch函数
,然后在dispatch函数中执行了其他函数的方法调用,而调用什么方法就是根据上面http_method_names中的列表进行判断的,而返回的值则为render, HttpResponse这些函数了
。
从这些角度,我们能发现,如果在我们继承了View实例对象的时候,是否可以根据类的属性继承来实现相应请求的封装呢。
app01/views.py如下:
from django.shortcuts import render, HttpResponse
from django.http import JsonResponse
from django.views import View
def index(request):
if request.method == "GET":
data_list = {'id': 1, 'title': '小编', 'age': 18}
return JsonResponse(data_list)
return HttpResponse('post的ok')
class Students(View):
def dispatch(self, request, *args, **kwargs):
if request.method == "GET":
return HttpResponse('before_get')
# 去当前类中找不同的方法
func = getattr(self, request.method.lower())
# 返回HttpResponse对象
ret = func(request, *args, **kwargs)
return ret
def get(self, request, *args, **kwargs):
return HttpResponse('get')
def post(self, request, *args, **kwargs):
return HttpResponse('post')
def put(self, request, *args, **kwargs):
return HttpResponse('put')
def delete(self, request, *args, **kwargs):
return HttpResponse('delete')
此时打开postman访问http://127.0.0.1:8000/students/如下:
可以发现通过反射的操作,就可以灵活的对返回请求函数做相应的操作了
,那么类都是继承关系,我们能否直接继承View实例的函数并重写呢?
app01/views.py如下:
from django.shortcuts import render, HttpResponse
from django.http import JsonResponse
from django.views import View
def index(request):
if request.method == "GET":
data_list = {'id': 1, 'title': '小编', 'age': 18}
return JsonResponse(data_list)
return HttpResponse('post的ok')
class MyBaseView(object):
def dispatch(self, request, *args, **kwargs):
# 请求结束前
if request.method == "POST":
return HttpResponse('404')
# 继承父类方法
res = super(MyBaseView, self).dispatch(request, *args, **kwargs)
# 请求结束后
return res
class Students(MyBaseView, View):
def get(self, request, *args, **kwargs):
return HttpResponse('get')
def post(self, request, *args, **kwargs):
return HttpResponse('post')
def put(self, request, *args, **kwargs):
return HttpResponse('put')
def delete(self, request, *args, **kwargs):
return HttpResponse('delete')
此时打开postman访问http://127.0.0.1:8000/students/如下:
可以发现类之间是可以继承的,且继承的时候也要注意先后顺序为从左到右查找,当子类MyBaseView继承父类Students时调用函数发现没有该函数时,会依次从左往右查找函数,调用Students的父类View的dispatch函数
。
三、CSRF请求认证
1.Csrf的介绍
CSRF跨站点请求伪造(Cross—Site Request Forgery)是通过中间件实现的,目的是为了用户访问浏览器时更加的安全(不会受到xss攻击),本质上是生成一堆的随机字符串。
settings如下:
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',
]
中间件是类似于在执行前和返回后的判断,和校验,一般可以用于用户登录验证,session的token校验、路由黑白名单那和各种验证中会使用到(具体后面介绍)。
而我们现在要知道
csrf是基于中间件中的process_view方法中实现
的,用于检查视图是否被 @csrf_exempt(免除csrf认证),
内部是通过请求体或cookie中获取token去调用
,此时我们将注释解除掉。
2.FBV中取消、添加Csrf认证
app01/views.py如下:
from django.shortcuts import render, HttpResponse
from django.http import JsonResponse
from django.views import View
from django.views.decorators.csrf import csrf_exempt,csrf_protect
@csrf_exempt
def index(request):
if request.method == "GET":
data_list = {'id': 1, 'title': '小编', 'age': 18}
return JsonResponse(data_list)
return HttpResponse('post的ok')
此时打开postman访问http://127.0.0.1:8000/index/如下:
可以看到,加了@csrf_exempt即可免除csrf的认证了。
如果想添加csrf认证可以加@csrf_protect装饰器。
3.CBV中取消、添加Csrf认证
app01/views.py如下:
from django.shortcuts import render, HttpResponse
from django.http import JsonResponse
from django.views import View
from django.views.decorators.csrf import csrf_exempt, csrf_protect
from django.utils.decorators import method_decorator
class MyBaseView(object):
@method_decorator(csrf_exempt)
def dispatch(self, request, *args, **kwargs):
# 请求结束前
if request.method == "POST":
return HttpResponse('404')
# 继承父类方法
res = super(MyBaseView, self).dispatch(request, *args, **kwargs)
# 请求结束后
return res
class Students(MyBaseView, View):
def get(self, request, *args, **kwargs):
return HttpResponse('get')
def post(self, request, *args, **kwargs):
return HttpResponse('post')
def put(self, request, *args, **kwargs):
return HttpResponse('put')
def delete(self, request, *args, **kwargs):
return HttpResponse('delete')
此时打开postman访问http://127.0.0.1:8000/students/如下:
可以发现通过 @method_decorator(csrf_exempt)即可取消csrf的认证,同理添加也是一样只需要@method_decorator(csrf_protect)即可,不过该装饰器需写在类方法的dispatch函数
中。