3、django视图层

#前言:视图逻辑怎么分块儿都可以。只要你的路由能找到就行。#

 

1、CBV(class base views)模式和FBV(function base views)模式

  顾名思义。一个在views里面写函数。一个在views里写类方法。

  CBV具体格式如下:

  urls代码:  

from django.urls import path,re_path
from CBV_app import views

urlpatterns = [
    path('login/', views.Login.as_view()),
    path('starter/', views.Starter.as_view()),
]

  views代码:

class Login(View):

    def get(self, request):
        return HttpResponse("ok")
    
    def post(self, request):
        pass
    
    
class Starter(View):
    def get(self, request):
        return render(request, 'base.html')
    
    def post(self, request):
        pass

  如上:CBV与FBV相比好处就是。是用class的方式编写,可以使用面向对象的好处。如多继承,反射等等。

  且继承的view类中的dispatch方法帮我们写了请求分发。我们只需要把自己的方法名写成对应请求类型即可(如上)。不用再去判断请求类型。

  view部分源码截取如下:

class View:
    """
    Intentionally simple parent class for all views. Only implements
    dispatch-by-method and simple sanity checking.
    """

    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 kwargs.items():
            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)

 

2、request和response

  请求数据平常使用较多的有。cookies、session、token、body参数、user-agent等等。(META可以拿ip),无需再看

  响应在views中主要有三种形式。HttpResponse()、render()、redirect()、

    HttpResponse()就返回一个具体的字符串。没有什么好说的。

    render()、源码如下:

def render(request, template_name, context=None, content_type=None, status=None, using=None):
    """
    Return a HttpResponse whose content is filled with the result of calling
    django.template.loader.render_to_string() with the passed arguments.
    """
    content = loader.render_to_string(template_name, context, request, using=using)
    return HttpResponse(content, content_type, status)

      1、request,用于生成响应的请求对象。

      2、template_name,要使用的模板的完整名称,可选

      3、context,添加到模板的一个字典,如果不为空。则在渲染之前调用。(多用于前后端不分离项目)

    redirect()

      如下代码。一个很简陋的demo。校验IP访问频率。次数过多重定向。

class AccessFrequencyVerification2(MiddlewareMixin):
    """
    做访问频率校验。
    1、每次登录。在表里面查询有无该ip的访问记录。
    2、如果没有。记录ip、访问时间。 访问次数写成1
    3、如果表里面查询有该IP的访问记录。且访问时间距当前时间小于60s,则访问次数+1。大于则把访问次数写为0。
    4、访问之前判断次数有没有大于20。如果大于,请求接到一个独立页面。
    """
    def process_request(self, request):
        if request.path in ["/error/"]:
            return None
        else:
            if request.META.get('HTTP_X_FORWARDED_FOR'):
                ip = request.META.get("HTTP_X_FORWARDED_FOR")
            else:
                ip = request.META.get("REMOTE_ADDR")

            a = AccessFrequencyVerification.objects.filter(ip=ip).first()
            if a is None:
                # 新用户插入数据逻辑
                time = timezone.now()
                AccessFrequencyVerification.objects.create(
                    ip=ip,
                    Access_time=time,
                    Number_visits=1,
                )
            else:
                # 老用户处理逻辑
                Access_time = AccessFrequencyVerification.objects.filter(ip=ip).first().Access_time
                time = timezone.now()
                time_difference = time-Access_time
                a = AccessFrequencyVerification.objects.filter(ip=ip).first().Number_visits
                b = datetime.timedelta(seconds=60)
                if time_difference < b:
                    # 60s之内连续登录
                    AccessFrequencyVerification.objects.filter(ip=ip).update(Number_visits=a+1)
                else:
                    # 60s之后登录
                    AccessFrequencyVerification.objects.filter(ip=ip).update(Access_time=time)
                    AccessFrequencyVerification.objects.filter(ip=ip).update(Number_visits=0)
                if a > 20:
                    return redirect("/error/")
                else:
                    return None

    当然,重定向也可以写一个完成URL。

     

posted @ 2020-01-03 16:30  John.Liu-  阅读(133)  评论(0编辑  收藏  举报