enumerate latex分成两列用什么命令

VC读取数据源列表和驱动程序列表-真格学网-提供健康,养生,留学,移民,创业,汽车等信息
VC读取数据源列表和驱动程序列表
来源:IT168 &责任编辑:李志 &时间: 12:50:58
vc++6.0编写一个c语言程序用来从终端读取用户输入...问:vc++6.0编写一个c语言程序用来从终端读取用户输入的数字(1<数字<10)...答:你输入语句有问题,应该不是%i而是%dVC++中文件中数据的读取问:比如我要计算两组数据,都很长,每次计算都只从文件中读取一组数据,但是...答:建议你参考我写的一段代码voidCMainFrame::planeOutput(){for(inti=0;iVC数据读取的问题问:关于内存加载运行源码,现在有一个混合的文件,在C32中前半部分是一个图...答:从文件的指定位置读取就行了埃比如你用CFile类读取这个文件,Open后用Seek函数到把游标定位到exe数据开始的位置,然后read就可以了。vc++,读取一个数据文件的一行数据,怎样计算读了...答:用CFile类的read()函数;他的到返回值就是已经读的子符个数如CFf.open("d://1.txt",可读可写);charsz[256]={0};inti=f.read(sz,256)//这里的就是读取的个数.这里你可以看看一行多少字符数256可以改20看情况VC如何得到某一个进程数量?问:我打开了3个程序a.exe,那么在任务管理器里面可以看到3个a.exe在运行...答:简单办法没有。只有枚举进程,然后OpenProcess,再比较进程名。可参考:#include#include#include#include"psapi.h"voidPrintProcessNameAndID(DWORDprocessID){TCHARszProcessName[MAX_PATH]=TEXT("");//Getahandletothe...VC读取数据源列表和驱动程序列表(图1)VC读取数据源列表和驱动程序列表(图2)VC读取数据源列表和驱动程序列表(图3)VC读取数据源列表和驱动程序列表(图4)VC读取数据源列表和驱动程序列表(图5)VC读取数据源列表和驱动程序列表(图6)VC如何得到某一个进程数量?问:我打开了3个程序a.exe,那么在任务管理器里面可以看到3个a.exe在运行...答:简单办法没有。只有枚举进程,然后OpenProcess,再比较进程名。可参考:#i防抓取,真格学网提供内容。==========以下对应文字版==========vc怎么读取txt列数据问:比如data.txt中两列,空格隔开12.212.312.412.51415.2.........答:vc++读取txt文件中数据代码如下:CStdioFilemReadF防抓取,真格学网提供内容。
数据源信息存放在
vc++编程,怎么文件读取数据?问:我要做一个函数模型,就是利用一大堆数据去推一个公式,我是刚接触vc,...答:在C++中,有一个stream这个类,所有的I/O都以这个“流”类为基础的,包括我们要防抓取,真格学网提供内容。HKEY_LOCAL_MACHINE\SOFTWARE\ODBC\ODBC.INI
VC怎么访问硬件信息,读取数据问:1、我现在有一个USB键盘,键盘上面有计算器和小屏幕,当计算后,键盘上...答:1、键盘上的计算器你是读不出来的(除非它提供的了接口指令),因为它本身是一个单片机。如防抓取,真格学网提供内容。
驱动程序信息存放在
vc++怎样从excel文件中读写数据问:vc++2008中的一个c++控制台程序,需要从excel文件中读入几列和几行数据...答:转载:首先利用VisualC++6.0,建立一个MFC基于对话框的防抓取,真格学网提供内容。HKEY_LOCAL_MACHINE\SOFTWARE\ODBC\ODBCINST.INI
VC读取内存数据?问:读取内存数据我想查找有没有我指定的进程...if!=NULL就把它给从内存...答:随便看到你提的这个问题.如果是读取内存,你直接读就行了.关键是范围和具体的位置问题.如果进程是防抓取,真格学网提供内容。附:
HKEY hKvc6.0如何读取excel数据到listctrl列表中真晕倒~,你的连接字符串错了首先provider&你的拼写就错了,你写成rovider&第二,你连接oracle,你用sql防抓取,真格学网提供内容。
RegOpenKeyEx(HKEY_LOCAL_MACHINE,&SOFTWARE\\ODBC\\ODBC.INI&,0,KEY_READ,&hKey);matlab读取数据,结束后为何vc读取还会出错数据试试看就清楚了fclose(s);//关闭串口//其他命令instrfind//列出当前的串口,和状态...fclose(instrfind)//关防抓取,真格学网提供内容。
DWORD dwSubKeyCount,dwMaxSubKeyNameLVC读取SQLite数据库中的表的数据,该怎么解决BYname&,&dbResult,&row,&col,&szError);if(result==SQLIT防抓取,真格学网提供内容。
RegQueryInfoKey(hKey,NULL,NULL,NULL,&dwSubKeyCount,&dwMaxSubKeyNameLength,NULL,NULL,NULL,vc异步读取串口数据超时问题?vc写软件太费周章,用.net的C#,SerialPort控件很好用。有些很好的串口软件,也是基于.net的。防抓取,真格学网提供内容。NULL,NULL,NULL);vc读取txt中用逗号隔开的数据,并赋给变量#include#include#include&iostream.h&main(){t;iostream.h&main(){防抓取,真格学网提供内容。
long index = 0;VC++中关于读取文本文件内容然后通过列表控件逐行输出的问...先找到空格的位置比如为iSpaceI以空格为界线,把整个字符分成两个小字符串比如这是一行数据:Cont_File/&#防抓取,真格学网提供内容。
char* szSubKeyName = new char[dwMaxSubKeyNameLength+1];请问如何用VC连接数据库并读取SQLServer数据库中的数据在新建的工程中选择有数据库支持,点那个数据源按钮然后选择要你使用的数据库,将你...选择你在该模块中要使用的数据库,然后在其后的编程中调用防抓取,真格学网提供内容。
DWORD dwSubKeyNVC读取内存数据?随便看到你提的这个问题.如果是读取内存,你直接读就行了.关键是范围和具体的位置问题.如果进程是指定的,直接openprocess,....然后....再....去读就行了.ifpId防抓取,真格学网提供内容。
for (index=0;index&(long)dwSubKeyCindex++)如何在vc中读取oracleclob类型的数据?数据。第三种OO4O,照着oracle安装后给出的读clob类型的例子写的,连数据库都打不开。ODOStartup();intn=防抓取,真格学网提供内容。
{ RegEnumKeyEx(hKey,index,szSubKeyName,&dwSubKeyName,NULL,NULL,NULL,NULL);如何取得vc列表控件中的数据,列表控件为报告形式,用GetItemT...for(n;n&m_LIST.GetItemCount();n++)//取列表数据{filepath=m_LIST.Ge防抓取,真格学网提供内容。
RegCloseKey(hKey);防抓取,真格学网提供内容。
RegOpenKeyEx(HKEY_LOCAL_MACHINE,&SOFTWARE\\ODBC\\ODBC.INI\\ODBC Data Sources&,0,KEY_RE姚明当年为什么拒绝澳大利亚美女队长的示爱?姚明不只球打的好,智商也高,情商也高,从其多次公开讲话就可以看出。现在来看,假如当初娶了劳伦斯,小孩也是外国籍,这对其中国身份有影响,现在也不可能做篮协主席。防抓取,真格学网提供内容。AD,&hKey);啥攻陷不攻陷的,江苏卫视又不是郭德纲开的,人家江苏台的实力可比郭德纲大多了,纵然郭德纲是大腕,也得乖乖听电视台的安排。所以请谁去表演节目电视台有自己的考虑和选择,而不会考虑谁是谁的对头,最多不会让郭德防抓取,真格学网提供内容。
DWORD dwValueCount,dwMaxValueNameL齐达内的执教能力,在皇马可以印证是不弱的,但是说到所谓的执教水平,还有待时间的进一步检验。皇马如今意气风发,一来皇马的牌面实力确实傲视天下,二来齐达内对于球队的掌控力可以让每一个皇马球员发挥出自己应有防抓取,真格学网提供内容。
RegQueryInfoKey(hKey,NULL,NULL,NULL,NULL,NULL,NULL,&dwValueCount,&dwMaxValueNameLength,NULL(我们在山里拍摄)关于候鸟的纪录片对设备的要求还是比较高的。我正在拍黑颈鹤等鸟类的纪录片,因为国内的候鸟大都受到过人类的攻击,所以对待人类的心理很是谨慎,一般很那接近。比如说黑颈鹤,在春天交配季节和夏防抓取,真格学网提供内容。,NULL,NULL);
谢邀!直线行驶确实是困挠广大考生的一道难关,特别是对方向感很差的考生。那么,怎么确保直线行驶不出问题呢?在回答这个问题前,我们先来了解直线行驶的考试要求:1,直线行驶过程中不能压左右边缘线,2,行驶中防抓取,真格学网提供内容。
char* szValueName = new char[dwMaxValueNameLength+1];这个我有特意研究过,一般有骨盆前倾的人都有这个问题,我前女友就不能做“亚洲蹲”她骨盆前倾,而且她遗传她妈,同样她妈也是骨盆前倾的,一样不能蹲。得垫着脚或者穿高跟坡跟鞋。骨盆前倾的人臀部看上去很翘,屁股防抓取,真格学网提供内容。
DWORD dwValueN如今流传下来的佛经,都是佛陀但是弘法时所讲的内容,弟子们记录下来的。至于佛陀是不是也用佛珠,最早关于佛珠的记载是《木槵子经》:佛告王言:若欲灭烦恼障、报障者,当贯木槵子一百八,以常自随;若行、若坐、若防抓取,真格学网提供内容。
for (index=0;index&(long)dwValueCindex++)翡翠和绿松石哪个更好,翡翠和绿松石有什么不同?松玉堂来告诉你!翡翠被誉为“硬玉之王”,一直以来都备受喜爱。而绿松石作为古老宝石之一,同样是广大收藏爱好者的心头好。今天,松玉堂就来聊一聊,翡翠和绿松石的防抓取,真格学网提供内容。
{ RegEnumValue(hKey,index,szValueName,&dwValueName,NULL,NULL,NULL,NULL); 我吃过新鲜的无花果,新鲜的口感不是很好,有一点点甜,其实大部分都没有味道,闻起有一点点清香味,反正我不喜欢吃。区别:新鲜的更水润,而且在治疗和营养价值上肯定是优于干果的。所以,在鲜果上市时最好用鲜果防抓取,真格学网提供内容。
RegCloseKey(hKey);防抓取,真格学网提供内容。
当前打开键的句柄或下列预定义保留的句柄值: 呵呵,我可以负责任的告诉你,没有任何看点!我是大年初六去看的《大闹天竺》。这片儿的后劲儿太足槽点太多,真是不吐不快。  (一)  马蓉给了王宝强一点绿色,他用来开了个印度染坊。  玩儿色彩,像张艺谋在防抓取,真格学网提供内容。
HKEY_CLASSES_ROOT手机内存满了,可以先清理一下内存。一般腾讯的软件占内存比较大,腾讯里有qq和微信。qq和微信里都有头像缓存,还有看过的照片视频之类的都缓存下来了,需要的请保存下来,不需要的清理。其二,照片。把以前的老防抓取,真格学网提供内容。
HKEY_CURRENT_CONFIG卧室是我们睡觉的地方,在风水学中,床的摆放会在一定程度上影响人的气运、健康等,好的摆放能够给人带来好运和健康的身体等。所以我们一起来看看床的摆放的最好位置,和床的摆放禁忌吧。床头的摆放朝哪个方向好?床防抓取,真格学网提供内容。
HKEY_CURRENT_USER如果你不玩大型游戏的话,主要的区别还是在以下几方面。1、屏幕显示效果和色彩还原度。一般贵的手机用的屏幕色彩还原度都比较高,效果也比较艳丽清晰,而千元机的屏幕色彩会偏淡,不够饱满,同样是1080P分辨率防抓取,真格学网提供内容。
HKEY_LOCAL_MACHINE恒大引进罗本的几率几乎为零,为什么这么说呢?首先罗本的年龄不符合恒大的引援邀请,罗本已经34岁了,恒大鲜有引援超过30岁的先例,穆里奇是因为和刘永灼有三年之约在前,也是出去球队建设的需要,罗比尼奥呢也防抓取,真格学网提供内容。
HKEY_USERS咱大保定有20个世界冠军、30个亚洲冠军130多个全国冠军光奥运金牌,手里就有6块!郗恩庭他是保定历史上第一个世界冠军。作为一名乒乓球运动员,他在上个世纪七十年代曾称霸世界乒坛。他是第32届世乒赛男单防抓取,真格学网提供内容。
samDesired 不一定,但总的来说,时间越久的,通常会比时间短的更有收藏价值。具体与该纪念币的发行量、题材热度、历史损耗量或流通量有关。八十年代的纪念币和邮票,尤其是80年代初期的,发行量相对比较小,很多品种的收藏价防抓取,真格学网提供内容。
制定?个访问标记以描述访问新键的安全性富贵竹喜温暖、湿润环境,对光照要求不高,夏季需要遮阳。夏天生长较快,要勤浇水,常向叶面喷水,不要见干再浇。冬季要做好保暖工作,降低浇水次数。水培富贵竹注意事项:1、剪枝:45°斜向上剪枝,可以扩大枝条防抓取,真格学网提供内容。
此参数可以是下列值的?个联合 今日头条问答时尚频道的粉丝,你好!iEVER美课很高兴为你解答,分享实用的观点~,遇见最美的自己~(打字不容易,还请多多点赞评论支持噢~)啦啦啦,下面iEVER美课来为大家来解答#最强美妆#无妆胜有妆防抓取,真格学网提供内容。
KEY_ALL_ACCESS张家界和九寨沟,哪个更好玩?都去过N次。之所以能去N次,是因为这两地都不是普通景区,而是超大型世界级自然遗产、国家级5A自然风景保护区。名头、地位相当。但是,这两地不在一个量级,不好比较。九寨沟一瞥。防抓取,真格学网提供内容。
KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS, KEY_NOTIFY, KEY_CREATE_SUB_KEY, KEY_CRE很多,做营销得时刻关注现下社会动态,涉及面也比较广,大概我分成以下几点:1.36kr,梅花,it桔子……这几个都是看一些营销资讯与最新案例、营销动态的。2.一般做营销的还要学东西,所以就得备有一些营销防抓取,真格学网提供内容。ATE_LINK, 和 KEY_SET_VALUE 访问的联合. 提起星女郎林允,少女与清新二词少不了,她甜美的气场不具侵略性反倒灿烂明媚,让人感觉舒心,对着镜头浅浅一笑,便能轻松成为焦点。成为星女郎后衣品也是不断提升。虽然身材比例不算完美,但林允懂得扬长避短,照样防抓取,真格学网提供内容。
KEY_CREATE_LINK说粤菜难吃,可能算不上吧!吃不惯可能会有。我只知道湖南人很多时候会觉得粤菜没味道,像我之前的一个同事,每次跟他出去吃饭,肯定要看看桌面上有没有备辣椒,如果这桌没有就四周看看其它桌,有就准备着随时要借一防抓取,真格学网提供内容。
允许创建严格符号的链接. 作为多年的HR,对职业大典还是比较了解的。我是职场火锅,专门涮职场的,回答这个问题如下:首先不要歧视农民工,农民工的收入不比一些工种低的。农民工都是计件的,一天200元,一个月就是6000元,不低。但防抓取,真格学网提供内容。
KEY_CREATE_SUB_KEY马东许知远对话,高下不论。许是个陈腐的知识份子,在自己的角落里保持对时代的距离、固执己见,是好的思想者,但不是好的采访者和对话者;如果他逃避技术,认为技术毁灭人类,为什么做这个新媒体视频节目呢?马东的防抓取,真格学网提供内容。
允许创建子键 . 我不知道你清不清楚一个词叫做国际化,华为手机,不仅是在国内,在国外也有很多的消费者关注。在国外如果在手机上写上华为的中文的话,会有很多人看不懂。用英文LOGO就比较好理解了外国人就知道这个是华为。其实防抓取,真格学网提供内容。
KEY_ENUMERATE_SUB_KEYS小米,一家改变了智能时代的公司。在前年,小米推出了小米手环,小米手环1的推出版本是有两个的,一个是普通的,定价69元。一个是光感版,定价99元。小米手环的推出,销量是火爆的。就连当时我的同学在学校不上防抓取,真格学网提供内容。
允许枚举子键 . 最近的章泽天有点开挂,戛纳电影节、高定时装周,每次亮相都颇为惊艳,这位93年已为人妻人母的妹纸的华丽转变可以说非常成功了,现在的你提到她时是想起那位手拿奶茶的清纯少女,还是清华的最美校花,或是在各种高防抓取,真格学网提供内容。
KEY_EXECUTE这个问题问得尴尬,总感觉世界上这么多的女人,没有一个敢说自己是最会收纳的。毕竟漂亮的女人太多,懒惰的女人更多啊。去到美女家里,乱七八糟的多了去了。所以嘛,美女还是需要学习下怎么收拾的。家里人多,每个人防抓取,真格学网提供内容。
允许读访问.
KEY_NOTIFY
允许改变通知.
KEY_QUERY_VALUE
允许查询子键的数据.
KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS, 和 KEY_NOTIFY 访问的联合.
KEY_SET_VALUE
允许设置子键的数据.
KEY_SET_VALUE 和 KEY_CREATE_SUB_KEY 访问的联合.
LONG RegOpenKeyEx(
HKEY hKey,// 待打开的键的句柄
LPCTSTR lpSubKey,
// 待打开的子键名称的地址
DWORD ulOptions,
// 保留的,必须为0.
REGSAM samDesired,
// 安全访问标记
PHKEY phkResult // 待打开的键的句柄的地址
LONG RegQueryInfoKey(
HKEY hKey,// 待查询的键的句柄
LPTSTR lpClass, // 类字符串缓冲器地址
LPDWORD lpcbClass,
// 类字符串缓冲器大小的地址
LPDWORD lpReserved,
// 保留的,必须为 NULL.
LPDWORD lpcSubKeys,
// 子键数目缓冲器的地址
LPDWORD lpcbMaxSubKeyLen, // 最长的子键名称长度缓冲器的地址
LPDWORD lpcbMaxClassLen, // 最长的类字符串长度缓冲器的地址
LPDWORD lpcValues,
// 值项数目缓冲器的地址
LPDWORD lpcbMaxValueNameLen,
// 最长的值名称长度缓冲器的地址
LPDWORD lpcbMaxValueLen, // 最长的值数据长度缓冲器的地址
LPDWORD lpcbSecurityDescriptor,
// 安全描述符长度缓冲器的地址
PFILETIME lpftLastWriteTime // 最近写入时间缓冲器的地址
LONG RegEnumKeyEx(
HKEY hKey,// 待枚举的键的句柄
DWORD dwIndex, // 待枚举的子键的索引
LPTSTR lpName, // 子键名称缓冲器的地址
LPDWORD lpcbName,
// 子键缓冲器大小的地址
LPDWORD lpReserved,
// 保留的,必须为 NULL.
LPTSTR lpClass, // 类字符串缓冲器的地址
LPDWORD lpcbClass,
// 类缓冲器大小的地址
PFILETIME lpftLastWriteTime // 键的最近写入时间的地址
vc怎么读取txt列数据问:比如data.txt中两列,空格隔开12.212.312.412.51415.2.........答:vc++读取txt文件中数据代码如下:CStdioFilemReadFile2;CStringstr1;mReadFile2.Open("a.txt",CFile::modeRead|CFile::typeText);while(mReadFile2.ReadString(str1)==TRUE){AfxMessageBox(str1);}mReadFile2.Close();vc++编程,怎么文件读取数据?问:我要做一个函数模型,就是利用一大堆数据去推一个公式,我是刚接触vc,...答:在C++中,有一个stream这个类,所有的I/O都以这个“流”类为基础的,包括我们要认识的文件I/O,stream这个类有两个重要的运算符:1、插入器(VC怎么访问硬件信息,读取数据问:1、我现在有一个USB键盘,键盘上面有计算器和小屏幕,当计算后,键盘上...答:1、键盘上的计算器你是读不出来的(除非它提供的了接口指令),因为它本身是一个单片机。如果你想直接输出到文本,比较麻烦:可以记录键值后台模拟键盘计算器操作并输出。2、如果键盘驱动已加载,一般来说功能按键已能使用,如果你需要捕获键...vc++怎样从excel文件中读写数据问:vc++2008中的一个c++控制台程序,需要从excel文件中读入几列和几行数据...答:转载:首先利用VisualC++6.0,建立一个MFC基于对话框的工程项目,共享DLL,Win32平台。工程名称ExcelTest。在主对话框中加入一个按钮,IDIDC_EXCELTESTCaptionTestExcel双击该按钮,增加成员函数voidCExcelTestDlg::OnExceltest()。...
猜你还喜欢当前位置: >>
一步一步学Django
一步一步学 Django第1 页第一讲1 开篇入门Django 是新近出来的 Rails 方式的 web 开发框架。在接触 Django 之前我接触过其它几种 Python 下的 web framework, 但感觉 Karrigell 是最容易上手的。 不过 Django
从我个人的感觉 上来看,它的功能更强大,社区也很活跃,高手众多,发展也是极为迅速。3Django 的入门体验但 Django 呢?如果说最简单的 web 体验 Hello, Django! 如何写呢?决不会象 Karrigell 那样简单,只从它提供的教程来看,你无法在安装后非常 Easy 地写出一个 Hello, Django! 的例 子,因为有一系列的安装和准备工作要做。那么下面我把我所尝试写最简单的 Hello, Django! 的 例子写出来。请注意,我测试时是在 Windows XP 环境下进行的。3.1安装python setup.py install参考文档 Django installed,一般地,Django 安装前还需要先安装 setuptools 包。可以从 PyPI 上搜到。 目前最新的版本是 0.95 版, 可以从 Django 的主页上面下载。 如果你想从老的 0.91 迁移到最新版本,可以参阅 RemovingTheMagic 文档。安装后,建议检查 pythoninstalldir/Scripts 目录是否在你的 PATH 环境中,如果不在,建议将这个目录设置到 PATH 中。因为如果你采用标准 的 Python 安装方法, 那么 Django 会自动在 Scripts 目录下安装 django-admin.py 程序。 这样, 一旦你设置了 Scripts 在 PATH 中,就可以在命令行下任何目录中执行 django-admin.py 了。3.2生成项目目录因为 Karrigell 可直接开发,因此放在哪里都可以。而 Django 是一个框架,它有特殊的配 置要求,因此一般不需要手工创建目录之类的工作, Django 提供了 django-admin.py 可以做这 件事。为使用 django-admin.py ,建议将 Python 的 Scripts 目录加入到 PATH 环境变量中去。 django-admin.py startproject newtest 这样就在当前目录下创建了一个 newtest 目录,进去入可以看到有四个文件:这个 newtest 将是我们以后工作的目录,许多讲解都是基于这个目录的。 __init__.py 表示这是一个 Python 的包 manage.py 提供简单化的 django-admin.py 命令, 特别是可以自动进行 DJANGO_SETTINGS_MODULES 和 PYTHONPATH 的处理,而没有这个命令,处理上面环境变量是件麻烦的事情 settings.py 它是 django 的配置文件 uls.py url 映射处理文件, Django 的 url 映射是 url 对某个模块方法的映射, 目前不能自动完成 在 0.91 版, django-admin.py startproject 会生成 apps 目录。但 0.95 版之后已经没有 了。 虽然 django-admin.py 为我们生成了许多东西,而且这些东西在以后的开发中你都需要熟悉, 但现在我们的目标是最简单的体验,就认为我们不需要知道它们都有什么用吧。 项目创建好了,那么我们可以启动服务器吗? Django 为了开发方便,自带了一个用于开发的 web server。在 0.91 版,你需要至少修改一下 settings.py 中的 DATABASE_ENGINE ,如果你不 改,那么 Django 会报错。在 0.95 版之后,不再需要设置了。3.3.1 3.3.1server: 启动 web server:别急呀,还没看见 Hello, Django! 在哪里呢。是的,我只是想看一看, Django 能否启动。 manage.py runserver 一步一步学 Django第2 页一旦出现: Validating models... 0 errors found. Starting server on port 8000 with settings module 'newtest.settings'. Go to http://127.0.0.1:8000/ for Django. Quit the server with CONTROL-C (Unix) or CTRL-BREAK (Windows). 说明 Django 真的启来了。在浏览器中看一下,有一个祝贺页面,说明成功了。3.3.2 更改主机或端口默认情况下, runserver 命令在 8000 端口启动开发服务器,且只监听本机连接。要想要更改服务器端口的话,可将端 口作为命令行参数传入:python manage.py runserver 8080还可以改变服务器监听的 IP 地址。要和其他开发人员共享同一开发站点的话,该功能特别有用。下面的命令:python manage.py runserver 0.0.0.0:8080会让 Django 监听所有网络接口,因此也就让其它电脑可连接到开发服务器了3.4helloworld 增加一个 helloworld 的 app 吗?在 Django 中绝大多数应用都是以 app 形式存在的, 但一定要加吗?其实并不一定。 Django 在 中,每个 app 就是一个子包,真正调用时需要通过 URL Dispatch 来实现 url 与模块方法的映射。 这是 Django 的一大特色, 但也是有些麻烦的地方。 不用它, 你无法发布一个功能, 如果在 Django 中存在一种缺省的简单映射的方式, 这样我想可以大大提高 Django 的入门体验度。 不过在比较大 的项目中,使用 app 还是一个非常好的方式,它可将项目功能进行分割,以便组织和代码的重用。 因此根据 URL Dispatch 的机制,我们只要保证 Django 可以在正确的地方找到方法进行调用即 可。 那么我们就根本不去创建一个 app 了。 newtest 目录下建一个文件 helloworld.py 内容为: 在 from django.http import HttpResponse def index(request): return HttpResponse(&Hello, Django.&) 0.95 版之后对许多 Django 模块都做了简化。 具体可参考: NamespaceSimplification 文档。3.5修改 urls.pyfrom django.conf.urls.defaults import * urlpatterns = patterns('', # Example: # (r'^newtest/',include('newtest.apps.foo.urls.foo')), (r'^$', 'newtest.helloworld.index'), 一步一步学 Django第3 页# Uncomment this for admin: #(r'^admin/', include('django.contrib.admin.urls')), ) 上面的 r'^$' 是为了匹配空串,也就是形如: http://localhost:8000/ 。如果这时 web server 已经启动了,那么直接刷新页面就行了。现在觉得 Django 是不是简单多了,除了创建一 个项目的操作,然后可能要修改两个配置文件。4结论Django 本身的确是一种松散的框架组合,它既复杂又简单。复杂是因为如果你想使用它的自 动化的、 高级的功能你需要学习很多的东西, 而且它的教程一上来就是以这种过于完整的例子进行 展示,自然会让你觉得很麻烦。不过看了我的讲解之后,是不是觉得还是挺简单的。那么我们就先 以无数据库的方式进行下去,一点点地发掘 Django 的功能特性吧。第二讲 生成一个 web form 做加法的简单例子1 引言随着学习,我们的例子也开始复杂了,下一步我想实现一个简单的 web 加法器。界面会是这 样:如何处理页面表格提交的数据,并且会对 URL Dispatch 作更进一步的解释。2创建 add.py 文件我们先创建一个 add.py 文件。(由于我们还没有涉及到 Django 的模型,因此象 add.py 这 样的东西叫什么呢?还是称其为 View 吧。因为在 django 中,View 是用来显示的,它代替了一 般的 MVC 中的 Control 的作用,因为 Django 中不是 MVC 而是 MTV (Model Template View)) from django.http import HttpResponse text = &&&&form method=&post& action=&/add/&&&input type=&text& name=&a& value=&%d&& + &input type=&text& name=&b& value=&%d&& &input type=&submit& value=&=&& &input type=&text& value=&%d&&&/form&&&& def index(request): if request.POST.has_key('a'): a = int(request.POST['a']) b = int(request.POST['b']) else: a = 0 b = 0 return HttpResponse(text % (a, b, a + b)) 请注意 action 为 /add/ , Django 中链接后面一般都要有 '/' , 在 不然有可能得不到 POST 数据。有关更详细的关于常见问题可以参阅 NewbieMistakes 文档。 这里只有一个 index 方法。所有在 view 中的方法第一个参数都会由 Django 传入 request 对象,它就是请求数据对象,它是由 Django 自动生成。其中有 GET 和 POST 属性,分别保存两 种不同的提交方式的数据,它们都可以象字典一样工作。更多关于 request 的内容参见 Request and response objects 文档。 那么我的想法就是:进入页面后(就是上面的效果),页面上有两个输入文本框,一个是提交按 钮,一个是显示结果的文本框。在两个输入文本框中输入整数,然后点击提交(&=&号按钮),将返 回相同的页面,但结果文本框中将显示两数相加的和。两个输入文本框分别定义为 a 和 b 。这里 的逻辑就是:先判断 POST 数据中是否有变量 a ,如果没有则表示是第一次进入,则 a, b 初始 为 0 ,然后返回页面。如果有变量 a ,则计算结果,返回页面。3urls.py, 修改 urls.py,增加 add 的 url 映射。 一步一步学 Django第4 页from django.conf.urls.defaults import * urlpatterns = patterns('', # Example: # (r'^testit/', include('newtest.apps.foo.urls.foo')), (r'^$', 'newtest.helloworld.index'), (r'^add/$', 'newtest.add.index'), # Uncomment this for admin: # (r'^admin/', include('django.contrib.admin.urls')), ) 4 5 6 1. 启动 server 在浏览器测试:http://localhost:8000/add,你会看到和我相似的界面, 然后输入整数试一试。 补充说明 在 form 中的 method=&post& 。 你当然可以使用 get , 但是在 Django 的设计风格中认为, 使用 POST 表示要对数据进行修改,使用 GET 则只是获取。 2. Django 提供了 URL Dispatch 文档,专门讲解有关 url 映射的东西。其中有一部分是关于 url 的正则表达式解析的。原本我认为象 Karrigell 中一样,定义在 form 中的变量会自动 映射为方法的参数,但是我错了。方法中的参数是从 url 中通过正则表达式解析出来的,或 者是在 url_conf(即 urls.py 文件)中指定的。因此它与 Karrigell 一点也不一样。因此, 如果你想从 POST 或 GET 数据中得到值,那么象我一样去做好了。使用 request.POST 或 request.GET 或还有一个可以“统吃”的方法 request.REQUEST ,它们是一个字典数据,使 用起来也算方便。从这里我更想了解方法中参数的使用,当然这个例子并没有,有机会再使用吧。关于正则表达 式解析参数在 blog 和 rss 中用得是非常多的。第三讲 使用 Template 的简单例子1 引言从上一例我们看到,表格的生成是直接在 index() 函数中返回的 HTML 代码,这种混合方式 对于大型开发非常不好,下面我们就学习模板的使用。 Django 自带有模板系统,但你可以不使用 它,只要在 return 前使用自已喜欢的模板系统进行处理,然后返回即可。但 Django 自带的模板 系统有很多特点, 我不做过多的说明。 我只是想使用它。 现在我的问题就是: 我有一个通讯录数据, 我想使用一个表格来显示。为了方便,我们不需要使用数据库,因此我把它存在 view 文件中。2创建 list.py#coding=utf-8 from django.shortcuts import render_to_response address = [ {'name':'张三', 'address':'地址一'}, {'name':'李四', 'address':'地址二'} ] def index(request): return render_to_response('list.html', {'address': address})我使用了汉字,并且字符的编码使用了 utf-8 ,请注意,而且以后如果不特别注明,所有的 带汉字的文件,包括模板都将使用 utf-8 编码。 这里使用了一个新方法是 render_to_response ,它可以直接调用模板并返回生成好的文本。 它接收两个参数,第一个是模板的文件名。在 Django 0.91 中,模板文件都是以 .html 结尾的, 并且使用时是不带后缀的。 0.95 版本取消了缺省模板后缀的设置, 但 因此模板文件名必须是完整 的,不再有默认后缀了。第二个参数是一个字典,这里只有一个 Key ,名字是 address ,它的值 是一个字典的列表。只要注意模板所接收的就是这样的字典和包含字典的列表就行了。在 0.91 中 一步一步学 Django第5 页render_to_response 是在 django.core.extensions 中的,而到了 0.92 转变为 django.shortcuts 。3 4目录: 在 newtest 中创建 templates 目录:用来存放模板文件 修改 settings.pyTEMPLATE_DIRS = ( # Put strings here, like &/home/html/django_templates&. # Always use forward slashes, even on Windows. './templates', )如果有多个模板目录,加进去就行了。 Django 会按顺序搜索的。Django 还支持在 App 中定 义一个 templates 目录。这样 Django 在启动时会检查所有安装的的 App 的 templates 目录, 如果存在,则将路径的搜索放在 TEMPLATE_DIRS 之后。这样就可以很方便地管理你的模板了。5创建 templates/list.html&h2&通讯录&/h2& &table border=&1&& &tr&&th&姓名&/th&&th&地址&/th&&/tr& {% for user in address %} &tr& &td&{{ user.name }}&/td& &td&{{ user.address }}&/td& &/tr& {% endfor %} &/table&生成了一个两列的表格。在 Django 模板中 {{}} 表示引用一个变量, {%%} 表示代码调用。 在变量引用中, Django 还支持对变量属性的访问,同时它还有一定的策略,详细的建议查看 The Django template language 文档。这里我也使用了汉字,因此它也需要使用 utf-8 编码。 这里使用 for .. in 的模板 Tag 处理。因此 address 需要是一个集合。在我们的 View 代 码中, address 为一个 list 值。每个 list 又是一个字典。因此 {{ user.name }} 和 {{ user.address }} 就是将此字典中的元素取出来。后面我们将了解更多的模板中的 Tag 标签的 使用。且你会发现, Django 中的 Tag 很强大,可通过扩展形成庞大的 Tag 库方便模板的开发。6修改 urls.py 增加了 list 的 url 映射。from django.conf.urls.defaults import * urlpatterns = patterns('', # Example: # (r'^testit/', include('newtest.apps.foo.urls.foo')), (r'^$', 'newtest.helloworld.index'), (r'^add/$', 'newtest.add.index'), (r'^list/$', 'newtest.list.index'), # Uncomment this for admin: # (r'^admin/', include('django.contrib.admin.urls')), )7server: 启动 server:http://127.0.0.1:8000/list,效果如这样:第四讲 生成 csv 格式文件并下载1 引言 一步一步学 Django第6 页经过前几节的学习,我想大家应该比较熟悉 Django 的大致开发流程了:? ? ?增加 view 方法 增加模板 修改 urls.py剩下的就是挖掘 Django 提供的其它的能力。在我们还没有进入模型(model)之前还是再看一 看外围的东西,再更进一步体验 Django 吧。在 Django 中我看到了一个生成 csv 格式的文档 (Outputting CSV dynamically),非常好,它没有数据库,正好用来做演示。现在我的需求就是提 供 csv 格式文件的下载。 我们会在原来 list(表格) 例子基础上进行演示, 步骤就是上面的流程。2修改 templates/list.html在文件最后增加: &p&&a href=&/csv/address/&&csv 格式下载&/a&&/p& 它将显示为一个链接,它所指向的链接将用来生成 csv 文件。3在 newtest 下增加 csv_test.py#coding=utf-8 from django.http import HttpResponse from django.template import loader, Context address = [ ('张三', '地址一'), ('李四', '地址二') ] def output(request, filename): response = HttpResponse(mimetype='text/csv') response['Content-Disposition'] = ' filename=%s.csv' % filename t = loader.get_template('csv.html') c = Context({'data': address,}) response.write(t.render(c)) return responseloader, Context 是从 django.core.template 导入的,而 0.95 为 django.template 。具 体可以参考: NamespaceSimplification 文档。以后类似的地方不再详述。 这里使用的东西多了一些。这里没有 render_to_response 了,而是演示了一个完整的从头进 行模板解析的处理过程。为什么需要这样,因为我们需要修改 response 对象的值,而 render_to_response 封装了它使得我们无法修改。从这里我们也可以看到,在调用一个方法时, Django 会传入一个 request 对象,在返回时,你需要将内容写入 response ,必要时修改它的某 些属性。 更详细的建议你参考 django 所带的 request_response 文档, 里面详细描述了两个对象 的内容,并且还可以在交互环境下进行测试,学习非常方便。response 对象也是由 Django 自动 维护的。具体的内容参见 Request and response objects 文档。 这里 address 不再是字典的列表,而是 tuple 的列表。让人高兴的是, Django 的模板除了 可以处理字典,还可以处理序列,而且可以处理序列中的元素。一会在模板定义中我们会看到。 这里 output() 是我们希望 Django 调用的方法, 不再是 index() 了。 而且它与前面的 index() 不同,它带了一个参数。这里主要是想演示 url 的参数解析。因此你要注意,这个参数一定是放 在 url 上的。它表示输出文件名。 response = HttpResponse(mimetype='text/csv') response['Content-Disposition'] = ' filename=%s.csv' % filename 这两行是用来处理输出类型和附件的。它表明返回的是一个 csv 格式的文件。 一步一步学 Django第7 页t = loader.get_template('csv.html') c = Context({'data': address,}) response.write(t.render(c)) 这几行就是最原始的模板使用方法。先通过 loader 来找到需要的模板,然后生成一个 template 对象,再生成一个 Context 对象,它就是一个字典集。然后 t.render(c) 这个用来对 模板和提供的变量进行合并处理,生成最终的结果。最后调用 response.write() 将内容写入。4增加 templates/csv.html{% for row in data %}&{{ row.0|addslashes}}&, &{{ row.1|addslashes}}&, {% endfor %}使用了一个 for 循环。这里 data 与上面的 Context 的 data 相对应。因为 data 是一个列 表,它的每行是一个 tuple ,因此 row.0, row.1 就是取 tuple 的第一个和第二个元素。 | 是 一个过滤符,它表示将前一个的处理结果作为输入传入下一个处理。因此 Django 的模板很强大, 使用起来也非常直观和方便。 addslashes 是 Django 模板内置的过滤 Tag ,它用来将结果中的 特殊字符加上反斜线。同时我们注意到,每个 {{}} 前后都有一个双引号,这样就保证每个字符串 使用双引号引起来。然后在第一个与第二个元素之间还使用了逗号分隔。最后 endfor 在下一行, 表示上面每行模板后有一个回车。Django 还允许你自定义 Tag ,在 The Django template language: For Python programmers 文档中有描述。5修改 urls.pyfrom django.conf.urls.defaults import * urlpatterns = patterns('', # Example: # (r'^testit/', include('newtest.apps.foo.urls.foo')), (r'^$', 'newtest.helloworld.index'), (r'^add/$', 'newtest.add.index'), (r'^list/$', 'newtest.list.index'), (r'^csv/(?P&filename&\w+)/$', 'newtest.csv_test.output'), # Uncomment this for admin: # (r'^admin/', include('django.contrib.admin.urls')), )增加了 csv 的 url 映射。上面的正则表达式有些复杂了,因为有参数的处理在里面。 (?P&filename&\w+) 这是一个将解析结果起名为 filename 的正则表达式, 它完全符合 Python 正 则表达式的用法。在最新的 Django 中,还可以简化一下: (\w+) 。但这样需要你的参数是按顺 序传入的, 在一个方法有多个参数时一定要注意顺序。 关于 url 的配置问题在 URL configuration 文档中有说明。还记得吗?我们的链接是写成 /csv/address/ ,因此上面实际上会变成对 csv.output(filename='address') 的调用。server: 6 启动 server:看一下结果吧。点击链接,浏览器会提示你保存文件的。很简单吧。但这里 面的内容其实也不少,而且许多地方都有很大的扩展空间。第五讲 session 和数据库1 引言现在我们就学习一下 session 吧。 session 可以翻译为“会话”,做过 web 的可能都知道。 它就是为了实现页面间的数据交换而产生的东西, 一般有一个 session_id , 它会保存在浏览器的 cookie 中,因此如果你的浏览器禁止了 cookie ,下面的试验是做不了的。在 Django 中的 session 也非常简单, 它就存在于 request 对象的 session 属性中。 你可以把它看成一个字典就 可以了。下面我们做一个非常简单的功能:首先当用户进入某个页面,这个页面会显示一个登录页 一步一步学 Django第8 页面,上面有一个文本框用来输入用户名,还有一个提交按钮用来提交数据。当用户输入用户名,然 后点提交,则显示用户已经登录,并且打印出用户的姓名来,同时还提供一个“注销”按钮。然后 如果用户再次进入这个页面, 则显示同登录成功后的页面。 如果点击注销则重新进入未登录的页面。2在 newtest 下创建 login.pyfrom django.http import HttpResponseRedirect from django.shortcuts import render_to_response def login(request): username = request.POST.get('username', None) if username: request.session['username'] = username username = request.session.get('username', None) if username: return render_to_response('login.html', {'username':username}) else: return render_to_response('login.html') def logout(request): try: del request.session['username'] except KeyError: pass return HttpResponseRedirect(&/login/&)两个方法: login() 和 logout()。login() 用来提供初始页面、处理提供数据和判断用户是 否登录。而 logout() 只是用来从 session 中删除用户名,同时将页面重定向到 login 画面。这 里我仍然使用了模板,并且根据传入不同的字典来控制模板的生成。是的,因为 Django 的模块支 持条件判断,所以可以做到。 在 login() 中的判断逻辑是:A. 先从 POST 中取 username (这样 username 需要由模板的 form 来提供),如果存在则加入到 session 中去。加入 session 很简单,就是一个字典的 Key 赋值。 B. 然后再从 session 中取 username ,有两种可能:一种是上一步实现的。还有一种可能是直 接从以前的 session 中取出来的,它不是新产生的。而这里并没有细分这两种情况。因此这个判 断其实对应两种页面请求的处理: 一种是提交了用户姓名, 而另一种则是处理完用户提交姓名之后, 用户再次进入的情况。而用户再次进入时,由于我们在前面已经将他的名字保存在 session 里面 了, 因此可以直接取出来。 如果 session 中存在, 则表示用户已经登录过, 则输出 login.html 模 板,同时传入了 username 字典值。而如果 session 中不存在,说明用户从来没有登录过,则输 出 login.html 模板,这次不带值。因此对于同一个 login.html 模板传入的不同值,后面我们会看到模板是如何区分的。在 logout() 中很简单。先试着删除 session ,然后重定向页面到 login 页面。这里使用了 HttpResponseRedirect 方法,它是从以前我们看到的 HttpResponse 派生来的子类。更多的派生 子类和关于 response 的内容要参考 Request and response objects 文档。3templates/login.html 创建 templates/login.html{% if not username %} &form method=&post& action=&/login/&& 用户名:&input type=&text& name=&username& value=&&&&br/& &input type=&submit& value=&登录&& &/form& {% else %} 你已经登录了!{{ username }}&br/& &form method=&post& action=&/logout/&& &input type=&submit& value=&注销&& &/form& {% endif %} 一步一步学 Django第9 页整个是一个 if 语句。 Django 模板中的 if 可以象 Python 一样使用, 在 如使用 not , and , or 。象 if not username 表示什么呢?它表示如果 username 不存在,或为空,或是假值等等。 而此时我们利用了 username 不存在这种判断。上面的逻辑表示,如果 username 不存在,则显示 一个表单, 显示用户名输入文本框。 如果存在, 则显示已经登录信息, 同时显示用户名和注销按钮。 而这个注销铵钮对应于 logout() 方法。4urls.py: 修改 urls.py:增加了 login 和 logout 两个 url 映射。from django.conf.urls.defaults import * urlpatterns = patterns('', # Example: # (r'^testit/', include('newtest.apps.foo.urls.foo')), (r'^$', 'newtest.helloworld.index'), (r'^add/$', 'newtest.add.index'), (r'^list/$', 'newtest.list.index'), (r'^csv/(?P&filename&\w+)/$', 'newtest.csv_test.output'), (r'^login/$', 'newtest.login.login'), (r'^logout/$', 'newtest.login.logout'), # Uncomment this for admin: #(r'^admin/', include('django.contrib.admin.urls')), )5启动 server 运行但我要说,你一定会报错。而且我的也在报错。从这一刻起,我们就要进入有数据库的环境了。 因为在 django 中 session 是存放在数据库中的。所以在这里要进行数据库的初始化了。6settings.py, 修改 settings.py,主要修改以下地方:DATABASE_ENGINE = 'sqlite3' DATABASE_NAME = './data.db' DATABASE_USER = '' DATABASE_PASSWORD = '' DATABASE_HOST = '' DATABASE_PORT = ''这里我使用 sqlite3 。在使用数据库时,需要安装相应的数据库处理模块。对 sqlite3 只需 要修改两项: DATABASE_ENGINE 和 DATABASE_NAME 。这里数据文件名我使用了相对路径,在实际 情况下可能使用绝对路径为好。 sqlite3 对应的是 pysqlite2 模块, http://pysqlite.org/ 下 从 载到最新版本。如果你使用 utf-8,要注意缺省字符编码应为 utf-8。同时对于 DATABASE_PORT 字 段,Django 目前允许使用数字或字符串表示了。7初始化数据库: 改了配置还不够, 还要执行相应的建库、 建表的操作, 使用 django-admin.py 或 manage.py 都可以:manage.py syncdb它可以自动创建已经安装的 App 中,在数据库中不存在的 Model。并且会自动将表的权限赋 与超级用户。并且把超级用户的创建也结合到了一起。8server, 启动 server,这次再进入试吧:http://localhost:8000/login/,从此我们要进入数据库 的世界了, 当然目前还没有用到, Django 提供的许多自动化的高级功能都是需要数据库支持的。 而第六讲 wiki 的例子1 引言 一步一步学 Django第 10 页以后的例子可能会越来越复杂,下面我们按照 TurboGears 的 20 Minute Wiki Tutorial 的 例子仿照一个,我们要用 Django 来做 wiki。我不会按 TurboGears 的操作去做,只是实现一个 我认为的最简单的 wiki。现在我的要求是:做一个简单的 wiki,要可以修改当前页面,即在页面 下面提供一个编辑的按钮。 然后还要识别页面中的两个开头大写的单词为页面切换点, 可以进入一 个已经生成好的页面,或提示创建一个新页面。下面我们将开始创建 Django 中的 app 了。 先说一下。如果你看过官方版的教程,它就是讲述了一个 Poll 的 app 的生成过程。那么一 个 app 就是一个功能的集合,它有自已的 model ,view 和相应的模板,还可以带自已的 urls.py 。那么它也是一个独立的目录,这样一个 app 就可以独立地进行安装,你可以把它安装 到其它的 Django 服务器中去。 因此采用 app 的组织形式非常有意义。 而且 adango-admin.py 也 提供了一个针对 app 的命令,一会我们就会看到。而且 Django 提供一些自动功能也完全是针对 于 app 这种结构的。Model, Template, View 就合成了 MTV 这几个字母。 Model 是用来针对数 据库,同时它可以用来自动生成管理界面, View 在前面我们一直都用它,用来处理请求和响应的 相当于 MVC 框架中的 Controller 的作用, Template 用来生成界面。2创建 wiki appmanage.py startapp wiki在 0.91 版, app 都是放在 apps 目录下的 目录下的。不过到了 0.95 版,apps 目录不自动创建了。 因此你就可以直接放在项目目录下了。这样在 wiki 子目录下有以下文件: __init__.py 表示 wiki 目录是一个包。 views.py 用来放它的 view 的代码。 models.py 用来放 model 代码。3编辑 wiki/models.pyfrom django.db import models # Create your models here. class Wiki(models.Model): pagename = models.CharField(max_length=20, unique=True) content = models.TextField()每个 model 其实在 Django 中就是一个表,你将用它来保存数据。在实际的应用中,一般都 要与数据库打交道,如果不想用数据库,那么原因可能就是操作数据库麻烦,创建数据库环境也麻 烦。但通过 Django 的 model 处理,它是一种 ORM (Object Relation Mapping, 对象与关系的映 射),可以屏蔽掉底层数据库的细节,同时提供以对象的形式来处理数据。非常方便。而且 Django 的 model 层支持多种数据库,如果你改变数据库不是问题,这也为以后的数据库迁移带来好处。 Wiki 是 model 的名字,它需要从 models.Model 派生而来。它定义了两个字段,一个是字段 是 pagename , 用来保存 wiki 页面的名字,它有两个参数,一个是最大长度(从这点上不如 SQLAlchemy 方便, SQLAlchemy 并不需要长度,它会根据有无长度自动转为 TEXT 类型),目前 CharField 需要这个参数;另一个是 unique 表示这个字段不能有重复值。还有一个字段是 content ,用来保存 wiki 页面的内容,它是一个 TextField 类型,它不需要最大长度。 在运行时, Django 会自动地为这个 model 增加许多数据操作的方法。关于 model 和 数据 库操作 API 的详细内容参见 Model reference 和 Database API reference 的文档。4修改 settings.py, 安装 app虽然我们的其它工作没有做完,但我还是想先安装一下 app 吧。每个 app 都需要安装一下。 安装一般有两步: 1. 修改 settings.py INSTALLED_APPS = ( 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 一步一步学 Django第 11 页'django.contrib.sites', 'newtest.wiki', ) 2. 执行(在 newtest 目录下) manage.py syncdb 以前是使用 install wiki 。现在也可以使用,不过使用 syncdb 要更简单得多。如果没有报 错就是成功了。这一步 Django 将根据 model 的信息在数据库中创建相应的表。5在命令行下加入首页(FrontPage) 在命令行下加入首页(FrontPage)我们假设首页的名字为 FrontPage ,并且我们将在命令行下增加它,让我们熟悉一下命令行 的使用,进入 newtest 目录,然后: manage.py shell 进入 python &&& from newtest.wiki.models import Wiki &&& page = Wiki(pagename='FrontPage', content='Welcome to Easy Wiki') &&& page.save() &&& Wiki.objects.all() [&Wiki object&] &&& p = Wiki.objects.all()[0] &&& p.pagename 'FrontPage' &&& p.content 'Welcome to Easy Wiki' 因为在写这篇教程时是在 magic-removal 分枝下进行的操作,因此有些 API 并不稳定。象 objects 的方法以前是沿用 model 的方法,但后来进行了简化,比如 get_list() 变为 all() 。 还有一系统的变化。具体的可参见 Removing The Magic 文档中关于 Descriptor fields 的说明。 在 Django 中,对于数据库的记录有两种操纵方式,一种是集合方式,一种是对象方式。集合 方式相当于表级操作,在 0.92 中可以使用 model.objects 来处理。objects 对象有一些集合方 式的操作,如 all() 会返回全部记录, filter() 会根据条件返回部分记录。而象插入新记录则 需要使用记录方式来操作。6修改 wiki/views.py#coding=utf-8 from newtest.wiki.models import Wiki from django.template import loader, Context from django.http import HttpResponse, HttpResponseRedirect from django.shortcuts import render_to_response def index(request, pagename=&&): &&&显示正常页面,对页面的文字做特殊的链接处理&&& if pagename: #查找是否已经存在页面 #pages = Wiki.objects.get_list(pagename__exact=pagename) pages = Wiki.objects.filter(pagename=pagename) if pages: #存在则调用页面模板进行显示 return process('wiki/page.html', pages[0]) else: #不存在则进入编辑画面 return render_to_response('wiki/edit.html', {'pagename':pagename}) 一步一步学 Django第 12 页else: #page = Wiki.objects.get_object(pagename__exact='FrontPage') page = Wiki.objects.get(pagename='FrontPage') return process('wiki/page.html',page) def edit(request, pagename): &&&显示编辑存在页面&&& #page = Wiki.objects.get_object(pagename__exact=pagename) page = Wiki.objects.get(pagename=pagename)return render_to_response('wiki/edit.html', {'pagename':pagename, 'content':page.content})def save(request, pagename): &&&保存页面内容,老页面进行内容替换,新页面生成新记录&&& content = request.POST['content'] #pages = Wiki.objects.get_list(pagename__exact=pagename) pages = Wiki.objects.filter(pagename=pagename) if pages: pages[0].content = content pages[0].save() else: page = Wiki(pagename=pagename, content=content) page.save() return HttpResponseRedirect(&/wiki/%s& % pagename) import re r = re.compile(r'\b(([A-Z]+[a-z]+){2,})\b') def process(template, page): &&&处理页面链接,并且将回车符转为&br&&&& t = loader.get_template(template) content = r.sub(r'&a href=&/wiki/\1&&\1&/a&', page.content) content = re.sub(r'[\n\r]+', '&br&',content) c = Context({'pagename':page.pagename,'content':content}) return HttpResponse(t.render(c)) 将原来老的 model 方法加了注释,目前改用最新的 API 了。代码有些长,有些地方已经有说明和 注释了。简单说一下:? index() 用来显示一个 wiki 页面。它需要一个参数就是页面的名称。如果在数据库中找得 到,则调用 process()方法(process()方法是一个自定义方法,主要用来对页面的文本进行处理, 比如查找是否有满足 wiki 命名规则的单词,如果有则替换成链接。再有就是将回车转为 &br& )。 如果没有找到,则直接调用编辑模板显示一个编程页面。当然,这个页面的内容是空的。只是它的 页面名字就是 pagename 。如果 pagename 为空,则进入 FrontPage 页面。 Wiki.objects 对象 有 filter() 方法和 get() 方法,一个返回一个结果集,一个返回指定的对象。这里为什么使用 filter() 呢,因为一旦指定文件不存在,它并不是返回一个 None 对象,而是抛出异常,而我没 有使用异常的处理方式。 通过 filter() 如果存在则结果中应有一个元素, 如果不存在则应该是一 个 [] 。这样就知道是否有返回了。filter() 中使用的参数与一般的 db-api 是一样的,但如果是比较相等,可以为: pagename__exact=pagename 也可以简化为 pagename=pagename 。 Django 中, 在 一些字段的比较 操作比较特殊,它是在字段名后加 __ 然后是比较条件。这样看上去就是一个字符串。具体的参见 The Database API 。回车转换的工作其实可以在模板中使用 filter 来完成。?从对模板的使用 (wiki/edit.html) 可以猜到在后面我们要在 templates 中创建子目录了。 的确,对于不同的 app ,我们可以考虑将所有的模板都放在统一的 templates 目录下,但为了区 分方便,一般都会针对 app 创建不同的子目录。当然也可以不这样,可以放在其它的地方,只要 修改 settings.py ,将新的模板目录加进去就行了。 因为我们在设计 model 时已经设置了 pagename 必须是唯一的,因此一旦 filter() 有返回 值,那它只能有一个元素,而 pages[0] 就是我们想要的对象。?page = wikis.get(pagename='FrontPage'),是表示取出 pagename 为 FrontPage 的页面。 你可能要说,为什么没有异常保护,是的,这也就是为什么我们要在前面先要插条记录在里面的原 因。这样就不会出错了。再加上我要做的 wiki 不提供删除功能,因此不用担心会出现异常。 一步一步学 Django第 13 页edit() 用来显示一个编辑页面,它直接取出一个页面对象,然后调用 wiki/edit.html 模板 进行显示。也许你还是要问,为什么不考虑异常,因为这里不会出现。为什么?因为 edit() 只用 在已经存在的页面上,它将用于存在页面的修改。而对于不存在的页面是在 index() 中直接调用 模板来处理, 并没有直接使用这个 edit() 来处理。 也许你认为这样可能不好, 但由于在 edit() 要 重新检索数据库,而在 index() 已经检索过一次了,没有必要再次检索,因此象我这样处理也没 什么不好,效率可能要高一些。当然这只是个人意见。 ? save() 用来在编辑页面时用来保存内容的。它先检查页面是否在数据库中存在,如果不存在 则创建一个新的对象,并且保存。注意,在 Django 中,对对象处理之后只有调用它的 save() 方 法才可以真正保存到数据库中去。如果页面已经存在,则更新页面的内容。处理之后再重定向到 index() 去显示这个页面。?7 8在 templates 中创建 wiki 子目录 编辑 templates/wiki/page.html&h2&{{ pagename }}&/h2& &p&{{ content }}&/p& &hr/& &p& &form method=&POST& action=&/wiki/{{ pagename }}/edit/&& &input type=&submit& value=&编辑&& &/form&&/p&它用来显示页面, 同时提供一个“编辑”按钮。 当点击这个按钮时将调用 view 中的 edit() 方法。9编辑 templates/wiki/edit.html&h2&编辑:{{ pagename }}&/h2& &form method=&POST& action=&/wiki/{{pagename}}/save/&& &textarea name=&content& rows=&10& cols=&50&&{{ content }}&/textarea&&br/& &input type=&submit& value=&保存&& &/form&它用来显示一个编辑页面,同时提供“保存”按钮。点击了保存按钮之后,会调用 view 中的 save() 方法。10修改 urls.pyfrom django.conf.urls.defaults import * urlpatterns = patterns('', # Example: # (r'^testit/', include('newtest.apps.foo.urls.foo')), (r'^$', 'newtest.helloworld.index'), (r'^add/$', 'newtest.add.index'), (r'^list/$', 'newtest.list.index'), (r'^csv/(?P&filename&\w+)/$', 'newtest.csv_test.output'), (r'^login/$', 'newtest.login.login'), (r'^logout/$', 'newtest.login.logout'), (r'^wiki/$', 'newtest.wiki.views.index'), (r'^wiki/(?P&pagename&\w+)/$', 'newtest.wiki.views.index'), (r'^wiki/(?P&pagename&\w+)/edit/$', 'newtest.wiki.views.edit'), (r'^wiki/(?P&pagename&\w+)/save/$', 'newtest.wiki.views.save'), # Uncomment this for admin: #(r'^admin/', include('django.contrib.admin.urls')), ) 增加了 wiki 等 4 个 url 映射。一般一个 wiki ,我们访问它的一个页面可能为: wiki/pagename。我设计对 index() 方法的调用的 url 为:r'^wiki/(?P&pagename&\w+)/$' 一步一步学 Django第 14 页也就是把 wiki/后面的解析出来作为 pagename 参数。但这样就带来一个问题,如果我想实现 wiki/edit.html 表示修改, pagename 作为一个参数通过 POST 来提交好象就不行了。因为上面 的解析规则会“吃”掉这种情况。因此我采用 Zope 的表示方法:把对象的方法放在对象的后面。 我可以把 pagename 看成为一个对象, edit , save 是它的方法,放在它的后面,也简单,也清 晰。当然如果我们加强上面的正则表达式,也可以解析出 wiki/edit.html 的情况。因此 wiki/pagename 就是显示一个页面,wiki/pagename/edit 就是编辑这个页面, wiki/pagename/save 就是保存页面。而 pagename 解析出来后就是分别与 index() , edit() , save() 的 pagename 参数相对应。 下面你可以运行了。11server: 启动 server: manage.py runserver,进入 http://localhost:8000/wiki首先进入这个页面:然后你点编辑,则进入 FrontPage 的编辑界面:然后我们加上一个 TestPage ,它符合 wiki 的名字要求,两个首字母大写的单词连在一起。 然后点击保存。看见了吧。页面上的 TestPage 有了链接。点击它将进入:这是 TestPage 的编辑页面。让我们输入中文,然后输入 FrontPage 。然后保存。 一步一步学 Django第 15 页好了,剩下的你来玩吧。点击 FrontPage 将回到首页。第七讲 通讯录1 引言敢问路在何方,路在脚下。如果你坚持下来,一定会有收获的。直到目前我们已经学了:? ?settings.py 的设置 ? 模板 ? app ? model url dispatcher ? session 其实在某些方面,使用 Django 还可以更加方便。而且我们还有许多东西没有学,一点点跟着 我学吧。我有一个通讯录,它是保存在 Excel 文件中的,我不想每次到目录下去打开它,我希望 用 Django 做一个 web 上的简单应用,如何做呢?2创建 address appmanage.py manage.py startapp address ;这样就创建好了 address 相关的目录了。3修改 address/models.py#coding=utf-8 from django.db import models # Create your models here. class Address(models.Model): name = models.CharField('姓名', max_length=6, unique=True) gender = models.CharField('性别', choices=(('M', '男'), ('F', '女')), max_length=1)#, radio_admin=True) telphone = models.CharField('电话', max_length=20) mobile = models.CharField('手机', max_length=11)这回 model 复杂多了。在上面你可以看到我定义了四个字段: name , gender , telpnone , mobile 。其中 gender 表示性别,它可以从一个 tuple 数据中进行选取。并且在后面的 radio_admin=True 表示在 admin 的管理界面中将使用 radio 按钮来处理。 Django 提供了许多的字段类型,有些字段类型从数据的取值范围来讲没有什么区别,但之所 以有这种区别, 是因为: Django 的数据类型不仅仅用于创建数据库, 进行 ORM 处理, 还用于 admin 的处理。 一方面将用来对应不同的 UI 控件, 另一方面提供对不同的数据类型将进行不同的数据校 验的功能。在 Django 中每个字段都可以有一个提示文本,它是第一个参数,如果没有则会使用字 段名。因此我定义的每个字段为了方便都有一个对应的汉字提示文本。 因为本节主要是讲 admin 的使用。admin 是 Django 提供的一个核心 app(既然是 app 就需 要安装,一会就看到了),它可以根据你的 model 来自动生成管理界面。我为什么要用它,因为有 了这个管理界面,对于通讯录的增加、删除、修改的处理界面完全可以通过 admin 来自动生成, 我不用自已写。不相信吗?我们就会看到了。那么 admin 到底可以带来些什么好处呢?它的功能 很强大,不仅界面漂亮,还能对数据提供操作记录,提供搜索。特别是它是在用户权限控制之下, 你都可以不用考虑安全的东西了。 并且它本身就是一个非常好的学习的东西, 特别是界面自动生成 方面,学习它的代码可以用在我们自已的定制之中。当然,也许你用不上 admin ,它的确有一定 的适应范围,不过对于大部分工作来说它可能足够了。对于那些交互性强的功能,你可能要自已实 现许多东西,对于管理集中,主要以发布为主的东西,使用它可以节省你大量的时间。至于怎么使 用,你要自已去权衡。但这一点对于快速实现一个 web 应用,作用非常大,这是 Django 中的一 个亮点。4settings.py 修改 settings.py 一步一步学 Django第 16 页INSTALLED_APPS = ( 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', 'django.contrib.admin', 'newtest.wiki', 'newtest.address', ) 这里我们加入了两个 app ,一个是 address ,还有一个是 django.contrib.admin 。 admin 也是一个应用,需要加入才行,后面还要按添加 app 的方式来修改 url 映射和安装 admin app。 这些与标准的 app 的安装没有什么不同。5安装 admin appmanage.py syncdb (username : admin 3814264),这样将在数据库中创建 admin 相关 的表。6修改 urls.pyfrom django.conf.urls.defaults import * urlpatterns = patterns('', # Example: # (r'^testit/', include('newtest.apps.foo.urls.foo')), (r'^$', 'newtest.helloworld.index'), (r'^add/$', 'newtest.add.index'), (r'^list/$', 'newtest.list.index'), (r'^csv/(?P&filename&\w+)/$', 'newtest.csv_test.output'), (r'^login/$', 'newtest.login.login'), (r'^logout/$', 'newtest.login.logout'), (r'^wiki/$', 'newtest.wiki.views.index'), (r'^wiki/(?P&pagename&\w+)/$', 'newtest.wiki.views.index'), (r'^wiki/(?P&pagename&\w+)/edit/$', 'newtest.wiki.views.edit'), (r'^wiki/(?P&pagename&\w+)/save/$', 'newtest.wiki.views.save'), # Uncomment this for admin: (r'^admin/', include('django.contrib.admin.urls')), )缺省的 urls.py 中在最后已经加上了 admin 的映射,不过是一个注释,把注释去掉就好了。 这里要注意,它使用了一个 include 方式。对于这种 URL 的解析 Django 是分段的,先按 r'^admin/' 解析(这里没有 $),匹配了则把剩下的部分丢给 django.contrib.admin.urls.admin 去进行进一步的解析。使用 include 可以方便移植,每个 app 都可以有独立的 urls.py ,然后 可以与主 urls.py 合在一起使用。 配置起来相对简单。 而且可以自由地在主 urls.py 中修改应用 URL 的前缀,很方便。7增加超级用户: 增加超级用户:进入 http://localhost:8000/adminadmin 功能是有用户权限管理的,因此一个 admin 替你完成了大量的工作:用户的管理和信 息的增加、删除、修改这类功能类似,开发繁琐的东西。那么我们目前还没有一个用户,因此可以 在命令下创建一个超级用户,有了这个用户,以后就可以直接在 admin 界面中去管理了。 一步一步学 Django第 17 页manage.py shell &&& from django.contrib.auth.create_superuser import createsuperuser &&& createsuperuser() 它会让你输入用户名,邮件地址和口令。如果你使用了 syncdb 的话,应该在运行的最后,当 没有超级用户时会提示你创建的。因此这一步可能会省略掉。如果想直接创建可以使用这种方法。 这种方法与 authentication 所讲述的不完全一致,原因就是这种方法不用设置 PYTHONPATH 和 DJANGO_SETTING_MODULE 环境变量,所以要简单一些。这回再进去看一下吧。上面已经有一些东西了,其中就有用户管理。但如何通过 admin 增加通讯录呢?别急,我们 需要在 model 文件中增加一些与 admin 相关的东西才可以使用 admin 来管理我们的 app 。 因此 是否启用 admin 管理取决于你。只要在 model 中增加 admin 相关的部分,我们的应用才可以在 admin 中被管理。8修改 address/models.py#coding=utf-8 from django.db import models # Create your models here. class Address(models.Model): name = models.CharField('姓名', maxlength=6, unique=True) gender = models.CharField('性别',choices=(('M','男'),('F','女')), maxlength=1, radio_admin=True) telphone = models.CharField('电话', maxlength=20) mobile = models.CharField('手机', maxlength=11) class Admin: pass 在 0.91 版 Admin 内部类需要写成 class META: admin = meta.Admin()在 0.95 版发生了变化。有了这个东西,你就可以在 admin 中看到 adress 这个 app 了。再 到浏览器中看一下是什么样子了。看见了吧。上面有增加和删除的按钮,先让我们点击一下增加吧。 一步一步学 Django第 18 页这个自动生成的界面是不是很不错。增加一条保存起来了。不过我发现当我输入 limodou 时, 只能输入 limodo 好象 u 输不进去。为什么?因为我把姓名按汉字算最多 6 个就够了,一旦我使 用英文的名字可能就不够。因此这是一个问题,一会要改掉。怎么新增的记录叫 &Address object&这样看上去很别扭。为什么会这样,因为没有定义特殊 的方法。下面就让我们定义一下。9修改 address/models.py#coding=utf-8 from django.db import models # Create your models here. class Address(models.Model): name = models.CharField('姓名',maxlength=6,unique=True) gender = models.CharField('性别', choices=(('M', '男'), ('F', '女')), maxlength=1, radio_admin=True) telphone = models.CharField('电话', maxlength=20) mobile = models.CharField('手机', maxlength=11) def __str__(self): return self.name class Admin: pass改好了,再刷新下页面。这次看见了吗?增加了一个 __str__ 方法。这个方法将在显示 Address 实例的时候起作用。我们就使用某个联系人的姓名就行了。曾经在 0.91 使用 __repr__ 也可以,但后来只能使用 __str__ 了。要注意。 一步一步学 Django第 19 页你记得吗?Model 是与数据库中的表对应的,为什么我们改了 model 代码,不需要重新对数 据库进行处理呢?因为只要不涉及到表结构的调整是不用对表进行特殊处理的。 不过, 我们马上要 修改表结构了。10address/models.py: 修改 address/models.py:姓名留短了真是不方便,另外我突然发现需要再增加一个#coding=utf-8 from django.db import models # Create your models here. class Address(models.Model): name = models.CharField('姓名', maxlength=20, unique=True) gender = models.CharField('性别', choices=(('M', '男'), ('F', '女')), maxlength=1, radio_admin=True) telphone = models.CharField('电话', maxlength=20) mobile = models.CharField('手机', maxlength=11) room = models.CharField('房间', maxlength=10) def __repr__(self): return self.name class Admin: pass房间字段。这回表结构要改变了,怎么做呢?11修改表结构目前 Django 没有一个特别的命令可以直接更新表结构。 为什么呢?在 Django 看来修改表结 构并不是件很容易的事情, 主要的问题是数据库中现有的数据怎么办, 因此为了使旧的数据可以平 滑迁移到新的表结构中,这步操作还是手工来做好一些。但现在我们正在开发中,因此很有可能表 结构要经常发生变化,每次手工做多麻烦呀。 Django 有一个命令行命令: sqlreset 可以生成 drop 表,然后创建新表的 SQL 语句,因此我们可以先调用这个命令,然后通过管道直接导入数据 库的命令行工具中。这里我使用的是 sqlite3 ,因此我这样做: manage.py sqlreset address|sqlite3 data.db sqlreset 后面是要处理的 app 的名字, 因此它只会对指定的 app 有影响。 但这样, 这个 app 的所有数据都丢失了。 如果想保留原有数据, 你需要手工做数据切换的工作。 另外 django-amdin.py 还提供了更为简单的命令 manage.py reset address ,效果同上面是一样。对于其它的数据库, 在数据库命令行可能是不同的,这个你自已去掌握吧。同时对于 sqlite3 ,有人可能想:直接把 数据库文件删除了不就行了。但是你一定要清楚,如果存在其它的 app 的话,它们的数据是否还 有用,如果没用删除当然可以,不过相应的 app 都要再重新 install 一遍以便初始化相应的表。 如果数据有用,这样做是非常危险的,因此还是象上面的处理为好,只影响当前的 app 。12进入 admin我们可以再次进入 admin 了,增加,删除,修改数据了。用了一会,也许你会希望:能不能 有汉化版本的界面呢?答案是肯定的,而且已做好了。13修改 settings.py把 LANGUAGE_CODE 由 'en' 改为 'zh-cn' , TIME_ZONE 建议改为 'CCT',刷新下界面,是 不是变成汉字了。 国际化支持在 Django 中做得是非常的出色, 程序可以国际化, 模板可以国际化, 甚至 js 都可以国际化。 这一点其它的类似框架都还做不到。 而国际化的支持更是 RoR 的一个弱项, 甚至在 Snakes and Rubies 的会议上,RoR 的作者都不想支持国际化。但 Django 却做得非常出 色,目前已经有二十多种语言译文。在增加,删除,修改都做完了,其实还剩下什么呢?显示和查 询。那么实现它则需要写 view 和使用模板了。这个其实也没什么,最简单的,从数据库里查询出 所有的数据,然后调用模板,通过循环一条条地显示。不错是简单。但是在做之前,先让我们想一 想, 这种处理是不是最常见的处理方法呢?也许我们换成其它的应用也是相似的处理。 如果很多这 样的处理,是不是我们需要每次都做一遍呢?有没有通用的方便的方法。答案是:有! Django 已 经为我们想到了,这就是 Generic views 所做的。它把最常见的显示列表,显示详细信息,增加, 修改,删除对象这些处理都已经做好了一个通用的方法,一旦有类似的处理,可以直接使用,不用 一步一步学 Django第 20 页再重新开发了。但在配置上有特殊的要求。具体的可以看 Generic views 文档。从这里我有一点 想法,我认为 view 这个名称特别容易让人产生误解,为什么呢?因为 view 可以译为视图,给人 一种与展示有关的什么东西。 但实际上 Django 中的 view 相当于一个 Controller 的作用, 它是 用来收集数据,调用模板,真正的显示是在模板中处理的。因此我倒认为使用 Controller 可能更 合适, 这样就称为 MTC 了。 另外,Generic views 产生的意义在于 Django 的哲学理含 DRY (Don't repeat yourself, 不要自已重复), 目的是重用, 减少重复劳动。 还有其它的哲学理含参见 Design philosophies 文档。因此可以知道 view 可以省掉,但模板却不能省, Django 在这点上认为: 每个应用的显示都可能是不同的,因此这件事需要用户来处理。但如果有最简单的封装,对于开发 人员在测试时会更方便,但目前没有,因此模板我们还是要准备,而且还有特殊的要求,一会就看 到了。 对于目前我这个简单的应用来说,我只需要一个简单的列表显示功能即可,好在联系人的信息 并不多可以在一行显示下。因此我要使用 django.views.generic.list_detail 模块来处理。14address/urls.py, 增加 address/urls.py,对,我们为 address 应用增加了自已的 urls.py。from django.conf.urls.defaults import * from newtest.address.models import Address info_dict = { # 'model': Address, 'queryset': Address.objects.all(), } urlpatterns = patterns('', (r'^/?$', 'django.views.generic.list_detail.object_list',info_dict), )info_dict 存放着 object_list 需要的参数,它是一个字典。不同的 generic view 方法需 要不同的 info_dict 字典(这个变量你可以随便起名)。 对于我们要调用的 object_list 它只要一 个 queryset 值即可。 但这个值需要一个 queryset 对象。 因此在第二句从 newtest.address.models 中导入了 Address 。并且使用 Address.objects.all() 来得到一个全部记录的 queryset 。在 0.91 版,需要两个参数 app_name 和 module_name 。但在 0.95 版之后, module_name 取消了。 代替为 model_name 的小写形式。而 info_dict 也变成了一个 model 值了。但最新的变化是 model 也不要了,取而代之的是 queryset 。这样会更方便。只是我的代码要改来改去的。 前面已经谈到:使用 generic view 只是减少了 view 的代码量,但对于模板仍然是必不可少 的。因此要创建符合 generic view 要求的模板。主要是模板存放的位置和模板文件的名字。使用 object_list() 需要的模板文件名为: app_label/model_name_list.html , 这是缺省要查找的模 板名。15 16创建 templates/address 目录 创建 templates/address/address_list.html&h1&通讯录&/h1& &hr& &table border=&1&& &tr& &th&姓名&/th& &th&性别&/th& &th&电话&/th& &th&手机&/th& &th&房间&/th& &/tr& {% for person in object_list %} &tr& &td&{{ person.name }}&/td& &td&{{ person.gender }}&/td& &td&{{ person.telphone }}&/td& &td&{{ person.mobile }}&/td& &td&{{ person.room }}&/td& 一步一步学 Django第 21 页&/tr& {% endfor %} &/table&17urls.py, 修改 urls.py,将我们的应用的 urls.py include 进去。from django.conf.urls.defaults import * urlpatterns = patterns('', # Example: # (r'^testit/', include('newtest.apps.foo.urls.foo')), (r'^$', 'newtest.helloworld.index'), (r'^add/$', 'newtest.add.index'), (r'^list/$', 'newtest.list.index'), (r'^csv/(?P&filename&\w+)/$', 'newtest.csv_test.output'), (r'^login/$', 'newtest.login.login'), (r'^logout/$', 'newtest.login.logout'), (r'^wiki/$', 'newtest.wiki.views.index'), (r'^wiki/(?P&pagename&\w+)/$', 'newtest.wiki.views.index'), (r'^wiki/(?P&pagename&\w+)/edit/$', 'newtest.wiki.views.edit'), (r'^wiki/(?P&pagename&\w+)/save/$', 'newtest.wiki.views.save'), (r'^address/', include('newtest.address.urls')), # Uncomment this for admin: (r'^admin/', include('django.contrib.admin.urls')), )可以看到 r'^address/' 没有使用 $ ,因为它只匹配前部分,后面的留给 address 中的 urls.py 来处理。18启动 server 看效果第八讲 为通讯录增加文件导入和导出功能1 引言上一讲的确很长,但如果看代码你会发现,代码主要在 model 的调整中,``urls.py`` 的工 作不多,而连一行 view 的代码都没有写。是不是非常方便呢!那么让我们来继续完善这个通讯录 吧。现在我想完成的是:增加批量导入和导出功能.为什么要批量导入呢?因为一般情况下,我一 定是已经有了一个通讯录文件(象以前我说过的 Excel 文件),那么现在需要转到 web 上来,难道 要我一条条全部手工录入吗?能不能上传文件, 自动插入到数据库中去呢?那么就让我们实现一个 文件上传的处理吧。 为了简化, 我采用 csv 格式文本文件(这个文件在 svn 中有一个例子 data.csv , 不然就自行生成好了)。 abc,M,11,11,11, bcd,M,11,11,11, ass,M,11,11,11, dfsdf,F,11,11,11, sfas,F,11,11,11,2修改 templates/address/address_list.html 一步一步学 Django第 22 页&h1 id=&title&&通讯录&/h1& &hr& &form enctype=&multipart/form-data& method=&POST& action=&/address/upload/&& 上传通讯录文件: &input type=&file& name=&file&/&&br/& &input type=&submit& value=&上传文件&/& &/form& &table border=&1&& &tr& &th&姓名&/th& &th&性别&/th& &th&电话&/th& &th&手机&/th& &th&房间&/th& &/tr& {% for person in object_list %} &tr& &td&{{ person.name }}&/td& &td&{{ person.gender }}&/td& &td&{{ person.telphone }}&/td& &td&{{ person.mobile }}&/td& &td&{{ person.room }}&/td& &/tr& {% endfor %} &/table&3address/views.py 修改 address/views.py#coding=utf-8 # Create your views here. from newtest.address.models import Address from django.http import HttpResponseRedirect from django.shortcuts import render_to_response def upload(request): file_obj = request.FILES.get('file', None) if file_obj: import csv import StringIO buf = StringIO.StringIO(file_obj['content']) try: reader = csv.reader(buf) except: return render_to_response('address/error.html', {'message':'你需要上传一个 csv 格式的文件!'}) for row in reader: # objs = Address.objects.get_list(name__exact=row[0]) objs = Address.objects.filter(name=row[0]) if not objs: obj = Address(name=row[0], gender=row[1], telphone=row[2], mobile=row[3], room=row[4]) else: obj = objs[0] obj.gender = row[1] obj.telphone = row[2] obj.mobile = row[3] obj.room = row[4] obj.save() return HttpResponseRedirect('/address/') else:return render_to_response('address/error.html', {'message':'你需要上传一个文件!'}) 一步一步学 Django第 23 页这里有一个 upload() 方法,它将使用 csv 模块来处理上传的 csv 文件。首先查找姓名是否 存在于数据库中,如果不存在则创建新记录。如果存在则进行替换。如果没有指定文件直接上传, 则报告一个错误。 如果解析 csv 文件出错, 则也报告一个错误。 报造错误使用了一个名为 error 的 模板,我们马上要创建。4创建 templates/error.html&h2&出错&/h2& &p&{{ message }}&/p& &hr& &p&&a href=&/address/&&返回&/a&&/p&5ddress/urls.py, 修改 address/urls.py,增加一个 upload 的 url 映射。from django.conf.urls.defaults import * from newtest.address.models import Address info_dict = { # 'model': Address, 'queryset': Address.objects.all(), } urlpatterns = patterns('', (r'^/?$', 'django.views.generic.list_detail.object_list', info_dict), (r'^upload/$', 'address.views.upload'), )6启动 server 测试这样导入功能就做完了。那导出呢?很简单了,参考 csv 的例子去做就可以了。不过,并不 全是这样,仍然有要修改的地方,比如 csv.html 模板,它因为写死了处理几个元素,因此需要改 成一个循环处理。7修改 templates/csv.html{% for row in data %}{% for i in row %}&{{ i|addslashes }}&,{% endfor %} {% endfor %} 将原来固定个数的输出改为循环处理。8templates/address/address_list.html, 修改 templates/address/address_list.html,增加生成导出的 csv 文件的链接&h1 id=&title&&通讯录&/h1& &hr& &form enctype=&multipart/form-data& method=&POST& action=&/address/upload/&& 上传通讯录文件: &input type=&file& name=&file&/&&br/& &input type=&submit& value=&上传文件&/& &/form& &hr& &p&&a href=&/address/output/&&导出为 csv 格式文件&/a&&/p& &table border=&1&& &tr& &th&姓名&/th& &th&性别&/th& &th&电话&/th& &th&

我要回帖

更多关于 latex enumerate 编号 的文章

 

随机推荐