一、FORM

1、概述

django表单系统中,所有的表单类都作为django.forms.Form的子类创建,包括ModelForm

关于django的表单系统,主要分两种

  基于django.forms.Form: 所有表单类的父类
  基于django.forms.ModelForm: 可以和模型类绑定的Form
 

django中的Form一般有两种功能:

  • 输入html
  • 验证用户输入

1、forms.Form

from django.conf.urls import url
from hello import views urlpatterns = [
url(r'^add_publisher/$', views.add_publisher, name='add_publisher'),
]

urls.py

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>添加出版社信息</title>
</head>
<body>
<form action="{% url 'add_publisher' %}" method="post">
{% csrf_token %}
{{ publisher_form.as_p }}
<input type="submit" value="提交"><br>
</form>
</body>
</html>

add_publisher.html

from django.db import models

class Publisher(models.Model):
name = models.CharField(max_length=30, verbose_name="名称")
address = models.CharField("地址", max_length=50)
city = models.CharField("城市", max_length=60)
state_province = models.CharField("省份", max_length=30)
country = models.CharField("国家", max_length=50)
website = models.URLField("网址")

models

from django import forms
from hello.models import Publisher class PublisherForm(forms.Form):
name = forms.CharField(label="名称", error_messages={"required": "这个项必须填写"})
address = forms.CharField(label="地址", error_messages={"required": "这个项必须填写"})
city = forms.CharField(label="城市", error_messages={"required": "这个项必须填写"})
state_province = forms.CharField(label="省份", error_messages={"required": "这个项必须填写"})
country = forms.CharField(label="国家", error_messages={"required": "这个项必须填写"})
website = forms.URLField(label="网址", error_messages={"required": "这个项必须填写"})

forms.py

from django.shortcuts import render, render_to_response, redirect,HttpResponse
from hello.models import Publisher
from hello.forms import PublisherForm def add_publisher(request):
if request.method == "POST":
publisher_form = PublisherForm(request.POST) if publisher_form.is_valid():
Publisher.objects.create(
name = publisher_form.cleaned_data['name'],
address = publisher_form.cleaned_data['address'],
city = publisher_form.cleaned_data['city'],
state_province = publisher_form.cleaned_data['state_province'],
country = publisher_form.cleaned_data['country'],
website = publisher_form.cleaned_data['website'],
)
return HttpResponse("添加出版社信息成功!")
else:
publisher_form = PublisherForm()
return render(request, 'add_publisher.html', locals())

views.py

2、forms.ModelForm

from django import forms
from hello.models import Publisher class PublisherForm(forms.ModelForm): class Meta:
model = Publisher # 把models中的Publisher类绑定过来
exclude = ("id",) # 指定不要显示的字段,fields是指定要显示的字段

forms.py

from django.shortcuts import render, render_to_response, redirect,HttpResponse
from hello.models import Publisher
from hello.forms import PublisherForm def add_publisher(request):
if request.method == "POST":
publisher_form = PublisherForm(request.POST)
if publisher_form.is_valid():
publisher_form.save() # 这里这一句就把前端传过来的值全部写入数据库中了
return HttpResponse("添加出版社信息成功!")
else:
publisher_form = PublisherForm()
return render(request, 'add_publisher.html', locals())

views.py

其他配置和上面一样

3、Django验证表单

(1)表单字段的验证器validators
from django import forms
from hello.models import Publisher
from django.core.exceptions import ValidationError def validate_name(value):
try:
Publisher.objects.get(name=value)
raise ValidationError("%s的信息已经存在" %value)
except Publisher.DoesNotExist:
pass class PublisherForm(forms.ModelForm): name = forms.CharField(label="名称", validators=[validate_name,]) #validate_name是上面定义的 class Meta:
model = Publisher
exclude = ("id",)

(2)clean_filedname,验证字段,针对某个字段进行验证

from django import forms
from hello.models import Publisher class PublisherForm(forms.ModelForm): def clean_name(self):
value = self.cleaned_data.get('name')
try:
Publisher.objects.get(name=value)
raise ValidationError("%s的信息已经存在" % value)
except Publisher.DoesNotExist:
pass
return value class Meta:
model = Publisher
exclude = ("id",)

(3)表单clean方法,可针对整个表单进行验证

from django import forms
from hello.models import Publisher class PublisherForm(forms.ModelForm): def clean(self):
cleaned_data = super(PublisherForm, self).clean()
value = cleaned_data.get('name')
try:
Publisher.objects.get(name=value)
self._errors['name']=self.error_class(["%s的信息已经存在" % value])
except Publisher.DoesNotExist:
pass
return cleaned_data class Meta:
model = Publisher
exclude = ("id",)

(4)一个常用的验证器validators

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import re
from django import forms
from django.core.exceptions import ValidationError def mobile_validate(value):
mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
if not mobile_re.match(value):
raise ValidationError('手机号码格式错误') class PublishForm(forms.Form): user_type_choice = (
(0, '普通用户'),
(1, '高级用户'),
) user_type = forms.IntegerField(widget=forms.widgets.Select(choices=user_type_choice,
attrs={'class': "form-control"})) title = forms.CharField(max_length=20,
min_length=5,
error_messages={'required': '标题不能为空',
'min_length': '标题最少为5个字符',
'max_length': '标题最多为20个字符'},
widget=forms.TextInput(attrs={'class': "form-control",
'placeholder': '标题5-20个字符'})) memo = forms.CharField(required=False,
max_length=256,
widget=forms.widgets.Textarea(attrs={'class': "form-control no-radius", 'placeholder': '详细描述', 'rows': 3})) phone = forms.CharField(validators=[mobile_validate, ],
error_messages={'required': '手机不能为空'},
widget=forms.TextInput(attrs={'class': "form-control",
'placeholder': '手机号码'})) email = forms.EmailField(required=False,
error_messages={'required': '邮箱不能为空','invalid': '邮箱格式错误'},
widget=forms.TextInput(attrs={'class': "form-control", 'placeholder': '邮箱'}))

forms.py

def publish(request):
ret = {'status': False, 'data': '', 'error': '', 'summary': ''}
if request.method == 'POST':
request_form = PublishForm(request.POST)
if request_form.is_valid():
request_dict = request_form.clean()
print request_dict
ret['status'] = True
else:
error_msg = request_form.errors.as_json()
ret['error'] = json.loads(error_msg)
return HttpResponse(json.dumps(ret))

views.py

更多验证器官网:

4、例子

(1)Ajax提交form验证

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

urls.py

#!/usr/bin/env python
# -*- coding:utf-8 -*- from django import forms class LoginForm(forms.Form):
# 这个字段username要和html中input标签的name的属性值一样
username = forms.CharField(min_length=10,
required=True,
label='用户名',
error_messages={'required':'用户名必须填写',
'invalid':'格式不对',
'min_length':'最少10位字母'}) # 这个字段password要和html中input标签的name的属性值一样
password = forms.CharField(min_length=10,
max_length = 18,
required=True,
label='密码',
error_messages={'required':'这个选项必填',
'invalid':'格式不对',
'min_length':'最少10个字母',
'max_length': '最多18个字母',}) num = forms.IntegerField(min_value=10,
max_value=18,
label='数字',
error_messages={'required':'这个选项必填',
'invalid':'格式不对',
'min_value':'最小值10',
'max_value':'最大值18'}) email = forms.EmailField(label='邮箱',
error_messages={'required':'这个选项必填',
'invalid':'格式不对',}) url = forms.URLField(label='网址',
error_messages={'required':'这个选项必填',
'invalid':'格式不对',}) # 自定义标签和样式,上面的字段默认是forms.TextInput
test = forms.CharField(widget=forms.TextInput(attrs={'class':'c1','placeholder':'自定义输入框'})) # 备注
test1 = forms.CharField(widget=forms.Textarea(attrs={'class':'c1','placeholder':'自定义输入框'})) # 复选框(讲数据库时补充)
test_choice = (
(0,'上海'),
(1,'深圳'),
)
test2 = forms.IntegerField(widget=forms.Select(choices=test_choice))

forms.py

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>FORM验证(AJAX)</title>
<style>
.error-msg{
color:red;
}
</style>
</head>
<body>
<div>
<input type="text" name="username" placeholder="用户名">
</div>
<div>
<input type="password" name="password" placeholder="密码">
</div>
<div>
<input type="text" name="num" placeholder="数字">
</div>
<div>
<input type="email" name="email" placeholder="邮箱">
</div>
<div>
<input type="url" name="url" placeholder="网址">
</div>
<input type="button" value="提交" onclick="DoSubmit();"> <script src="/static/jquery-1.12.4.js"></script>
<script>
function DoSubmit() {
var input_dict = {};
$("div input").each(function () {
var v = $(this).val();
var k = $(this).attr('name'); input_dict[k] = v;
});
console.log(input_dict);
$('.error-msg').remove();
$.ajax({
url : '/login/',
type : 'POST',
data : input_dict,
dataType:'json',
success:function (result) {
console.log(result);
if(result.status){
location.href = '/index/'
}else{
$.each(result.message,function (k,v) {
console.log(v[0].message);
// <span class="error-msg">错误信息</span>
var tag = document.createElement('span');
tag.className = 'error-msg';
tag.innerText = v[0].message;
// input(name="username")
$('input[name="' + k + '"]').after(tag);
})
}
},
error:function () { }
});
} </script>
</body>
</html>

login.html

from django.shortcuts import render,HttpResponse,redirect
from myproject.forms import LoginForm,LoginForm1
import json def login(request):
if request.method == 'POST':
result = {'status':False,'message':None}
obj = LoginForm(request.POST)
ret = obj.is_valid()
if ret:
print(obj.clean())
result['status'] = True
else:
from django.forms.utils import ErrorDict
print(type(obj.errors),obj.errors.as_json())
error_dict = obj.errors.as_json()
result['message'] = json.loads(error_dict)
return HttpResponse(json.dumps(result)) return render(request,'login.html')

views.py

(2)form生成html并验证

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),
url(r'^login1/', views.login1),
url(r'^index/', views.index),
]

urls.py

#!/usr/bin/env python
# -*- coding:utf-8 -*- from django import forms class LoginForm1(forms.Form):
# 这个字段username要和html中input标签的name的属性值一样
username = forms.CharField(min_length=10,
required=True,
label='用户名',
error_messages={'required':'用户名必须填写',
'invalid':'格式不对',
'min_length':'最少10位字母'}) # 这个字段password要和html中input标签的name的属性值一样
password = forms.CharField(min_length=10,
max_length = 18,
required=True,
label='密码',
error_messages={'required':'这个选项必填',
'invalid':'格式不对',
'min_length':'最少10个字母',
'max_length': '最多18个字母',}) num = forms.IntegerField(min_value=10,
max_value=18,
label='数字',
error_messages={'required':'这个选项必填',
'invalid':'格式不对',
'min_value':'最小值10',
'max_value':'最大值18'}) email = forms.EmailField(label='邮箱',
error_messages={'required':'这个选项必填',
'invalid':'格式不对',}) url = forms.URLField(label='网址',
error_messages={'required':'这个选项必填',
'invalid':'格式不对',}) # 自定义标签和样式,上面的字段默认是forms.TextInput
test = forms.CharField(label='test',
error_messages={'required':'这个选项必填','invalid':'格式不对',},
widget=forms.TextInput(attrs={'class':'c1','placeholder':'自定义输入框'})) # 备注
test1 = forms.CharField(label='test1',
error_messages={'required':'这个选项必填','invalid':'格式不对',},
widget=forms.Textarea(attrs={'class':'c1','placeholder':'自定义输入框'})) # 复选框(讲数据库时补充)
test_choice = (
(0,'上海'),
(1,'深圳'),
)
test2 = forms.IntegerField(widget=forms.Select(choices=test_choice))

forms.py

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>FORM验证并生成HTML</title>
<style>
.error-msg{
color:red;
}
</style>
</head>
<body>
<form action="/login1/" method="post">
<div>
{{ obj1.username }}
{% if obj1.errors.username %}
<span class="error-msg">{{ obj1.errors.username.0 }}</span>
{% endif %}
</div>
<div>
{{ obj1.password }}
{% if obj1.errors.password %}
<span class="error-msg">{{ obj1.errors.password.0 }}</span>
{% endif %}
</div>
<div>
{{ obj1.num }}
{% if obj1.errors.num %}
<span class="error-msg">{{ obj1.errors.num.0 }}</span>
{% endif %}
</div>
<div>
{{ obj1.email }}
{% if obj1.errors.email %}
<span class="error-msg">{{ obj1.errors.email.0 }}</span>
{% endif %}
</div>
<div>
{{ obj1.url }}
{% if obj1.errors.url %}
<span class="error-msg">{{ obj1.errors.url.0 }}</span>
{% endif %}
</div>
<div>
{{ obj1.test }}
{% if obj1.errors.test %}
<span class="error-msg">{{ obj1.errors.test.0 }}</span>
{% endif %}
</div>
<div>
{{ obj1.test1 }}
{% if obj1.errors.test1 %}
<span class="error-msg">{{ obj1.errors.test1.0 }}</span>
{% endif %}
</div>
<div>
{{ obj1.test2 }}
{% if obj1.errors.test2 %}
<span class="error-msg">{{ obj1.errors.test2.0 }}</span>
{% endif %}
</div>
<input type="submit" value="提交"">
</form>
</body>
</html>

login1.html

from django.shortcuts import render,HttpResponse,redirect

from myproject.forms import LoginForm,LoginForm1
import json def login1(request):
if request.method == 'POST':
objPost = LoginForm1(request.POST)
ret = objPost.is_valid()
if ret:
print(objPost.clean()) else:
pass
return render(request, 'login1.html', {'obj1': objPost}) else:
objGet = LoginForm()
return render(request,'login1.html',{'obj1':objGet}) def index(request): return HttpResponse('ok')

views.py

forms.py中的choice如果是从数据库中取的数据:只要choice=models.类名.objects.all().values_list('id','name'),因为values_list返回的是元组列表,choice = [(1,'普通用户'),(2,'超级用户')]

但是这样choice还是第一次取的数据,如果增加了数据,则不会时时更新,重启可以解决,但是在生产环境是不现实的,so 还有一种方法:

class IndexForm(forms.Form):
#c = [
# (1,'CEO'),
# (2,'CTO')
#] c = models.UserType.objects.all().values_list('id','name')
user_type_id = forms.IntergetField(widget=forms.Select(choices=c)) def __init__(self,*args,**kwargs): # 在views中实例化时,执行构造方法,就会时时更新了
super(IndexForm,self).__init__(*args,**kwargs)
self.fields['user_type_id'].widget.choices = models.UserType.objects.all().values_list('id','name')

官网更多:https://docs.djangoproject.com/en/1.10/ref/forms/fields/

二、中间件

django 中的中间件(middleware),在django中,中间件其实就是一个类,在请求到来和结束后,django会根据自己的规则在合适的时机执行中间件中相应的方法。

在django项目的settings模块中,有一个 MIDDLEWARE_CLASSES 变量,其中每一个元素就是一个中间件,每一个中间件是一个类,类中不一定要写5个方法

MIDDLEWARE_CLASSES = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

中间件中可以定义五个方法,分别是:

  • process_request(self,request)
  • process_view(self, request, callback, callback_args, callback_kwargs)
  • process_template_response(self,request,response)
  • process_exception(self, request, exception)
  • process_response(self, request, response)   最后必须return response

以上方法的返回值可以是None和HttpResonse对象,如果是None,则继续按照django定义的规则向下执行,如果是HttpResonse对象,则直接将该对象返回给用户。

django 1.10以下版本,如果process_request方法中有return语句则后面的所有request都不执行,所有的process_response都会执行,在django 1.10中有return则后面的

所有rerquest方法都不会执行,response只会这个request所属的这个的response才会执行,其他的response不会执行

请求先通过中间件执行所有的process_request方法,然后再执行process_view方法,然后执行views中的方法,

如果views中的方法包含render_to_response()方法则会执行process_template_response方法,如果views中的

方法执行错误了,则会执行process_exception方法,最后执行process_response方法。

自定义中间件

1、创建中间件类

class defindemiddleware:

    def process_request(self,request):
print(123)
def process_view(self, request, callback, callback_args, callback_kwargs):
print(456)
def process_exception(self, request, exception):
print(error)
def process_response(self, request, response):
print(end)
return response

2、注册中间件

MIDDLEWARE_CLASSES = (
'my.middleware.defindedmiddleware', # 目录结构my/middleware/类名
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
)

django 1.10中有点不一样,创建时需要继承父类:

from django.utils import deprecation

class defindemiddleware(deprecation.MiddlewareMixin):

    def process_request(self,request):
print(123)

三、跨站请求伪造

一、简介

  django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware 来完成。而对于django中设置防跨站请求伪造功能有分为全局和局部。

django的csrf做了两件事:1.往form表单中写入了csrf_token(普通表单post时用的是这里的token) 2.往cookie中也写入了csrf_token(Ajax post提交时用的是这里的token)

全局

  中间件 django.middleware.csrf.CsrfViewMiddleware

局部

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

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

二、应用

1、普通表单

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

2、Ajax

对于传统的form,可以通过表单的方式将token再次发送到服务端,而对于ajax的话,使用如下方式。需要下载导入jquery.cookie.js

from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^csrf/', views.csrf),
]

urls.py

from django.shortcuts import render,HttpResponse,redirect

def csrf(request):

    return render(request,'csrf.html')
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>csrf跨站请求伪造</title>
</head>
<body>
<form action="/csrf/" method="post">
{% csrf_token %}
<input type="text" name="v"/>
<input type="submit" value="提交">
</form> <input type="button" value="Ajax提交" onclick="DoAjax();"/> <script src="/static/jquery-1.12.4.js"></script>
<script src="/static/jquery.cookie.js"></script>
<script>
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 DoAjax() {
$.ajax({
url:'/csrf/',
type: 'post',
data:{'k1':'va'},
sucess:function (data) {
console.log(data);
}
});
}
</script>
</body>
</html>

csrf.html

官网:https://docs.djangoproject.com/en/1.9/ref/csrf/#ajax

四、Cookie

  Cookie,有时也用其复数形式Cookies,指某些网站为了辨别用户身份、进行session跟踪而储存在用户本地终端上的数据(通常经过加密),(可以叫做浏览器缓存),http是无状态的,通常cookie配合session进行状态的跟踪,cookie是存在客户端,session是存在服务器,sessionid是存在cookie中的键值对,所以session是依赖cookie的,django中的cookie默认是保存2周时间,用cookie可以做登录验证、多少周保持登录

1、获取Cookie:

request.COOKIES['key']
request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
参数:
default: 默认值
salt: 加密盐
max_age: 后台控制过期时间

2、设置Cookie:

rep = HttpResponse(...) 或 rep = render(request, ...)

rep.set_cookie(key,value,...)
rep.set_signed_cookie(key,value,salt='加密盐',...)
参数:
key, 键
value='', 值
max_age=None, 超时时间
expires=None, 超时时间(IE requires expires, so set it if hasn't been already.)
path='/', Cookie生效的路径,/ 表示根路径,特殊的:跟路径的cookie可以被任何url的页面访问
domain=None, Cookie生效的域名
secure=False, https传输
httponly=False 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)

由于cookie保存在客户端的电脑上,所以,JavaScript和jquery也可以操作cookie。

<script src='/static/js/jquery.cookie.js'></script>
$.cookie("list_pager_num", 30,{ path: '/' });

用户登录验证

urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^index/', views.index),
url(r'^log/', views.log),
]

urls.py

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<form action="/log/" method="POST">
<input type="text" name="user">
<input type="text" name="pwd">
<input type="submit" value="提交" />
</form>
</body>
</html>

log.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>欢迎:{{ user }}登录</h1>
</body>
</html>

index.html

from django.shortcuts import render,HttpResponse,redirect
from django import forms def log(request):
if request.method == 'POST':
u = request.POST.get('user')
p = request.POST.get('pwd')
if u == 'tom' and p == '':
print(u)
red = redirect('/index/')
red.set_cookie('username', u)
return red
else:
return render(request, 'log.html')
else:
return render(request, 'log.html') def index(request):
user = request.COOKIES.get('username')
if user:
return render(request, 'index.html', {'user':user})
else:
return redirect('/log/')

views.py

五、Session

  Session在计算机中,尤其是在网络应用中,称为“会话控制”。Session 对象存储特定用户会话所需的属性及配置信息。这样,当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。当用户请求来自应用程序的 Web 页时,如果该用户还没有会话,则 Web 服务器将自动创建一个 Session 对象。当会话过期或被放弃后,服务器将终止该会话。Session 对象最常见的一个用法就是存储用户的首选项。例如,如果用户指明不喜欢查看图形,就可以将该信息存储在 Session 对象中。会话状态仅在支持 cookie 的浏览器中保留。

Django中默认支持Session,其内部提供了5种类型的Session供开发者使用:

  • 数据库(默认)
  • 缓存
  • 文件
  • 缓存+数据库
  • 加密cookie

1、数据库Session

Django默认支持Session,并且默认是将Session数据存储在数据库中,即:django_session 表中。

a. 配置 settings.py

    SESSION_ENGINE = 'django.contrib.sessions.backends.db'   # 引擎(默认)

    SESSION_COOKIE_NAME = "sessionid"                       # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径(默认)
SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认)
SESSION_COOKIE_SECURE = False # 是否Https传输cookie(默认)
SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认)
SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默认)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期(默认)
SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存(默认) b. 使用 def index(request):
# 获取、设置、删除Session中数据
request.session['k1']
request.session.get('k1',None)
request.session['k1'] = 123
request.session.setdefault('k1',123) # 存在则不设置
del request.session['k1'] # 所有 键、值、键值对
request.session.keys()
request.session.values()
request.session.items()
request.session.iterkeys()
request.session.itervalues()
request.session.iteritems() # 用户session的随机字符串
request.session.session_key # 将所有Session失效日期小于当前日期的数据删除
request.session.clear_expired() # 检查 用户session的随机字符串 在数据库中是否
request.session.exists("session_key") # 删除当前用户的所有Session数据
request.session.delete("session_key") ...

2、缓存Session

a. 配置 settings.py

    SESSION_ENGINE = 'django.contrib.sessions.backends.cache'  # 引擎
SESSION_CACHE_ALIAS = 'default' # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置 SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串
SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径
SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名
SESSION_COOKIE_SECURE = False # 是否Https传输cookie
SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输
SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期
SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存 b. 使用 同上

3、文件Session

a. 配置 settings.py

    SESSION_ENGINE = 'django.contrib.sessions.backends.file'    # 引擎
SESSION_FILE_PATH = None # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir() # 如:/var/folders/d3/j9tj0gz93dg06bmwxmhh6_xm0000gn/T SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串
SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径
SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名
SESSION_COOKIE_SECURE = False # 是否Https传输cookie
SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输
SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期
SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存 b. 使用 同上

4、缓存+数据库Session

数据库用于做持久化,缓存用于提高效率

a. 配置 settings.py

    SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'        # 引擎

b. 使用

    同上

5、加密cookie Session

a. 配置 settings.py

    SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'   # 引擎

b. 使用

    同上

 

实例:Session用户验证

from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^session_login/', views.session_login),
url(r'^session_index/', views.session_index),
url(r'^session_logout/', views.session_logout),
]

urls.py

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>session用户登录验证</title>
</head>
<body>
<form action="/session_login/" method="POST">
{% csrf_token %}
<input type="text" name="user">
<input type="text" name="pwd">
<input type="submit" value="提交" />
</form>
</body>
</html>

session_login.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>session用户登录验证</title>
</head>
<body>
<h1>欢迎:{{ username }}登录</h1> <a href="/session_logout/">注销</a>
</body>
</html>

session_index.html

def session_login(request):
if request.method == 'POST':
user = request.POST.get('user')
password = request.POST.get('pwd')
if password == '' and user in USER_LIST:
request.session['username'] = user
return redirect('/session_index/')
return render(request,'session_login.html') """
# 未使用装饰器
def session_index(request):
user = request.session.get('user',None)
if not user:
return redirect('/session_login/')
else:
return render(request,'session_index.html',{'user': user})
""" def auth(func):
def inner(request,*args,**kwargs): user = request.session.get('username',None)
if not user:
return redirect('/session_login/')
return func(request,*args,**kwargs) return inner @auth
def session_index(request):
user = request.session.get('username',None)
return render(request,'session_index.html',{'username':user}) @auth
def session_logout(request):
del request.session['username']
return redirect('/session_login/')

设置session过程request.session['username'] = user 在session中设置属性的时候,django做了两件事:

1.往客户端的cookie中写入了sessionid和随机字符串

2.默认在数据库django_session中插入session_key,session_data,expire_date

更多参考:

https://docs.djangoproject.com/en/1.9/topics/http/sessions/

https://docs.djangoproject.com/en/1.9/ref/settings/#settings-sessions 

六、分页

一、Django内置分页

Paginator

更多django分页:

https://docs.djangoproject.com/en/1.9/topics/pagination/

二、自定义分页

分页功能在每个网站都是必要的,对于分页来说,其实就是根据用户的输入计算出应该在数据库表中的起始位置。

1、设定每页显示数据条数

2、用户输入页码(第一页、第二页...)

3、根据设定的每页显示条数和当前页码,计算出需要取数据表的起始位置

4、在数据表中根据起始位置取值,页面上输出数据


需求又来了,需要在页面上显示分页的页面。如:[上一页][1][2][3][4][5][下一页]

1、设定每页显示数据条数

2、用户输入页码(第一页、第二页...)

3、设定显示多少页号

4、获取当前数据总条数

5、根据设定显示多少页号和数据总条数计算出,总页数

6、根据设定的每页显示条数和当前页码,计算出需要取数据表的起始位置

7、在数据表中根据起始位置取值,页面上输出数据

8、输出分页html,如:[上一页][1][2][3][4][5][下一页]

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.pager a{
display: inline-block;
padding:5px;
background-color: cadetblue;
margin: 2px;
}
.pager a.active{
background-color: chartreuse;
}
</style>
</head>
<body>
<table border="1"> <tr>
<th>主机名</th>
<th>IP</th>
</tr>
{% for i in data %}
<tr>
<td>{{ i.hostname }}</td>
<td>{{ i.ip}}</td>
</tr>
{% endfor %}
</table>
<div>
总共:{{ count }}页
</div>
<div class="pager">
{{ page }}
</div>
</body>
</html>

page.html

from django.conf.urls import url,include
from django.contrib import admin
from app02.views import * urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^page/', page),
]

urls.py

from django.shortcuts import render,render_to_response,redirect
from django.utils.safestring import mark_safe
from app02 import models def try_int(arg,default): try:
arg = int(arg)
except Exception:
arg = default
return arg class PageInfo(): def __init__(self,current_page,all_count,per_item=10):
self.CurrentPage = current_page
self.AllCount = all_count
self.PerItem = per_item @property
def start(self):
return (self.CurrentPage-1)*self.PerItem @property
def end(self):
return self.CurrentPage*self.PerItem @property
def all_page_count(self):
temp = divmod(self.AllCount, self.PerItem)
if temp[1] == 0:
all_page_count = temp[0]
else:
all_page_count = temp[0] + 1
return all_page_count def Pager(page,all_page_count):
'''
page:当前页
all_page_count:所有页
'''
page_html = [] first_html = "<a href='/page?p=%d'>首页</a>" %(1,)
page_html.append(first_html) if page <= 1:
prv_html = "<a href='#'>上一页</a>"
else:
prv_html = "<a href='/page?p=%d'>上一页</a>" %(page-1,)
page_html.append(prv_html) begin = 0
end =0 if all_page_count <= 11:
begin = 0
end = all_page_count
else:
if page < 6:
begin = 0
end = 11
else:
if page + 6 > all_page_count:
begin = page - 6
end = all_page_count
if end > all_page_count:
end = all_page_count
else:
begin = page - 6
end = page + 6 for i in range(begin+1,end+1):
if page == i:
a_html = "<a class='active' href='/page?p=%d'>%d</a>" %(i,i)
#mark_safe让他转义为html
else:
a_html = "<a href='/page?p=%d'>%d</a>" %(i,i)
page_html.append(a_html) if page >= all_page_count:
next_html = "<a href='#'>下一页</a>"
else:
next_html = "<a href='/page?p=%d'>下一页</a>" %(page+1,)
page_html.append(next_html) end_html = "<a href='/page?p=%d'>尾页</a>" %(all_page_count,)
page_html.append(end_html) page_string = mark_safe(''.join(page_html)) return page_string def page(request):
page = request.GET.get('p',1)
page = try_int(page, 1)
count = models.HostInfo.objects.all().count() pageObj = PageInfo(page,count)
result = models.HostInfo.objects.all()[pageObj.start:pageObj.end] page_string = Pager(page, pageObj.all_page_count)
ret = {'data':result,'count':count,'page':page_string}
return render_to_response('page.html',ret)

分页views.py

from django.db import models

# Create your models here.

class HostInfo(models.Model):

    hostname = models.CharField(max_length=50)
ip = models.GenericIPAddressField()

models.py

总结,分页时需要做三件事:

  • 创建处理分页数据的类
  • 根据分页数据获取数据
  • 输出分页HTML,即:[上一页][1][2][3][4][5][下一页]

七、缓存

由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存,缓存将一个某个views的返回值保存至内存或者memcache中,5分钟内再有人来访问时,则不再去执行view中的操作,而是直接从内存或者Redis中之前缓存的内容拿到,并返回。

1、Django中提供了6种缓存方式:

  • 开发调试
  • 内存
  • 文件
  • 数据库
  • Memcache缓存(python-memcached模块)
  • Memcache缓存(pylibmc模块)

a、开发调试

# 此为开始调试用,实际内部不做任何操作
# 配置:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.dummy.DummyCache', # 引擎
'TIMEOUT': 300, # 缓存超时时间(默认300,None表示永不过期,0表示立即过期)
'OPTIONS':{
'MAX_ENTRIES': 300, # 最大缓存个数(默认300)
'CULL_FREQUENCY': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
},
'KEY_PREFIX': '', # 缓存key的前缀(默认空)
'VERSION': 1, # 缓存key的版本(默认1)
'KEY_FUNCTION' 函数名 # 生成key的函数(默认函数会生成为:【前缀:版本:key】)
}
} # 自定义key
def default_key_func(key, key_prefix, version):
"""
Default function to generate keys. Constructs the key used by all other methods. By default it prepends
the `key_prefix'. KEY_FUNCTION can be used to specify an alternate
function with custom key making behavior.
"""
return '%s:%s:%s' % (key_prefix, version, key) def get_key_func(key_func):
"""
Function to decide which key function to use. Defaults to ``default_key_func``.
"""
if key_func is not None:
if callable(key_func):
return key_func
else:
return import_string(key_func)
return default_key_func

b、内存

# 此缓存将内容保存至内存的变量中
# 配置:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'LOCATION': 'unique-snowflake',
}
} # 注:其他配置同开发调试版本

c、文件

# 此缓存将内容保存至文件
# 配置: CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': '/var/tmp/django_cache',
}
}
# 注:其他配置同开发调试版本

d、数据库

# 此缓存将内容保存至数据库

# 配置:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
'LOCATION': 'my_cache_table', # 数据库表
}
} # 注:执行创建表命令 python manage.py createcachetable

e、Memcache缓存(python-memcached模块)

# 此缓存使用python-memcached模块连接memcache

    CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
}
} CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': 'unix:/tmp/memcached.sock',
}
} CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': [
'172.19.26.240:11211',
'172.19.26.242:11211',
]
}
}

f、Memcache缓存(pylibmc模块)

# 此缓存使用pylibmc模块连接memcache

    CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
'LOCATION': '127.0.0.1:11211',
}
} CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
'LOCATION': '/tmp/memcached.sock',
}
} CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
'LOCATION': [
'172.19.26.240:11211',
'172.19.26.242:11211',
]
}
}

2、应用

a. 全站使用

使用中间件,经过一系列的认证等操作,如果内容在缓存中存在,则使用FetchFromCacheMiddleware获取内容并返回给用户,当返回给用户之前,判断缓存中是否已经存在,如果不存在则UpdateCacheMiddleware会将缓存保存至缓存,从而实现全站缓存

    MIDDLEWARE = [
'django.middleware.cache.UpdateCacheMiddleware', # 必须写在第一个
# 其他中间件...
'django.middleware.cache.FetchFromCacheMiddleware', # 必须写在最后一个
] CACHE_MIDDLEWARE_ALIAS = ""
CACHE_MIDDLEWARE_SECONDS = ""
CACHE_MIDDLEWARE_KEY_PREFIX = ""

b. 单独视图缓存

方式一:
from django.views.decorators.cache import cache_page @cache_page(60 * 15)
def my_view(request):
... 方式二:
from django.views.decorators.cache import cache_page urlpatterns = [
url(r'^foo/([0-9]{1,2})/$', cache_page(60 * 15)(my_view)),
]

c、局部视图使用

a. 引入TemplateTag

    {% load cache %}

b. 使用缓存

    {% cache 5000 缓存key %}  # 5000秒
缓存内容
{% endcache %}
官网更多:
https://docs.djangoproject.com/en/1.9/topics/cache/

2、redis缓存需要第三方

Django-redis 文档:
  http://niwinz.github.io/django-redis/latest/
  http://django-redis-cache.readthedocs.org/en/latest/

Django-redis 缓存后端安装:

$ sudo apt-get install redis-server    # 安装Redis Server
$ . ~/myprojectenv/bin/active # Source 到虚拟环境
$ pip install django-redis-cache # 安装缓存后端

Django-redis 缓存后端配置:

CACHES = {
'default': {
'BACKEND': 'redis_cache.RedisCache',
'LOCATION': '127.0.0.1:6379',
'OPTIONS': {
'DB': 1,
'PASSWORD': 'yadayada',
'PARSER_CLASS': 'redis.connection.HiredisParser',
'CONNECTION_POOL_CLASS': 'redis.BlockingConnectionPool',
'PICKLE_VERSION': -1,
},
},
}
    (1)LOCATION:

    Redis 服务器信息,可以是 address/port,也可以是 unix 域套接字。
可配置单个string,或者是 strings 的列表。 示例:
127.0.0.1:6379 #普通的TCP连接
/path/to/socket # Unix 域套接字连接
redis://[:password]@localhost:6379/0 # 普通的TCP连接
rediss://[:password]@localhost:6379/0 # SSL 封装的 TCP 连接
# http://redis.io/topics/encryption
unix://[:password]@/path/to/socket.sock?db=0 # Unix 域套接字连接 (2)Database Number: 设置存储空间, 可在 OPTIONS 和 LOCATION 中配置 ( Default DB: 1) redis://@localhost:6379/0 CACHES = {
'default': {
'OPTIONS': {
'DB': 1,
..
},
...
}
} (3)Password: 如果 Redis Server 设置了密码,则 CACHE 中也需要设置密码, 可在 OPTIONS 中配置,也可在 LOCATION 中配置 CACHES = {
'default': {
'OPTIONS': {
'PASSWORD': 'yadayada',
...
},
...
}
}

参数

Django-redis 缓存后端配置(redis主从):

CACHES = {
'default': {
'LOCATION': [
'127.0.0.1:6379', # Primary
'127.0.0.1:6380', # Secondary
'127.0.0.1:6381', # Secondary
],
'OPTIONS': {
'PASSWORD': 'yadayada',
'MASTER_CACHE': '127.0.0.1:6379',
...
},
...
}
}

基于Redis缓存的项目实例:

这里使用redis主从架构,做之前需要配置好redis主从,配置好两份redis.conf配置文件即可,slaveof 127.0.0.1 6379

(1)配置好redis主从
$ sudo cp /etc/redis/redis.conf{,1} $ sudo vi /etc/redis/redis.conf
37 daemonize yes
45 port 6379
64 bind 127.0.0.1
391 requirepass 123456 $ sudo vi /etc/redis/redis.conf1
37 daemonize yes
45 port 6380
64 bind 127.0.0.1
206 slaveof 127.0.0.1 6379
391 requirepass 123456 $ sudo redis-server /etc/redis/redis.conf
$ sudo redis-server /etc/redis/redis.conf1
$ ps -ef | grep redis-server
root 44429 1627 0 14:53 ? 00:00:00 redis-server 127.0.0.1:6379
root 44447 1627 1 14:54 ? 00:00:00 redis-server 127.0.0.1:6380
xiaozhi+ 44480 27618 0 14:54 pts/1 00:00:00 grep --color=auto redis-server (2)配置settings
CACHES = {
'default': {
'BACKEND': 'redis_cache.RedisCache',
'LOCATION': ['127.0.0.1:6379','127.0.0.1:6380'],
'OPTIONS': { 'MASTER_CACHE': '127.0.0.1:6379',
'DB': 2,
'PASSWORD': '',
},
'KEY_PREFIX': 'MyProject',
'TIMEOUT': 480
}
} (3)使用url方式进行view缓存 from django.views.decorators.cache import cache_page urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^$',cache_page(60 * 15)(Index.as_view())=,name='INDEX'),
url(r'^index2/$',Index2.as_view(),name='INDEX2'),
] 或者在views中的方法上调用装饰器
from django.views.decorators.cache import cache_page @cache_page(60 * 15, key_prefix='index2')
def Index2(request):
return render(request,'index.html') (4)使用template片段缓存
{% extends 'base.html' %}
{% load cache %}
{% load staticfiles %}
.
.
{% cache 500 sidebar %}
.
{% endcache %}

八、序列化

关于Django中的序列化主要应用在将数据库中检索的数据返回给客户端用户,特别的Ajax请求一般返回的为Json格式。

1、serializers

from django.core import serializers

ret = models.BookType.objects.all()

data = serializers.serialize("json", ret)

2、json.dumps

import json

#ret = models.BookType.objects.all().values('caption')
ret = models.BookType.objects.all().values_list('caption') ret=list(ret) result = json.dumps(ret)

由于json.dumps时无法处理datetime日期,所以可以通过自定义处理器来做扩展,如:

import json
from datetime import date
from datetime import datetime class JsonCustomEncoder(json.JSONEncoder): def default(self, field): if isinstance(field, datetime):
return o.strftime('%Y-%m-%d %H:%M:%S')
elif isinstance(field, date):
return o.strftime('%Y-%m-%d')
else:
return json.JSONEncoder.default(self, field) # ds = json.dumps(d, cls=JsonCustomEncoder)

八、信号

  Django中提供了“信号调度”,用于在框架执行操作时解耦。通俗来讲,就是一些动作发生的时候,信号允许特定的发送者去提醒一些接受者。

一般把信号卸载和项目同名的__init__文件中

1、Django内置信号

Model signals
pre_init # django的modal执行其构造方法前,自动触发
post_init # django的modal执行其构造方法后,自动触发
pre_save # django的modal对象保存前,自动触发
post_save # django的modal对象保存后,自动触发
pre_delete # django的modal对象删除前,自动触发
post_delete # django的modal对象删除后,自动触发
m2m_changed # django的modal中使用m2m字段操作第三张表(add,remove,clear)前后,自动触发
class_prepared # 程序启动时,检测已注册的app中modal类,对于每一个类,自动触发
Management signals
pre_migrate # 执行migrate命令前,自动触发
post_migrate # 执行migrate命令后,自动触发
Request/response signals
request_started # 请求到来前,自动触发
request_finished # 请求结束后,自动触发
got_request_exception # 请求异常后,自动触发
Test signals
setting_changed # 使用test测试修改配置文件时,自动触发
template_rendered # 使用test测试渲染模板时,自动触发
Database Wrappers
connection_created # 创建数据库连接时,自动触发

对于Django内置的信号,仅需注册指定信号,当程序执行相应操作时,自动触发注册函数:

from django.core.signals import request_finished
from django.core.signals import request_started
from django.core.signals import got_request_exception from django.db.models.signals import class_prepared
from django.db.models.signals import pre_init, post_init
from django.db.models.signals import pre_save, post_save
from django.db.models.signals import pre_delete, post_delete
from django.db.models.signals import m2m_changed
from django.db.models.signals import pre_migrate, post_migrate from django.test.signals import setting_changed
from django.test.signals import template_rendered from django.db.backends.signals import connection_created def callback(sender, **kwargs):
print("xxoo_callback")
print(sender,kwargs) xxoo.connect(callback)
# xxoo指上述导入的内容
from django.core.signals import request_finished
from django.dispatch import receiver @receiver(request_finished)
def my_callback(sender, **kwargs):
print("Request finished!")

2、自定义信号

a. 定义信号

import django.dispatch
pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])

b. 注册信号

def callback(sender, **kwargs):
print("callback")
print(sender,kwargs) pizza_done.connect(callback)

c. 触发信号

from 路径 import pizza_done

pizza_done.send(sender='seven',toppings=123, size=456)

由于内置信号的触发者已经集成到Django中,所以其会自动调用,而对于自定义信号则需要开发者在任意位置触发。

更多官网:https://docs.djangoproject.com/en/1.9/topics/signals/
 
 

Python自动化运维之28、Django(二)的更多相关文章

  1. 【目录】Python自动化运维

    目录:Python自动化运维笔记 Python自动化运维 - day2 - 数据类型 Python自动化运维 - day3 - 函数part1 Python自动化运维 - day4 - 函数Part2 ...

  2. Python自动化运维:技术与最佳实践 PDF高清完整版|网盘下载内附地址提取码|

    内容简介: <Python自动化运维:技术与最佳实践>一书在中国运维领域将有“划时代”的重要意义:一方面,这是国内第一本从纵.深和实践角度探讨Python在运维领域应用的著作:一方面本书的 ...

  3. python自动化运维篇

    1-1 Python运维-课程简介及基础 1-2 Python运维-自动化运维脚本编写 2-1 Python自动化运维-Ansible教程-Ansible介绍 2-2 Python自动化运维-Ansi ...

  4. python自动化运维之CMDB篇-大米哥

    python自动化运维之CMDB篇 视频地址:复制这段内容后打开百度网盘手机App,操作更方便哦 链接:https://pan.baidu.com/s/1Oj_sglTi2P1CMjfMkYKwCQ  ...

  5. Day1 老男孩python自动化运维课程学习笔记

    2017年1月7日老男孩python自动化运维课程正式开课 第一天学习内容: 上午 1.python语言的基本介绍 python语言是一门解释型的语言,与1989年的圣诞节期间,吉多·范罗苏姆为了在阿 ...

  6. python自动化运维学习第一天--day1

    学习python自动化运维第一天自己总结的作业 所使用到知识:json模块,用于数据转化sys.exit 用于中断循环退出程序字符串格式化.format字典.文件打开读写with open(file, ...

  7. Python自动化运维的职业发展道路(暂定)

    Python职业发展之路 Python自动化运维工程 Python基础 Linux Shell Fabric Ansible Playbook Zabbix Saltstack Puppet Dock ...

  8. Python自动化运维 技术与最佳实践PDF高清完整版免费下载|百度云盘|Python基础教程免费电子书

    点击获取提取码:7bl4 一.内容简介 <python自动化运维:技术与最佳实践>一书在中国运维领域将有"划时代"的重要意义:一方面,这是国内第一本从纵.深和实践角度探 ...

  9. python自动化运维之路~DAY5

    python自动化运维之路~DAY5 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.模块的分类 模块,用一砣代码实现了某个功能的代码集合. 类似于函数式编程和面向过程编程,函数 ...

随机推荐

  1. 关于在VMware上装lFEDORA系统

    VMware虚拟机启动当中某个操作系统的时候,会出现如下提示 Cannot connect virtual device floppy0. No corresponding device is ava ...

  2. [Redux] Supplying the Initial State

    We will learn how to start a Redux app with a previously persisted state, and how it merges with the ...

  3. (转载)Java 1.7的新特性

    网上找了一下,整理了贴出来. 下面是Java 1.7 里新出现的功能的一些用法例子: 对集合的支持 摒弃了 Java 集合接口的实现类,如: ArrayList . HashSet 和 HashMap ...

  4. 【IBM】Merlin 给 Java 平台带来了非阻塞 I/O

    Merlin 给 Java 平台带来了非阻塞 I/O 新增的功能大幅降低了线程开销 Java 技术平台早就应该提供非阻塞 I/O 机制了.幸运的是,Merlin(JDK 1.4)有一根几乎在各个场合都 ...

  5. abc - zx

    诛仙青云志 第26集    第25集 第24集    第23集    第22集   第21集    第20集    第19集  第18集    第17集    第16集   第15集     第14集 ...

  6. tcpdump 命令行抓包工具

    为了防止无良网站的爬虫抓取文章,特此标识,转载请注明文章出处.LaplaceDemon/SJQ. http://www.cnblogs.com/shijiaqi1066/p/3898248.html ...

  7. mvc Action上面加 [HttpPost]

    mvc  Action上面加 [HttpPost]  意思就是这个action只能响应post请求. 如果发get请求这里是没有响应的

  8. ActionResult 常见问题

    1:在Asp.net Mvc 2中由于对数据的保护,当返回类型为JsonResult时 ,默认情况下request需要为post.(可使用   return Json(person,JsonReque ...

  9. Getting Started with Testing ——开始单元测试

    Android tests are based on JUnit, and you can run them either as local unit tests on the JVM or as i ...

  10. appium系列教程(转载)

    1.系列文章:转载来源:乙醇的cnblog http://www.kuqin.com/shuoit/20140704/340994.html 2.环境部署:http://www.51testing.c ...