这是我们老大写的!很开心能在WuLuoStudio!不是一个人再战斗!!!
DJANGO for wizard
仅以此文,献给WuLuoStudio的各位wizard:)。
1django 是框架,框架是什么?
在了解框架的概念之前,我们来看看客户端浏览器请求到显示网页内容这个过程,如下:
![DJANGO for wizard - kymo - listen to your soul](http://img9.ph.126.net/io8jQOJsK3NtnKxC2WrS5Q==/2573525712083439059.jpg)
由上图,如果没有框架的话,数据查询、生成html、数据返回三个过程我们都需要利用相应的较为底层的API去实现,而且后台cgi程序的软件架构也得自己去实现。但是框架给了我们更加方便的接口和更为合理的架构模式。
框架可以认为是采用了某种架构,集成了几大模块(数据查询、返回、生成html)的软件。php的think php,、zend framework,java的spring, hibenate, structs以及django等都属于web 框架。框架给我们提供的有操作数据库的api,使得你可以不用亲自去实现sql语言,或者说给你提供了更为高效和简洁的数据库操作接口,还给我们提供了生成动态页面的接口,因为我们需要把后台处理的结果显示在返回给客户浏览器的html文件中,所以方便的接口使得我们前端网页和后台程序可以彼此分离,这给项目管理也带来了极大方便。另外是提供了合理清晰的软件架构,如django的mvc或者说是MTV(model、template、views)一目了然。当然还有许多其他的模块,之后再介绍。
2django的模块划分
前面提到django是基于mvc架构的框架,mvc 是现在应用非常广泛的一种软件架构模式,相关概念见
百科 。但是由于django的model、template、views模块声名显赫,以下部分基本按照MTV介绍。Url主要介绍django的url配置,Model介绍django的模型,Views介绍django的视图,Template介绍django的模板,然后对一些django的小把戏做一些概要介绍。
Url
django的url匹配不得不承认真是奇葩之作,使用正则匹配的url设计,使得web 应用的url简洁明朗,它的基本过程是这样子的:
![DJANGO for wizard - kymo - listen to your soul](http://img4.ph.126.net/PPMEnnGSHDHyawM4J9ZkdA==/6597147831983516494.jpg)
![](http://img6.ph.126.net/VvmVfsWglD0IcxcvvFoycQ==/189995609297601496.jpg)
如图所示,urls.py里就是整个web项目的url匹配正则式模式,其他的文件待会儿一一介绍。在urls.py中,定义了正则匹配的规则,以及匹配成功之后的方法名(且当这么理解):
![](http://img8.ph.126.net/N0HAkWsMljKVgkQR3jNPzw==/6597986759354218268.jpg)
比如说,你访问的url为
http://www.***.com/index/,则可以加入这样一句
![](http://img5.ph.126.net/Zwbp1AVxbOeSBqiFDEzp4Q==/1280148194097978795.jpg)
这里的url是一个django自带函数,它的实现如下:
![](http://img4.ph.126.net/nUjHAi7nfb5Y0X-_JzkmbQ==/6597409515751007924.jpg)
即如果匹配成功,则会调用index.views.home这个方法进行处理,或者转入到另外的url匹配(
假如我们是这样子定义的匹配规则:
url(r'^index/', include('index.urls'),)。
index 即为你web 项目的应用,一般在manage.py文件所在的目录下,使用python manage.py startapp index 生成,生成一个web app后会有四个文件,如下:
![](http://img9.ph.126.net/2HGJMKNaVMFqVyogg9CnQw==/614741349153871129.jpg)
models.py 接下来会介绍,定义的是你app所需要的数据库表映射对象。
views.py 即为该app的业务处理部分,在这里定义的函数参数都有一个request对象,该对象保存了web项目的session、cookie、以及用户提交的数据等内容,并且返回必须是一个httpresponse对象。根据url的匹配规则,需要定义一个名为home的函数,如下:
![](http://img8.ph.126.net/9O8vA9DSp-1667dlpHzO8w==/2665849504444547028.jpg)
然后运行
python manage.py runserver,这里顺带提一下,如果项目比较小的话,是不需要外部服务器程序支持的,因为它内嵌了一个web服务器,如果你的项目部署在自己的服务器上,那么可以python manage.py runserver (your vps ip):80,浏览器输入你vpsip或者自己绑定好的域名就可以访问你的django 网站了。
Model
在django里,model这块我知道的有以下两种:
单纯的数据模型 前文提到的django app的models.py 文件里的一些类,定义的就是web 数据库表在django里的映射对象。该对象继承了django封装好的数据库模型类,从而我们在定义自己的数据表对象之后,可以很方便的使用django模型提供的一些API,比如save()可以存数据, objects.create可以创建数据表对象等。
假如我们的网站有个项目表,定义的是项目的一些信息。我们在index的models.py可以这样定义:
![](http://img2.ph.126.net/Pyc_d3HyH9yzu70C6j9e9w==/6598075819795893992.jpg)
![](http://img5.ph.126.net/pwmp9GXjVmwqrY08ZxM1Jw==/6598178074377280295.jpg)
然后需要在settings.py中的INVALID_APPS列表中加入index。否则django无法识别该app的models.py,从而无法生成数据库。
![](http://img7.ph.126.net/akTHYN1iRyPWk2zzK4yeWw==/6598080217842405167.jpg)
接着 python manage.py syncdb
![](http://img5.ph.126.net/8KiHpzQXRfpKFez2bN_zYw==/6597164324657932175.jpg)
数据库表project 就ok了。
数据库存储会在之后的views和表单处理详述。
表单数据模型 web app少不了表单请求,django有自己独特的表单模块,相见
django 表单 ,django的表单模型需要和web 的某个数据库模型一一映射,用户提交表单后,django封装的表单模型会自动进行数据的存取。这个过程相当于集成了提取表单数据和数据库操作。之后在介绍表单的时候也会详述。
Template
然后是模板系统,django的模板系统有一点个人感觉是瑕疵,需要前端人员也了解一些模板系统的设计思路。但是,这也无可厚非,单纯的前端已经很少见了。这里讲三点,首先是模板系统的设置,我们在使用之前需要设置我们的.html文件和静态文本文件(css,js)的路径。
设置template_dir,在settings.py所在目录下新建template文件夹,用以保存.html文件。
![](http://img0.ph.126.net/wNY4TGEYnN0Br8M4wTQfzw==/6597876808191442280.jpg)
然后在settings.py中设置
![](http://img5.ph.126.net/Zu7cgQZgm-pWZOIQHaK4aA==/6597848220889119975.jpg)
![](http://img1.ph.126.net/h68JnrFMYM9ou_oxXSG8ag==/6598136292935423051.jpg)
![](http://img5.ph.126.net/rmUeXbT2ZVXbigQknFhRiA==/6597710781935637825.jpg)
要加入相应的模块支持,如下
![](http://img0.ph.126.net/JHkz0SLh5Gv6R-naWlUhPg==/6597135737355614350.jpg)
具体的测试见Views。
接着便是模板系统的模板语言,我们知道我们需要将后台的处理结果渲染(也就是呈现)在返回客户浏览器的html文件中,但是,django不支持像php那样的直接在html中加入php语言一样在html中加入python语句,但是,它有自己独特的一套模板语言,支持if,for等语句,
见后文例子中介绍。
最后是模板继承,什么意思?比如说,我们这样一个网页
![](http://img0.ph.126.net/fg6oc8d-7aUfyP8ItxpLGA==/6598258338726109280.jpg)
首页、日志、相册、音乐等必然都包含同样的header,如果每一个.html文件都写那部分的话,挺麻烦的,但是模板继承解决了这个问题,你需要做的事情就是定义一个顶层html文件,比如上面那个网页我可以定义一个base.html,index.html和article.html都会继承这个base.html,在base.html文件里需要被重新编排(且叫做编排)格式的地方使用
{% block block_name %}{% endblock %}注明,在index.html和article.html在文件头注明
{% extends 'base.html' %},然后在自编排的地方也同样使用
{% block block_name %} your_html_code {% endblock %},那么模板系统在解析index.html文件时,会把base.html的内容和自编排的内容整合成一个新的.html文件。
base.html(注意静态文件路径)
![](http://img8.ph.126.net/QVo5IO1uJLI4ECSvAce4bA==/6597882305749584418.jpg)
![](http://img7.ph.126.net/zepn2M01IMH1t5Fyl41bUQ==/6597770155563552157.jpg)
注意,继承自base.html的html文件的自定义部分必须在
{% block block_name %}{% endblock %}标签内,不然模板系统不予识别。如上面的index.html中{{nihao}}这个变量(views里会说明),模板系统不会解析出来。所以index.html看起来应该是这个样子:
![](http://img0.ph.126.net/56QVRNYowggjmlY_IOmuBw==/6597205006588155460.jpg)
Views
视图,用来处理呈现后台返回数据、用户提交数据以及数据的处理部分。django的MVC架构中的V包含了视图和之后介绍的模板系统。
之前介绍的index app的views.py文件的作用就是定义视图函数,视图函数的两大特征前面已经介绍,这里总结一下:一、参数必须有HttpRequest对象,也即request;二、返回类型必须是一个HttpResponse对象。之前的home就是一个视图函数。
视图函数主要是做数据处理,数据呈现并将数据渲染到相应的模板html文件中。
下图所示的即为将st(st是一个字典对象)的数据传到index.html中。
![](http://img6.ph.126.net/bO5eKvouAu2pAXN2A64P4A==/6597135737355614526.jpg)
![](http://img3.ph.126.net/hDdwA9EzXQs7aHqjPeOnuQ==/6597701985842616783.jpg)
之后的表单会介绍如何实现数据存储和读取。
Form
表单,django把表单都集成了,这点让人意外,但它就是这么做了,而且做的很出色,不管是数据检查和数据安全性都控制的十分的严格。在不使用form的时候,用户提交的表单数据一般都保存在HttpRequest对象的POST属性中,所以我们的html文件和views.py的视图函数以及urls.py看起来应该是这样子:
urls.py
![](http://img5.ph.126.net/H-D71lpzO6PtHO7vP1m6gQ==/6597606328330998915.jpg)
![](http://img2.ph.126.net/DShQl12IzuW0v0QZHhT1Rg==/6597809737982148782.jpg)
article.html
![](http://img6.ph.126.net/lZ2NZWAj_hoQpobmSddc5A==/6597234693402114346.jpg)
但是,你觉得这样子就能ok么?不,孩子你还天真了。它会提示你
CSRF verification failed.Request aborted。
django想的比你多,它的内嵌CSRF(反跨站)提供了一个安全的用户提交表单的环境。 网上很多人把CSRF直接给禁了!如果用户是个骇客(不能叫黑客),不好意思,不出几分钟,你的网站就要被他拿下了,所以
请相信一点:用户永远是最不可靠的:),你永远要做尽量全面的安全维护。有些人没事把你网站拿来练sql注入,练跨站攻击,坏的很。
那么怎么正确的使用csrf呢(三步走),一、在表单后面加
{% csrf_token %}
;
二、
在settings.py 的MIDDEL_CLASS 中加入
’django.middleware.csrf.CsrfViewMiddleware’;三、
在视图函数中要用RequestContext来渲染表单模板。所以settings.py、views.py、article.html三个文件的局部应该是这样子:
settings.py
![](http://img8.ph.126.net/-7LyKwGAQI-Oz1oCDHfboQ==/6597881206237956088.jpg)
views.py
![](http://img1.ph.126.net/uCz-zq3-CtliXJbDIWJHqQ==/6597256683634676701.jpg)
article.html
![](http://img4.ph.126.net/Tqne1yG5A5ObvPbU0ekPDg==/6597333649448698824.jpg)
我们提交表单后,查询数据库,会发现数据已经存入数据库了。
![](http://img6.ph.126.net/aEP2OF-1qN0oDDfR-4_Fng==/6597639313679837096.jpg)
![](http://img5.ph.126.net/FCC9kRd_iPm3hHqAqLHbGQ==/6597760259958893675.jpg)
然后在views里使用projectForm,看起来是这样子的:
![](http://img0.ph.126.net/VUih-56nXQkBDl2pRft-BA==/6597926286214694670.jpg)
![](http://img6.ph.126.net/Z69LkwPPMK-TkTX-F1yBfQ==/6598120899772636396.jpg)
![](http://img5.ph.126.net/sXdw6J9Gb3PczZWAg3NxgQ==/6597241290471881535.jpg)
field.errors是需要你自己去定义你表单数据的规则,比如密码我可以这样定义:
![](http://img2.ph.126.net/Xi63dtwh7Xef4nQ5PEBYPg==/6598293523098201862.jpg)
FormModel 在此不再赘述,即为form和model的综合体。
Summary:
文章好长,如有失误之处,还
望提醒。
@WuLuoStudio版权所有,如需转载,请注明出处。
DJANGO for wizard 续篇
接着上一篇的内容,假设你现在已经了解了Django的MVC架构,这里讲讲和前端有关的一些东西,虽然有班门弄斧之嫌,但且让我抛砖引玉。这篇博文主要介绍ajax以及ajax和django的CSRF机制的冲突解决。
ajax ,全称
Asynchronous JavaScript And XML(
异步JavaScript和XML),
是指一种创建交互式网页
应用的网页开发技术。简单的可以理解为javascript程序(一般都是用户浏览器程序)向服务器提交用户请求,并处理响应。我们知道浏览器程序提交请求的时候,必然会有一个等待返回结果的时间,这段时间内,用户被阻塞,再也无法进行下一步操作。但是,ajax使得我们在和服务器交互的时候,仍然能够进行其他的操作,这就是异步,或者也可以理解为多线程。
在这篇博客中,用的是jQuery去实现ajax,这里提一下jQuery,
jQuery使用户能更方便地处理HTML documents、events、实现动画效果,并且方便地为网站提供ajax交互。并且,更为方便的是,世界各地的js程序员为jQuery扩充了大量的开源库,使得开发出一个交互性极强、效果极炫的网站变得更加简单。首先需要下载
jQuery
的库,在你的模板文件中引入相应目录下的jQuery.js文件即可。
<script type="text/javascript" src=“/your_directory/jQuery.js"></script>
接着在你的模板文件index.html中加入这段js代码:
function reply(url){
alert(url);
$('<div>').load(url,
{'messageReply':document.getElementById('messageReply').value},
function(){
$('#deal').append($(this).html());
alert('转发成功!');
}
);
}
$('div').load函数可以这样解释,将id为messageReplay的标签的值赋和messageReply组成字典(可以一次发送多个数据),通过POST方式,发送到服务器端,服务端会去处理url,如果成功,执行下面定义的那个function,一般而言我们后台会返回一段字符,$('#deal').append() 要和前面的$('<div>')一起看,即在id为 deal的div中显示服务器返回的内容,这个过程,是不需要刷新页面的。
在html正文部分应该是这样子:
<textarea id = 'messageReply'> </textarea>
<input type='submit' value = 'submit' οnclick='reply('\text\')>
<div id = 'deal'></div>
我们需要在urls.py中加入对\text\的匹配规则
from *.views import deal_text
#other code
url(r'^text\', deal_text),
然后在相应的views.py中有如下代码:
from django.shortcuts import render_to_response
from django.http import HttpResponse
def deal_text(req):
st = req.POST.get('messageReplay','')
reply = '<div>ok</div>'
return HttpResponse(reply)
前面说到上面的ajax是通过post方式的,所以我们可以通过req.POST.get获取ajax提交的数据,然后返回reply的内容。但是,这样子还不行,问题在哪儿?上一篇提到说,如果是表单形式提交的话,必须加入CSRF,POST方式提交必须经过验证,方法前面提到过了,ajax的实质仍然是POST,所以仍然需要验证,不然会被认为是XSS,但是ajax怎么搞?It is easy!还记得前面表单后面的{% csrf_token %} 么,在表单提交的时候,会把{% csrf_token %}的内容也提交到后台,Django会自动进行认证。不过,在这里我们需要手动进行csrf_token的提交,不过还好有人帮我们写好了代码,把下面的代码保存为ajax.js,引入你的.html文件中即可,不过必须在jQuery引入之后进行。
$(
'html'
).ajaxSend(
function
(event, xhr, settings) {
function
getCookie(name) {
var
cookieValue =
null
;
if
(document.cookie && document.cookie !=
''
) {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var
cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break
;
}
}
}
return
cookieValue;
}
if
(!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) {
// Only send the token to relative URLs i.e. locally.
xhr.setRequestHeader(
"X-CSRFToken"
, getCookie(
'csrftoken'
));
}
});
然后提交ajax请求,应该不会出现403错误了。enjoy it
参考资料 jquery http://baike.baidu.com/view/1020297.htm
ajax http://baike.baidu.com/view/1641.htm
django 框架下使用ajax http://nswish.iteye.com/blog/967910
@WuluoStudio 版权所有 如需转载,请注明出处