当Django处理一个Request的过程是首先通过中间件,然后再通过默认的URL方式进行的。我们可以在Middleware这个地方把所有Request拦截住,用我们自己的方式完成处理以后直接返回Response,因此了解中间件的构成是非常有必要的。

1,中间件的概念

  一个完整的Django流程如下:

Django默认的Middleware如下:

  在Django项目中的settings模块中,有一个MIDDLEWARE_CLASSES变量,其中每一个元素就是一个中间件,如下:

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',
]

  每一个中间件都有具体的功能。中间件可以定义五个方法。

分析源码

  我们可以查看上面middleware 的源码,我们首先导入security:

from django.middleware.security import SecurityMiddleware

  我们查看源码,会发现:

  同样,我们再查看一个:

from django.middleware.common import CommonMiddleware

  我们查看源码,会发现:

再来继续:

from django.middleware.csrf import CsrfViewMiddleware

  我们查看源码,发现:

  我们是不是发现了一个共同的特点。也就是都有process_request和process_response。但是并不是所有的中间件都有process_request,但是所有中间件都有process_response。而且我们在写中间件的时候,在process_response一定要注意有返回值!!,process_request没有!!,如果process_request有return值的时候,就不会执行后面的程序了(所以这里可以拦截)

from django.middleware.clickjacking import XFrameOptionsMiddleware

  查看源码:

  我们从浏览器发出一个请求Request,得到一个响应后的内容HttpResponse,也就是说,每一个请求都是先通过中间件中的process_request函数,这个函数返回None 或者HttpResponse 对象,如果返回前者,继续处理其他中间件,如果返回前者,继续处理其他中间件,如果返回一个HttpResponse,就处理终止,返回到网页上。

  中间件不用集成任何类(可以继承object),下面一个中间件大概的样子:

class CommonMiddleware(object):
def process_request(self, request):
return None def process_response(self, request, response):
return response

  还有process_view,process_exception和process_template_response函数。

  中间件顾名思义,是介于request 与 response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出。因为改变的是全局,所以需要谨慎实用,用不好会影响到性能。

Django中间层的定义

Middleware is a framework of hooks into Django’s request/response processing. 

It’s a light, low-level “plugin” system for globally altering Django’s input or output.

  如果你想修改请求,例如被传送到view中的HTTPRequest对象。或者你想修改view返回的HTTPResponse对象,这些都可以通过中间件来实现。

  可能你想在view执行之前做一些操作,这种情况就可以用middleware来实现。

2,自定义中间件的方法

  中间件一共有五个方法:

process_request(self, request)

process_view(self, request, callback, callback_args, callback_kwargs)

process_template_response()

process_exception(self, request, exception)

process_response(self, request, response)

  

2.1  Request 预处理函数:process_request(self, request)

  这个方法的调用时机在Django接收到request之后,但仍未解析URL以确定应当运行的视图函数。Django向它传入相应的Request对象,以便在方法中修改。

  如果返回None,Django将继续处理这个request,执行后续的中间件,然后调用相应的view。

  如果返回HttpResponse对象,Django将不再执行任何除了process_response以外的其他的中间件以及相应的view,Django将立即返回该HttpResponse。

2.2  View预处理函数:process_view(self, request, callback, callback_args, callback_kwargs)

  这个方法的调用时机在Django执行完request预处理函数并确定待执行的view(即callback参数)之后,但在view函数实际执行之前。

request:HttpRequest 对象。

callback:Django将调用的处理request的python函数. 这是实际的函数对象本身,
而不是字符串表述的函数名。 args:将传入view的位置参数列表,但不包括request参数(它通常是传入view的第一个参数)。 kwargs:将传入view的关键字参数字典。

  process_view() 应当返回None或 HttpResponse 对象。如果返回 None, Django将继续处理这个request ,执行后续的中间件, 然后调用相应的view。

如果返回 HttpResponse 对象,Django 将不再执行任何其它的中间件(不论种类)以及相应的view,Django将立即返回。

2.3  Template模板渲染函数:process_template_response()

  默认不执行,只有在视图函数的返回结果对象中有render方法才会执行,并把对象的render方法的返回值返回给用户(注意不返回视图函数的return的结果了,而是返回视图函数return值(对象)中render方法的结果)

2.4  Exception后处理函数:process_exception(self, request, exception)

  这个方法只有在request处理过程中出了问题并且view函数抛出了一个未捕获的异常才会被调用。这个钩子可以用来发送错误通知,将现场相关信息输出到日志文件,或者甚至尝试从错误中自动恢复。

 这个函数的参数除了一贯的request对象之外,还包括view函数抛出的实际的异常对象exception 。

  process_exception() 应当返回None或HttpResponse对象。如果返回None,Django将用框架内置的异常处理机制继续处理相应request。如果返回HttpResponse对象,Django将使用该response对象,而短路框架内置的异常处理机制。

2.5  Response 后处理函数:process_response(self, request, response)

  这个方法的调用时机在 Django 执行 view 函数并生成 response 之后。

  该处理器能修改response 的内容;一个常见的用途是内容压缩,如gzip所请求的HTML页面。

  这个方法的参数相当直观:request是request对象,而response则是从view中返回的response对象。

  process_response() 必须返回 HttpResponse 对象. 这个 response 对象可以是传入函数的那一个原始对象(通常已被修改),也可以是全新生成的。

3,  自定义中间件方法练习

3.1 自定义中间件方法应用1(关于process_request 和 process_response方法)

    当用户发起请求的时候会依次经过所有的中间件,这个时候的请求是process_request,最后到达views的函数中,views函数处理后,在依次穿过中间件,这个时候是process_response,最后返回给请求者。

  上述截图中的中间件都是django中的,我们也可以自己定义一个中间件,我们可以自己写一个类,但是必须继承MiddlewareMixin。

(为什么必须继承MiddlewareMinxin?  当时是因为我们之前查看settings里面的中间件的情形,他们也是这样定义的。既然都是中间件,我们就需要按照人家的语法来写)

需要导入:

from django.utils.deprecation import MiddlewareMixin

  

在 views 中:

def index(request):

    print("view函数...")
return HttpResponse("OK")

  

在Mymiddlewares.py 中:

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse class Md1(MiddlewareMixin): def process_request(self,request):
print("Md1请求") def process_response(self,request,response):
print("Md1返回")
return response class Md2(MiddlewareMixin): def process_request(self,request):
print("Md2请求")
#return HttpResponse("Md2中断")
def process_response(self,request,response):
print("Md2返回")
return response

  

结果:

Md1请求
Md2请求
view函数...
Md2返回
Md1返回

  注意:如果当请求到达请求2的时候直接不符合条件返回,即return HTTPResponse(“Md2中断”),程序将请求直接发给中间件2 返回,然后依次返回到请求者,结果如下:

  返回Md2 中断的页面,后台打印如下:

Md1请求
Md2请求
Md2返回
Md1返回

  流程图如下:

3.2 自定义中间件方法应用2(关于process_view 方法)

  Mymiddlewares.py 修改如下:

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse class Md1(MiddlewareMixin): def process_request(self,request):
print("Md1请求")
#return HttpResponse("Md1中断")
def process_response(self,request,response):
print("Md1返回")
return response def process_view(self, request, callback, callback_args, callback_kwargs):
print("Md1view") class Md2(MiddlewareMixin): def process_request(self,request):
print("Md2请求")
# return HttpResponse("Md2中断")
def process_response(self,request,response):
print("Md2返回")
return response def process_view(self, request, callback, callback_args, callback_kwargs):
print("Md2view")

  细心的话,会发现我们增加了 process_view 函数。

  views.py 视图函数不用改,还是这样:

def index(request):

    print("view函数...")
return HttpResponse("OK")

  我们运行程式,结果如下:

Md1请求
Md2请求
Md1view
Md2view
view函数...
Md2返回
Md1返回

  下面继续使用流程图分析上面过程:

  当最后一个中间的 process_request 到达路由关系映射之后,返回到中间件1的 process_view ,然后依次往下,到达 views 函数,最后通过 process_response 依次返回到达用户。

  那么这样做有什么意义?

  我们可以发现,process_view() 里面有很多的参数。

我们捋一遍过程。

  首先,执行中间件1的process_request,然后执行中间件2的 process_request:

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse class Md1(MiddlewareMixin): def process_request(self,request):
print("Md1请求") class Md2(MiddlewareMixin): def process_request(self,request):
print("Md2请求")

  然后去urls.py 去找到 index() 函数:

urlpatterns = [
path('index/', views.index),
]

  然后返回中间件1的process_view 和中间件2的 process_view,将拿到的 views.index 传到 callback,去执行process_view()。

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse class Md1(MiddlewareMixin): def process_view(self, request, callback, callback_args, callback_kwargs):
print("Md1view") class Md2(MiddlewareMixin): def process_view(self, request, callback, callback_args, callback_kwargs):
print("Md2view")

  我们也可以尝试打印 callback这个视图函数,可以看到其结果如下:

callback =============>

<function  index at 0x103338bf8>

  而process_view中 callback_args 和 claaback_kwargs 是视图函数的参数。

  当执行完process_view的时候,就去视图函数执行其函数,然后执行 process_response。

  注意:process_view函数可以用来调用视图函数,我们调用如下:

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse class Md1(MiddlewareMixin): def process_request(self,request):
print("Md1请求") def process_response(self,request,response):
print("Md1返回")
return response def process_view(self, request, callback, callback_args, callback_kwargs):
print("Md1 view") class Md2(MiddlewareMixin): def process_request(self,request):
print("Md2请求") def process_response(self,request,response):
print("Md2返回")
return response def process_view(self, request, callback, callback_args, callback_kwargs):
print("Md2 view")
return HttpResponse("123")

  结果如下:

Md1请求
Md2请求
Md1 views
Md2 views
Md2返回
Md1返回

  但是请注意,页面返回的是  ‘123’, 而不是我们视图函数里面的 “OK”(为了怕大家混淆,我这里将index的视图函数贴上)。

def index(request):

    return HttpResponse("OK")

  如果要返回 OK 的话,怎么做呢?我们修改代码如下:

class Md1(MiddlewareMixin):

    def process_request(self,request):
print("Md1请求")
#return HttpResponse("Md1中断")
def process_response(self,request,response):
print("Md1返回")
return response def process_view(self, request, callback, callback_args, callback_kwargs): # return HttpResponse("hello") response=callback(request,*callback_args,**callback_kwargs)
return response

  结果如下:

Md1请求
Md2请求
view函数...
Md2返回
Md1返回

  注意:process_view 如果有返回值,会越过其他的 process_view 以及视图函数,但是所有的 process_response都还会执行。

3.3 自定义中间件方法应用3(关于process_exception 方法)

  Mymiddlewares.py 修改如下:

class Md1(MiddlewareMixin):

    def process_request(self,request):
print("Md1请求") def process_response(self,request,response):
print("Md1返回")
return response def process_view(self, request, callback, callback_args, callback_kwargs): # return HttpResponse("hello") # response=callback(request,*callback_args,**callback_kwargs)
# return response
print("md1 process_view...") def process_exception(self, request, exception):
print("md1 process_exception...") class Md2(MiddlewareMixin): def process_request(self,request):
print("Md2请求") def process_response(self,request,response):
print("Md2返回")
return response def process_view(self, request, callback, callback_args, callback_kwargs):
print("md2 process_view...") def process_exception(self, request, exception):
print("md2 process_exception...")

  结果如下:

Md1请求
Md2请求
md1 process_view...
md2 process_view...
view函数...
Md2返回
Md1返回

  当没有问题(异常)的时候,我们发现,和正常的执行没有任何区别。

  当views出错的时候, process_exception才会执行,我们看报错后的执行流程,如下:

  下面我们来模拟一个错误,执行看流程:

我们给views.py 里面加一个简单的错误,代码如下:

def index(request):
print("index doing")
james
return HttpResponse("index OK")

  我们执行程式,发现其执行流程如下:

Md1请求
Md2请求
md1 process_view...
md2 process_view...
view函数...
md2 process_exception...
md1 process_exception... Traceback (most recent call last):
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python37\lib\site-packages\django\core\handlers\exception.py", line 34,
in inner
response = get_response(request)
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python37\lib\site-packages\django\core\handlers\base.py", line 126, in _
get_response
response = self.process_exception_by_middleware(e, request)
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python37\lib\site-packages\django\core\handlers\base.py", line 124, in _
get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "E:\backup\pycode\web开发\User_model\users\views.py", line 7, in index
james
NameError: name 'james' is not defined Md2返回
Md1返回

  并且前端调用如下(当然这是Django自带默认的错误报错程式):

  我们也可以自己设定报错,我们将Mymiddlewares.py 修改如下:

class Md1(MiddlewareMixin):

    def process_request(self,request):
print("Md1请求") def process_response(self,request,response):
print("Md1返回")
return response def process_view(self, request, callback, callback_args, callback_kwargs): # return HttpResponse("hello") # response=callback(request,*callback_args,**callback_kwargs)
# return response
print("md1 process_view...") def process_exception(self, request, exception):
print("md1 process_exception...") class Md2(MiddlewareMixin): def process_request(self,request):
print("Md2请求") def process_response(self,request,response):
print("Md2返回")
return response def process_view(self, request, callback, callback_args, callback_kwargs):
print("md2 process_view...") def process_exception(self, request, exception):
print("md2 process_exception...")
return HttpResponse(exception)

  我们再执行程式,会发现前台是这样的:

  后台是这样的:

Md1请求
Md2请求
md1 process_view...
md2 process_view...
view函数...
md2 process_exception...
Md2返回
Md1返回

  我们发现在执行中间件2的process_exception后,不会去执行中间件1 了。因为中间件2将错误处理完之后,直接去执行response了。

4,中间件应用场景

  由于中间件工作在视图函数执行前,执行后。所以适合所有的请求/一部分请求做批量处理

1,做IP访问频率限制

  放在中间件类的列表中,阻止某些IP访问了。

  因为某些IP访问服务器的频率过高,所以进行拦截,比如限制每分钟不能超过20次。

2,缓存

  客户端请求来了,中间件去缓存看看有没有数据,有直接返回给用户,没有再去逻辑层,执行视图函数。

3,URL访问过滤

  如果用户访问的是login视图

  如果访问的是其他视图(需要检测是不是由session已经有了放行,没有返回login),这样就省的在多个视图函数上写装饰器了!

  那么如何写呢?如下:

Django通过中间件实现登录验证DEMO

  前提:中间件版的登录验证需要依靠session,所以数据库中要有django_session表。

urls.py代码:

from django.conf.urls import url
from django.contrib import admin
from app01 import views urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^login/$', views.login, name='login'),
url(r'^index/$', views.index, name='index'),
url(r'^home/$', views.home, name='home'),
]

  

views.py代码:

from django.shortcuts import render, HttpResponse, redirect

def index(request):
return HttpResponse("this is index") def home(request):
return HttpResponse("this is home") def login(request):
if request.method == 'POST':
user = request.POST.get("user")
pwd = request.POST.get("pwd") if user == 'james' and pwd == '123':
# 设置session
request.session['user'] = user
# 获取跳到登录页面之前的URL
next_url = request.GET.get('next')
# 如果有,就跳转到登录之前的URL
if next_url:
return redirect(next_url)
# 否则默认跳转到index页面
else:
return redirect('/index/')
return render(request, 'login.html')

  

login.html页面代码:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录页面</title>
</head>
<body>
<form action="{% url 'login' %}" method="post">
{% csrf_token %}
<p>
<label for="user">用户名:</label>
<input type="text" name="user" id="user">
</p>
<p>
<label for="pwd">密码:</label>
<input type="text" name="pwd" id="pwd">
</p>
<input type="submit" value="登录">
</form>
</body>
</html>

  

mymiddlewares.py 的代码:

# 自定义中间件
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import redirect, HttpResponse class AuthMD(MiddlewareMixin):
white_list = ['/login/', ] # 白名单
black_list = ['/black/', ] # 黑名单 def process_request(self, request):
next_url = request.path_info
print(request.path_info, request.get_full_path())
# 黑名单的网址限制访问
if next_url in self.black_list:
return HttpResponse("This is an illegal URL")
# 白名单的网址或者登录用户不做限制
elif next_url in self.white_list or request.session.get("user"):
return
else:
return redirect('/login/?next={}'.format(next_url))

  

settings.py 代码中添加内容如下:

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',
# 注意这个中间件是自己加的
'app01.mymiddleware.AuthMD',
]

  AuthMD 中间件注册后,所有的请求都要走AuthMD的process_request方法。如果URL在黑名单中,则返回This is an illegal  URL的字符串;访问的URL在白名单或者session中有user用户名,则不作阻拦走正常流程;正常的URL但是需要登录后访问,让浏览器跳转到登录页面。

  注意:AuthMD中间件中需要session,所以AuthMD注册的位置要在session中间的下方。

  如果黑名单的多,我们使用中间件简单,如果少,我们直接使用装饰器简单,就省去了写代码的麻烦,所以应用场景还是要看情况。

6,跨站请求伪造

1,简介

  django为用户实现防止跨站请求伪造的功能,通过中间件

django.middleware.csrf.CsrfViewMiddleware 来完成。而对于django中设置防跨站请求伪造功能有分为全局和局部。

全局:

  中间件 django.middleware.csrf.CsrfViewMiddleware

局部:

  • @csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
  • @csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。

注:from django.views.decorators.csrf import csrf_exempt,csrf_protect

2,方式

  方式1:

$.ajaxSetup({
data: {csrfmiddlewaretoken: '{{ csrf_token }}' },
});

  方式2:

<form>
{% csrf_token %}
</form> $.ajax({
data:{
"csrfmiddlewaretoken":$("[name='csrfmiddlewaretoken']").val();
}})

  方法3:

<script src="{% static 'js/jquery.cookie.js' %}"></script>

$.ajax({

    headers:{"X-CSRFToken":$.cookie('csrftoken')},

})

  

3,应用

普通表单

veiw中设置返回值:
  return render_to_response('Account/Login.html',data,context_instance=RequestContext(request))  
或者
return render(request, 'xxx.html', data) html中设置Token:
  {% csrf_token %}

  

ajax

  对于传统的form,可以通过表单的方式将token再次发送到服务端,而对于ajax的话,使用如下方式:

views.py

from django.template.context import RequestContext
# Create your views here. def test(request): if request.method == 'POST':
print request.POST
return HttpResponse('ok')
return render_to_response('app01/test.html',context_instance=RequestContext(request))

  

text.html

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
{% csrf_token %} <input type="button" onclick="Do();" value="Do it"/> <script src="/static/plugin/jquery/jquery-1.8.0.js"></script>
<script src="/static/plugin/jquery/jquery.cookie.js"></script>
<script type="text/javascript">
var csrftoken = $.cookie('csrftoken'); function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
function Do(){ $.ajax({
url:"/app01/test/",
data:{id:1},
type:'POST',
success:function(data){
console.log(data);
}
}); }
</script>
</body>
</html>

  

更多:https://docs.djangoproject.com/en/dev/ref/csrf/#ajax

https://www.cnblogs.com/huchong/p/7819296.html

https://www.cnblogs.com/yuanchenqi/articles/9036479.html

(自己的学习笔记,不喜勿喷,谢谢)

Django学习笔记(15)——中间件的更多相关文章

  1. Django学习笔记(13)——Django的用户认证(Auth)组件,视图层和QuerySet API

    用户认证组件的学习 用户认证是通过取表单数据根数据库对应表存储的值做比对,比对成功就返回一个页面,不成功就重定向到登录页面.我们自己写的话当然也是可以的,只不过多写了几个视图,冗余代码多,当然我们也可 ...

  2. Django 学习笔记(七)数据库基本操作(增查改删)

    一.前期准备工作,创建数据库以及数据表,详情点击<Django 学习笔记(六)MySQL配置> 1.创建一个项目 2.创建一个应用 3.更改settings.py 4.更改models.p ...

  3. Django学习笔记(9)—— 开发用户注册与登录系统

    一,项目题目: 开发用户注册与登录系统 该项目主要练习使用Django开发一个用户注册与登录的系统,通过这个项目然后巩固自己这段时间所学习的Django知识. 二,项目需求: 开发一个简单的用户登录与 ...

  4. Django学习笔记(4)——Django连接数据库

    前言 在MVC或者MTV设计模式中,模型(M)代表对数据库的操作.那么如何操作数据库呢?本小节就认真学习一下.首先复习一下Django的整个实现流程 ,然后再实现一下使用数据库的整个流程,最后学习一下 ...

  5. Django学习笔记(一):环境安装与简单实例

    Django学习笔记(一):环境安装与简单实例 通过本文章实现: Django在Windows中的环境安装 Django项目的建立并编写简单的网页,显示欢迎语与当前时间 一.环境安装 结合版本兼容性等 ...

  6. Django学习笔记(14)——AJAX与Form组件知识补充(局部钩子和全局钩子详解)

    我在之前做了一个关于AJAX和form组件的笔记,可以参考:Django学习笔记(8)——前后台数据交互实战(AJAX):Django学习笔记(6)——Form表单 我觉得自己在写Django笔记(8 ...

  7. Django学习笔记(11)——开发图书管理页面

    一,项目题目: 开发图书管理页面 该项目主要练习Django对多个数据库进行增删改查的操作. 二,项目需求: 基础需求:75% 1. 列出图书列表.出版社列表.作者列表 2. 点击作者,会列出其出版的 ...

  8. Django 学习笔记1-- URLconf

    今天好像巴黎有点乱,希望明天太阳还会照常升起. 简介 Django 是一个由 Python 编写.开源并采用经典的 MVC 设计模式的 Web Full Stack 应用框架. 在 Django 中, ...

  9. (学习笔记)laravel 中间件

    (学习笔记)laravel 中间件 laravel的请求在进入逻辑处理之前会通过http中间件进行处理. 也就是说http请求的逻辑是这样的: 建立中间件 首先,通过Artisan命令建立一个中间件. ...

  10. Django 学习笔记之四 QuerySet常用方法

    QuerySet是一个可遍历结构,它本质上是一个给定的模型的对象列表,是有序的. 1.建立模型: 2.数据文件(test.txt) 3.文件数据入库(默认的sqlite3) 入库之前执行 数据库同步命 ...

随机推荐

  1. 【CF704D】Captain America(上下界网络流)

    [CF704D]Captain America(上下界网络流) 题面 CF 洛谷 题解 如果没有限制,似乎就不用做了...因为我们只需要贪心的选择代价较小的颜色就行了. 那么我们不妨假设染红色的代价较 ...

  2. ABP开发框架前后端开发系列---(6)ABP基础接口处理和省份城市行政区管理模块的开发

    最近没有更新ABP框架的相关文章,一直在研究和封装相关的接口,总算告一段落,开始继续整理下开发心得.上次我在随笔<ABP开发框架前后端开发系列---(5)Web API调用类在Winform项目 ...

  3. 2018-8-10-win10-uwp-重启软件

    原文:2018-8-10-win10-uwp-重启软件 title author date CreateTime categories win10 uwp 重启软件 lindexi 2018-08-1 ...

  4. 学习Python前言

    先介绍下自己: 我是小芒果,在一家互联网公司上班 目前担任的是测试工程师职 自工作开始至今,已经3年之载 一路过来倒也轻松 期间学过几次python没一次能坚持下来 随着行业的饱和 测试技术的要求 以 ...

  5. Taro聊天室|react+taro仿微信聊天App界面|taro聊天实例

    一.项目简述 taro-chatroom是基于Taro多端实例聊天项目,运用Taro+react+react-redux+taroPop+react-native等技术开发的仿微信App界面聊天室,实 ...

  6. 定时器每隔10秒钟刷新一次jqgrid

    //console.log('每隔*秒钟刷新一次'); var timer = window.setInterval(function() { $("#table_list_1") ...

  7. 真机调试(A valid provisioning profile for this executable was not found.)

    这个问题是因为provisioning的问题,因为真机没有加入到账号下面的原因 解决步骤 1.吧identifier复制然后再平开开发中心 2.点击+号添加设备保存 3.在develope中选中保存即 ...

  8. 一文解读AI芯片之间的战争 (转)

    2015年的秋天,北京的雨水比往年要多些,温度却不算太冷.这一年里,年仅23岁的姚颂刚刚拿到清华大学的毕业证书;32岁的陈天石博士毕业后已在中科院计算所待了整整8年;而在芯片界摸爬滚打了14年的老将何 ...

  9. 我认为现代IDE编辑器应该具有的几个特性和Visual studio 2010增强

    工作中要使用 VS 2010, 有好多年没有使用Visual studio 了, 试了一小会, 发现VS 2010 缺少不少现代IDE应有的特性, 我认为重要的是下面几个特性, VS2010 已经是1 ...

  10. Python—函数基础篇

    https://www.cnblogs.com/littlefivebolg/p/9017449.html Python 解释器的内置函数 内置函数 作用 实例 abs() 返回数字的绝对值. abs ...