Python Django之虚拟环境搭建、视图函数CBV、FBV及CSRF原理(7)

本文详细介绍了如何在Django中搭建和使用virtualenv虚拟环境,以及视图函数CBV(Class-Based Views)和FBV(Function-Based Views)的区别和使用方法,包括源码分析。同时,讲解了CSRF(Cross-Site Request Forgery)请求认证的原理,并展示了在FBV和CBV中如何启用和禁用CSRF保护。
摘要由CSDN通过智能技术生成

一、django虚拟环境搭建

1.搭建虚拟环境virtualenv


在一般做项目中,为了项目在各版本之间可以兼容,一般都会使用虚拟环境来搭建django版本框架,目的是为了让项目更加的适应,所以今天就来教大家搭建一个虚拟环境virtualenv安装方法:

  1. 打开终端(cmd)
  2. 安装pip3 install virtualenv
  3. virtualenv 环境名称(安装在哪个盘或目录可以自己指定例如:D:)
  4. virtualenv 环境名称(例如:env2)
  5. cd 环境名称(env2) scripts目录
  6. 终端输入activate激活
  7. pip3 install django(版本自行指定)
  8. 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。这样做的优点主要下面两种:

  1. 提高了代码的复用性,可以使用面向对象的技术,比如Mixin(多继承)
  2. 可以用不同的函数针对不同的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函数中。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值