拾伍 ● Ajax技术

Ajax定义

Ajax: 异步的 JavaScript XML (Asynchronous+Javascript+XML)

通过Ajax, 我们可以在不重新加载整个网页的情况下,对网页的某部分进行更新(重新加载整个网页是: 雕版印刷, 对网页的某个部分进行更新: 活字印刷)

 

异步: 向服务器发送请求的时候,我们不必等待结果,而是可以同时做其他的事情,等到有了结果我们可以再来处理这个事

 

常见Ajax技术

1 $.post()$.get()$.load()是一些简单Ajax方法(用得较少)

<html>

<head>

<script type="text/javascript" src="/jquery/jquery.js"></script>

<script type="text/javascript">

$(document).ready(function () {

$("#b01").click(function () {

$('#myDiv').load('/jquery/test1.txt');

});

});

</script>

</head>

<body>

 

<div id="myDiv"><h2>通过 AJAX 改变文本</h2></div>

<button id="b01" type="button">改变内容</button>

 

</body>

</html>

 

2 jQuery.ajax(), $.ajax(), 能处理复杂的逻辑

般使用格式

$("#login_btn").on("click", function () {

$.ajax({

url: "/foo/",

type: 'POST',

data: 键值对(data是引用数据类型),

success: function(data){},

dataType: dataType

});

});

$.ajax()参数是一个字典, 它的键包括:

url→必需,默认为当前页地址)指向要操作的路径

type→可选, 请求方式("POST", "GET")

data→可选, 键值对(data是引用数据类型), 连同请求发送到服务器。

success→可选, 请求成功时执行的回调函数

dataType→可选, 规定预期的服务器响应的数据类型。若未指定, 则智能判断(xmljsonscript html)。

如果要处理 $.ajax() 得到的数据,则需要使用回调函数:beforeSenderrordataFiltersuccesscomplete

 

※ jQuery.ajax()的参数列表

参数名 

类型 

描述 

url  

String

(默认当前页地址发送请求的地址。 

type 

String

(默认: "GET") 请求方式 ("POST"  "GET"),默认为 "GET"。注意:其它HTTP 请求方法,如 PUT  DELETE 也可以使用,但仅部分浏览器支持。 

timeout 

Number

设置请求超时时间(毫秒)。此设置将覆盖全局设置。 

async  

Boolean

(默认: true) 默认设置下,所有请求均为异步请求。如果需要发送同步请求,请将此选项设置为 false。注意,同步请求将锁住浏览器,用户其它操作必须等待请求完成才可以执行。 

beforeSend 

Function

发送请求前可修改 XMLHttpRequest 对象的函数,如添加自定义 HTTP头。XMLHttpRequest 对象是唯一的参数。

function (XMLHttpRequest) {

  this; // the options for this ajax request

}

cache  

Boolean

(默认: true) jQuery 1.2 新功能,设置为 false 将不会从浏览器缓存中加载请求信息。 

complete  

Function

请求完成后回调函数 (请求成功或失败时均调用)。参数:XMLHttpRequest 对象,成功信息字符串。

function (XMLHttpRequest, textStatus) {

  this; // the options for this ajax request

}

contentType 

String

(默认: "application/x-www-form-urlencoded") 发送信息至服务器时内容编码类型。默认值适合大多数应用场合。 

※ fromenctype属性的默认值也是application/x-www-form-urlencoded

data

Object,

String

发送到服务器的数据。将自动转换为请求字符串格式。GET 请求中将附加在 URL 后。查看 processData 选项说明以禁止此自动转换。必须为Key/Value 格式。如果为数组,jQuery 将自动为不同值对应同一个名称。如 {foo:["bar1", "bar2"]} 转换为 '&foo=bar1&foo=bar2'

dataType

String

预期服务器返回的数据类型。如果不指定,jQuery 将自动根据 HTTP MIME 信息返回 responseXML  responseText,并作为回调函数参数传递,可用值:

"xml": 返回 XML 文档,可用 jQuery 处理。

"html": 返回纯文本 HTML 信息;包含 script 元素。

"script": 返回纯文本 JavaScript 代码。不会自动缓存结果。

"json": 返回 JSON 数据。

"jsonp": JSONP 格式。使用 JSONP 形式调用函数时,如 "myurl?callback=?" jQuery 将自动替换 ? 为正确的函数名,以执行回调函数。

error

Function

(默认自动判断 (xml  html)) 请求失败时将调用此方法。这个方法有三个参数:XMLHttpRequest 对象,错误信息,(可能)捕获的错误对象。

function (XMLHttpRequest, textStatus, errorThrown) {

  // 通常情况下textStatuserrorThown只有其中一个有值

  this; // the options for this ajax request

}

global

Boolean

(默认: true) 是否触发全局 AJAX 事件。设置为 false 将不会触发全局 AJAX事件,如 ajaxStart  ajaxStop 。可用于控制不同的Ajax事件

ifModified

Boolean

(默认: false) 仅在服务器数据改变时获取新数据。使用 HTTP  Last-Modified 头信息判断。

processData

Boolean

(默认: true) 默认情况下,发送的数据将被转换为对象(技术上讲并非字符串以配合默认内容类型 "application/x-www-form-urlencoded"。如果要发送 DOM 树信息或其它不希望转换的信息,请设置为 false

success

Function

请求成功后回调函数。这个方法有两个参数:服务器返回数据,返回状态

function (data, textStatus) {

  // data could be xmlDoc, jsonObj, html, text, etc...

  this; // the options for this ajax request

}

 

 

3 jQueryserialize() 方法

语法: $(selector).serialize()

serialize() 方法通过序列化表单值创建 URL 编码的文本字符串。

您可以选择一个或多个表单元素(如输入和/或文本区),或表单元素本身。

序列化的值可在生成 AJAX 请求时, 用于 URL 查询字符串中。

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

<title>菜鸟教程(runoob.com)</title>

<script src="http://cdn.static.runoob.com/libs/jquery/1.10.2/jquery.min.js">

</script>

<script>

$(document).ready(function () {

$("button").click(function () {

$("div").text($("form").serialize());

});

});

</script>

</head>

<body>

 

<form action="">

第一个名称: <input type="text" name="FirstName" value="Mickey"/><br>

最后一个名称: <input type="text" name="LastName" value="Mouse"/><br>

</form>

<button>序列化表单值</button>

<div></div>

 

</body>

</html>

 

效果:

 

序列化

● Django支持的序列化格式

Django支持的序列化格式包括json, xmlyaml, 我们只关注jsondjango序列化格式

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,主要用于传送数据。

 

● Djangoserializers.serialize() & pythonjson.dumps()

对于DjangoQueryset<Queryset [object,object,object]>, 不能使用pythonjson方法序列化,而要用到django serializers

情况1: 使用serializers.serialize

from django.core import serializers

 

ret = models.BookType.objects.all()

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

 

#serialize()的参数是:

# 序列化目标格式,

# 序列化的QuerySet对象 (事实上,第二个参数可以是任何可迭代的Django Model实例,但它很多情况下就是一个QuerySet).

情况2: 使用json.dumps()

import json

 

# ret1 = models.BookType.objects.all().values('caption')
# ret1['列名'] = list(ret1)

 

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

 

# 提示:.
# values()取到的格式是这种: < querytset[{key: value}, {key: value}.......] > 列表里面的字典类型的格式
# values_list()取到的格式是这种: < querytset[(), (), (), ()......] > 列表里面元祖的格式

 

拾陆 ● Django的表单系统: 主要分两种

基于django.forms.Form

定义形式

from django import forms

class FormName(forms.Form):

field1 = forms.XXField(...) # model字段是field1 = models.XXField(...)

field2 = forms.XXField(...)

 

表单字段的参数包括(不一定都有, 用逗号分隔参数)

max_length这种字段固有的参数

部件(widget)对象

字段参数负责"校验逻辑",而部件对象负责" 显示逻辑"

#form.py

from django import forms

 

class CommentForm(forms.Form):

name = forms.CharField()

url = forms.URLField()

comment = forms.CharField(widget=forms.Textarea()) # Textarea后的括号可以省略

# Widget (部件)Django HTML 输入元素的表示。(A widget is Django's representation of an HTML input element.)

# 这里的 comment 会变成 Textarea,而不是 CharField

 

# 如果想让Widget 具有一些特殊的CSS , 可以这样设置:

class CommentForm(forms.Form):

name = forms.CharField(widget=forms.TextInput(attrs={'class': 'special'}))

url = forms.URLField()

comment = forms.CharField(widget=forms.TextInput(attrs={'size': '40'}))

title = forms.CharField(max_length=20,

min_length=5,

error_messages={'required': '标题不能为空',

'min_length': '标题最少为5个字符',

'max_length': '标题最多为20个字符'},

widget=widgets.TextInput(attrs={'class': "form-control", 'placeholder': '标题5-20个字符'}))

 

细节知识

Form 的对象具有一个is_valid() 方法,它为所有的字段运行验证的程序。

当调用这个方法时,如果所有的字段都包含合法的数据,它将:

返回True

将表单的数据放到cleaned_data属性中。

其它Form对象的API:

http://www.lxway.com/496695522.htm

 

基于django.forms.ModelForm

※ ModelForm 能允许我们通过一个 Model, 直接创建一个和该Model的字段一一对应的表单,大大方便了表单操作:

#models.py

class ExamInfo(models.Model):

field1 = models.XXField(...) # 表单字段是field1 = forms.XXField(...)

field2 = models.XXField(...)

 

#form.py

#定义ExamInfoForm,Form的名字为模型名+Form

from django.forms import ModelForm

from .models import ExamInfo

class ExamInfoForm(ModelForm):

class Meta:

model = ExamInfo

fields = '__all__'

# fields = ('field1','field2') #只显示model中指定的字段

 

※ form组件的主要功能

生成HTML标签

验证用户数据(显示错误信息)----对用户提交的内容进行验证(from表单/Ajax

提交、保留上次提交的数据

初始化页面显示内容

 

钩子(hook)(对于django来说)

部钩子:校验单个字段,例如:用户名最短5个字符,最长12个字符;密码必须大于8位,验证码必须正确

全局钩子:校验多个字段,例如:密码和重复密码必须一致

 

对于MFC编程来说,消息钩子分为局部钩子和全局钩子。

局部钩子将仅拦截某一进程的指定消息,

全局钩子将拦截系统中所有进程的指定消息。

 

拾柒跨站请求伪造(csrf/xsrf, Cross-site request forgery)

● csrf定义

Django具有防止跨站请求伪造的功能,有全局和局部之分

--全局防止跨站请求伪造通过中间件 django.middleware.csrf.CsrfViewMiddleware 来完成

--局部防止跨站请求伪造通过@csrf_protect@csrf_exempt装饰器来实现

※ from django.views.decorators.csrf import csrf_protect, csrf_exempt

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

※ @csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。

 

● csrf案例

用户访问www.mybank.com网站, 登录并且未退出,

用户同时访问了一个黑客网站, 黑客网站发给客户的html代码中带有上面的代码(一段假装生成一个图片元素的html代码, get方式的数据传递), 因而访问了src对应的可实现转账的代码(此时cookie未失效), 因此, 一段服务端发给浏览器的csrf_token可用来验证某段代码是用户的浏览器发送的代码, 而不是其它服务器发送的.

 

● csrf的应用

详见: https://www.cnblogs.com/zhaof/p/6281482.html

1 ● 普通表单

# ① veiw中设置返回值:

											return render_to_response('Account/Login.html',data,context_instance=RequestContext(request))  
# 或者

										return render(request, 'xxx.html', data)

 

# ② html中设置Token:
form表单里面需要添加{%csrf_token%}

这样当你查看页面源码的时候,可以看到form中有一个input是隐藏的

总结原理:当用户访问login页面的时候,会生成一个csrf的随机字符串,并且cookie中也存放了这个随机字符串(如下图),当用户再次提交数据的时候会带着这个随机字符串提交,如果没有这个随机字符串则无法提交成功

 

2 ● Ajax

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

1, csrfajax提交的时候通过请求头(headers)传递的给后台的

2, csrf在前端的key为:X-CSRFtoken,到后端的时候django会自动添加HTTP_,并且最后为HTTP_X_CSRFtoken

3, csrfform中提交的时需要在前端form中添加{%csrftoken%}

    $("#btn1").click(function () {
        $.ajax({
            url:"/login/",
            type:"POST",
            data:{"usr":"root","pwd":"123"},
            headers:{ "X-CSRFtoken":$.cookie("csrftoken")}
            success:function (arg) {

 

            }
        });
    });
<script>

											//情况一: 一般情况

											$('#i1').click(function () {

										var csrf_token = $.cookie('csrf_token')

										$.ajax({

										url: 'xxx',

										type: 'post',

										data: {'username': xxx, 'password': 123123},

										headers: {'x-CSRFtoken': csrf_token},

										success: function (arg) {

 

            }
        });
    });

 


											//情况二: 如果想要实现在当get方式的时候不需要提交csrftoken,当post的时候需要,实现这种效果的代码如下:
    // Ajax整个页面统一配置
    //  xhr  XMLHttpRequest对象,默认Ajax底层使用的就是它
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);
            }
        }
    });
</script>

 

拾捌 ● WSGI

● WSGI定义

※ CGI(Common Gateway Interface)是通用网关接口,而WSGI就是PythonCGI包装,相对于FastcgiPHPCGI包装, 它规定了Web服务器调用其他可执行程序(CGI程序)的接口协议标准。

(1) WSGI(Web Server Gateway Interface, Web服务器网关接口)是一种规范, 是将Python服务器端程序连接到Web服务器的通用协议,它实现了Web服务器和Web应用程序之间的解耦(decoupling)

 

(2) WSGI接口规范的目的就是规范Web服务器与Web应用之间的交互,在协议之间进行转换(WSGI就是Web就是一个网关(Gateway),而网关的作用就是在协议之间进行转换。)

 

(3) WSGIWeb组件分成三类:Web服务器(WSGI Server)Web中间件(WSGI Middleware)Web应用程序(WSGI Application)

--服务器:指的是实现了调用应用(call application)的部分。

--中间件:处于服务器和应用两侧,起粘合作用,具体包括:请求处理、environ, 即环境变量的处理。

--应用:指的是可以被调用的一个对象,一般指的是包含一个__call__方法(实例可以当作函数一般调用)的对象。

 

python标准库提供的独立WSGI服务器(WSGI server)称为wsgiref(模块)

 

注意

※ environPython内置的dict对象,它是系统的环境变量;

通过import os; os.environ获取所有的环境变量;

查看环境变量: os.environ.get('path')可以获取path这个环境变量被赋值的路径

设置环境变量: os.environ["PATH"] = os.environ["PATH"]+';' + "要增加的路径"

 

WSGI的角色

WSGI的接口分为两个:

一个是它与Web服务器的接口,另一个是它与服务器端程序的接口。

① WSGI ServerWeb服务器的接口包括uwsgifast cgi

(我们无须详细学习)

服务器端的开发者需要关注的是WSGI与服务器端程序的接口。

※ DjangoCherryPy 都自带符合WSGI规范的 WSGI server,

而有些 WSGI 下的框架比如 pylonsbfg , 自己不实现 WSGI server, 而是使用 paste 作为 WSGI server, paste 是流行的 WSGI server, 带有很多中间件。

 

Django内置的服务器

Django 内部自带了一个方便本地测试的小服务器, 所以在刚开始学习 Django 的时候并不需搭建 apache 或者 nginx 服务器.

 

Django 自带的服务器基于 python wsgiref 模块实现的, 其百分之七八十的代码都是 wsgiref 中的代码, 只重写了一部分.

具体来说, Django 内置服务器基于 django.core.servers django.core.handlers这两个类共同实现.

 

 

拾玖中间件(MIDDLEWARE )

中间件的介绍

django中,中间件其实就是一个类; settings.py中,MIDDLEWARE 列表的每一个元素就是一个中间件:

 

http请求到达视图函数之前和视图函数return之后,Django会根据自己的规则在合适的时机执行中间件中相应的方法

 

注意: 如果在其中一个中间件里 request方法里 return了值,就会执行当前中间件的response方法,返回给用户然后报错, 并且不会再执行下一个中间件。

 

Django会先按顺序执行各个中间件的request方法, 然后执行视图函数, 然后反序执行各个中间件的response方法.例如:

 

自定义中间件的步骤

  1. project下随便创建一个py文件

  1. setings文件中注册这个 py文件

结果:

为啥报错了呢?

 

因为自定义的中间件response方法没有return结果交给下一个中间件,导致http请求中断了!!!

 

注意: 自定义的中间件request 方法不要return结果, 否则, 中间件不再会往下执行,导致 http请求到达不了视图层.

 

 

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

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

有关自定义中间件, 参见: https://www.cnblogs.com/huchong/p/7819296.html

 

 

贰拾Django的信号

信号的定义

Django中提供了"信号调度",用于在框架执行操作时解耦.

一些动作发生的时候,系统会根据信号定义的函数执行相应的操作. (例如下面的: 创建数据库记录时, 触发pre_savepost_save信号)

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

 

信号的案例

创建数据库记录时, 触发pre_savepost_save信号

# models.py

from django.db import models
class UserInfo(models.Model):
    name=models.CharField(max_length=32)
    pwd=models.CharField(max_length=64)

#

views.py
from django.shortcuts import render,HttpResponsefrom app01 import  models
def index(request):
    models.UserInfo.objects.create(name="mysql",pwd="mysql123")

										return HttpResponse("ok")

#

项目的__init__.py文件中代码
from django.db.models.signals import pre_save,post_save

 

def pre_save_func(sender,**kwargs):

										print("pre_save_func")
print("pre_save_msg:",sender,kwargs)

 

def post_save_func(sender,**kwargs):

										print("post_save_func")

										print("post_save_msg:",sender,kwargs)

 

pre_save.connect(pre_save_func)             # models对象保存前触发callback函数
post_save.connect(post_save_func)           # models对象保存后触发函数

#

创建一个index.html网页(内容不限),用浏览器打开这个项目,在服务端后台打印信息如下:
pre_save_func
pre_save_msg: <class
												'app01.models.UserInfo'> {'signal': <django.db.models.signals.ModelSignal object at 0x0000000002E62588>, 'instance': <UserInfo: UserInfo object>, 'raw': False, 'using': 'default', 'update_fields': None}

 

post_save_func
post_save_msg: <class
												'app01.models.UserInfo'> {'signal': <django.db.models.signals.ModelSignal object at 0x0000000002E62630>, 'instance': <UserInfo: UserInfo object>, 'created': True,
																				'update_fields': None, 'raw': False, 'using': 'default'}

 

# 比较打印的结果,可以看到models对象保存后,在打印信息里包含一个"create=True"的键值对.

有关自定义信号

, 详见:
http://www.cnblogs.com/haiyan123/p/8259647.html

 

 

贰拾壹 ● Django的缓存

缓存的定义

缓存,缓存将一个某个views的返回值保存至内存或者memcache中,之后再有人来访问时,则不再去执行view中的操作,而是直接从内存或者Redis中之前缓存的内容拿到,并返回。

Django settings cache 默认为

{

'default': {

'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',

}

}

也就是默认利用本地的内存来当缓存,速度很快,当然可能出来内存不够用的情况。

 

● Django中提供缓存方式

下面的缓存方式都需要在setting.py里面配置:

- 开发调试

- 本地内存(默认的缓存方式)

- 文件

- 数据库

- Memcache缓存(python-memcached模块)----memcache是一套分布式的高速缓存系统

- Memcache缓存(pylibmc模块)

- Redis缓存

详见:

https://code.ziqiangxuetang.com/django/django-cache.html

http://www.cnblogs.com/haiyan123/p/8424231.html

 

 

贰拾贰 ● admin

django amdindjango提供的一个后台管理页面,改管理页面提供完善的htmlcss,使得你在通过Model创建完数据库表之后,就可以对数据进行增删改查.

我们学习和使用更加完善的xadmin, 下面只介绍admin的简单用法.

 

● admin的一般使用步骤

项目名/项目名/urls.py配置url

url(r'^admin/', include(admin.site.urls))

 

注册medel类到admin: 应用名/admin.py里面把我们当前应用models.py里面的User 这个model注册进去,如下。

from django.contrib import admin

from .models import User

 

admin.site.register(User)

# 通过admin.site.register()函数逐个声明要管理的模型类.

# 再如: 假设有Book, MyAdmin, Publish, Author五个模型类:

admin.site.register(Book,MyAdmin) # Author模块和管理类绑定在一起,注册到后台管理

admin.site.register(Publish)

admin.site.register(Author)

 

通过python manage.py runserver命令启动项目,然后http://127.0.0.1:8000/admin访问,会自动跳转到它的主页,如图所示:

 

通过"python manage.py createsuperuser"命令创建超级用户,例如:

python manage.py createsuperuser

Username: admin

Email address: Password:

Password (again):

Superuser created successfully.

 

假如我创建了一个用户名:admin 密码:admin123的用户,我们就可以登录进django admin后台管理系统了,登录成功如下所示,我们可以通过右侧的 "add" 添加用户:

我们操作admin和我们操作数据库是一样的,例如上面的Users对应的就是sqlite数据库中的user,也就是说,如果要求不高的话后台都不需要我们开发了!

 

 

贰拾叁设置404页面和500页面

1, blog/templates/user下面添加一个404.html和一个500.html页面,代码任意,

 

2, 配置setting.py文件,如下:

DEBUG=True的时候, djangorunserver是自动使用StaticFilesHandlerserve 静态文件的,

DEBUG=False的时候, django就不处理静态文件, 交由其它的静态服务器来处理.

 

3, urls.py(settings.py文件下面)添加如下配置: 前面的代码是固定的,后面代码的意思是在blog模块下的views.py中处理这两个404500错误。

 

4, views.py中添加page_not_foundpage_error这两个方法,用于页面跳转,如下:

# 404错误
def page_not_found(request):

										return render(request,'user/404.html',{})
# 500错误
def page_error(request):

										return render(request, 'user/500.html', {})

 

 

贰拾肆富文本编辑器

常用富文本编辑器

Kindeditor

参考: http://www.cnblogs.com/wupeiqi/articles/6307554.html

 

DjangoUeditor3

参考: http://www.cnblogs.com/adc8868/p/7580705.html

 

Tinymce

参考: http://blog.csdn.net/u010505059/article/details/78650742

 

贰拾伍 ● REST & RESTful API

REST, Representational State Transfer"表现层状态转化", 全称是 Resource Representational State Transfer, "资源在网络中以某种表现形式进行状态转移"

※ Resource:资源,即数据(网络的核心,例如newsfeedfriends等);

Representational:某种表现形式,例如JSONXMLJPEG等;

State Transfer:状态变化, 通过GET,POSTHTTP动词实现。

RESTful API: 符合REST架构设计的API, HTTP协议就是属于REST架构的设计模式, 例如: 无状态,请求-响应机制.

RESTful API要求增删查改都是一个地址,具体靠HTTP请求头部信息判断, HTTP请求头包括Content-Type等信息.

※ REST是所有Web应用都应该遵守的架构设计指导原则。当然,REST并不是法律,违反了REST的指导原则,仍然能够实现应用的功能。但是违反了REST的指导原则,会付出很多代价,特别是对于大流量的网站而言

 posted on 2018-02-01 13:07  Arroz  阅读(235)  评论(0编辑  收藏  举报