#前言:视图逻辑怎么分块儿都可以。只要你的路由能找到就行。#
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。