django 架设网站入门指南[壹]
上节回顾 – 配置 基本视图和逻辑数据库配置 仍然在 settings.py 中, 找到 DATABASE_ 开头的项目. 现在用 sqlite3 作为数据库, 它已经集成在 python 2.5 以后的版本中, 这样就省去了安装配置的环节. 现在修改这些项目 DATABASE_ENGINE = 'django.db.backends.sqlite3' DATABASE_NAME = 'guestbook/db_file'
这里 DATABASE_NAME 同样需要给出文件的绝对路径, 原理跟之前模板目录那个一样, 如果不能确定每次的工作目录, 那么就填绝对 db_file 的路径吧. 保存设置, 然后执行数据库同步操作 $ guestbook/manage.py syncdb 会输出提示 Creating table auth_permission Creating table auth_group Creating table auth_user Creating table auth_message Creating table django_content_type Creating table django_session Creating table django_site
You just installed Django's auth system, which means you don't have any superusers defined. Would you like to create one now? (yes/no):
这些是 django 为内置的用户, 会话等类型建立的表, 最后询问是否立即建立一个超级用户. 这里答 yes (仅一个 y 是不行的唉), 然后输入用户名, 电子邮箱和密码. 最后会建立表的索引, 然后结束. 现在, 你可以在 guestbook 目录下看到文件 db_file 了, 它是数据库使用的文件. ORM 和数据库操作 django 的 ORM 非常轻松. 打开 home 目录下的 models.py, 建立留言类型 from django.db import models
class Message(models.Model): name = models.CharField(max_length=32) content = models.CharField(max_length=32) dt = models.DateTimeField(auto_now=True)
注, 使用 django 的 ORM, 该类型需要继承于 models.Model , 而要往数据库中放的数据项, 需要是 models 模块中的对应的域类型. 至于 auto_now=True , 它指出时间和日期在该对象插入数据库时自动使用当前日期时间. 类型弄好了, 得再同步一次数据库. 这些操作可以不重启服务器 $ guestbook/manage.py sql home $ guestbook/manage.py syncdb
回到 guestbook/home/views.py, 增加函数 save_message , 让它将表单数据存入数据库, 并重定向回到首页
Posted at Feb 03 2010 - 14:09:53
Permanent Link:
/p/76
Load full text
|
Post tags:
Web Server
Tutorial
Python
django
ORM
|
django 架设网站入门指南[零]
安装 根据 django 官方文档, 需要 python 2.3 或更高版本. 不过按现在的 python 普及程度, 想必大家的机器上都有 python 2.5 或 2.6 了. 我的操作系统是 ubuntu 9.10, 自带的是 2.6 版本. debian 用户安装 django 很简单, 只需要 # apt-get install python-django 就可以了, 其它发行版看有没有类似的方法. 或者在 官方站点下载源代码安装 祝好运. 建立项目 startproject 首先找到一个地方, 建立一个项目 guestbook, 我们将在这个项目中搭建一个留言板. $ django-admin startproject guestbook 有些系统中 django-admin 并非一个命令, 需要 $ python django-admin.py startproject guestbook 执行完这个之后, 当前目录下会创建一个名为 guestbook 的目录, 里面包含了一个最简单的服务器: 显示一个主页. 执行 $ python guestbook/manage.py runserver 启动后会看到类似以下输出 Validating models... 0 errors found
Django version 1.1.1, using settings 'guestbook.settings' Development server is running at http://127.0.0.1:8000/ Quit the server with CONTROL-C.
这时, manage.py 已经在本地 8000 端口创建了一个服务器, 赶快打开浏览器去访问吧! 为 guestbook/manage.py 加上可执行属性 (在 ubuntu 9.10 下该属性已经自动添加了) $ chmod u+x guestbook/manage.py 创建应用 startapp 在 django 世界的哲学里, 每个功能称之为一个应用. 创建应用也使用 manage.py 来完成. 比如现在用以下命令创建一个首页应用 $ guestbook/manage.py startapp home 这时 guestbook 目录下会多出一个 home 目录, 里面有这些文件 __init__.py models.py tests.py views.py 比较烦的是, 这时得回去修改设置, 打开 settings.py 查找 INSTALLED_APPS , 在这一坨里面加一行 INSTALLED_APPS = ( 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', 'guestbook.home', )
这样 home 应用才算是有了名分. 好, 现在再来实现功能. 因为现在只是处理页面, 所以只需要在 guestbook/home/views.py 里面修修补补就好了. 打开它, 其实相当于是个空文件, 把这一段代码放进去 from django.http import HttpResponse
def display(req): return HttpResponse('<html><body>hello, django!')
我知道你已经不耐烦了, 如果你曾经写 php 的话. 不过现在还有最后一步, 修改路径映射. 打开 guestbook/urls.py, 在里面加一句话
Posted at Feb 03 2010 - 05:02:06
Permanent Link:
/p/74
Load full text
|
Post tags:
Web Server
Tutorial
django
Python
|
Makefile 与 C 语系头文件依赖自动解析
h1. 如何获得源文件依赖的头文件? 这一部分内容与 Makefile 毫无关系, 它由编译器完成. 以 g++ 为例, 可以尝试使用以下方法输出 .cpp 文件依赖的头文件 g++ -M [your cpp file]
乱糟糟的, 不是吗? 这是因为 g++ 把依赖的库文件也给列出来了. 忽略库文件, 则使用这样的命令 g++ -MM [your cpp file]
显然, 这些东西扔到标准输出是毫无用处的, 可以对其进行重定向 g++ -MM [your cpp file] > [some file]
但是这还是有问题, 只把依赖关系放进文件当然不行, 编译源文件的指令还没弄出来呢. 下面就得另外想办法了. h1. 怎么添加编译指令并运行它们? 添加指令本质上就是追加文件内容, 方法有难有简单, 最简单的无非是写个脚本 echo 并追加重定向到文件中. 在这篇粗陋的文章里就用这招了. 好, 写个 Makefile 脚本 [target.o]:[your cpp file] ....g++ -MM $< > Makefile.tmp ....echo "....g++ $< -c" >> Makefile.tmp ....make -f Makefile.tmp
这里的四个点号 (....) 表示一个制表符, 嗯, 是的, Makefile 只能用万恶的制表符来缩进, 而且还必须缩进; Makefile.tmp 一定不要是当前的 Makefile, 要不然就出现文件覆盖的悲剧了... 结果就是, 一旦 make 到这个目标, 它会生成一串依赖关系和构建方法到另一个 Makefile, 然后把编译这等脏活累活都甩给那个倒霉的家伙. h1. 怎么转移目标? 如果上述目标仍然写成 xxx.o : xxx.cpp , 那么如果仅仅是依赖的头文件被修改了, 这个目标仍然不会被 make 到. 一个很挫的方法是, 不要把目标定为 xxx.o 文件, 相反, 弄成一个永不会生成的目标比较好, 比如叫 xxx.d 这个名字. 下面上一个完整的例子. 这个例子中有个叫做 DEP 的 Makefile 变量没有被声明过, 嗯, 这将是你的事情. 请将所有需要编译并连接的 cpp 源文件列个表, 然后修改它们的后缀变成 d, 那么 DEP 的值就是这个表. Code Snippet 0-0
CXX=g++ CXXFLAGS=-Wall -pg MKTMP=Makefile.tmp
all:object
object:$(DEP) ....$(CXX) $(CXXFLAGS) *.o -o $@
%.d:%.cpp ....$(CXX) -MM $< > $(MKTMP) ....echo "....$(CXX) $< $(CXXFLAGS) -c" >> $(MKTMP) ....make -f $(MKTMP)
clean: ....rm -f *.o ....rm -f test.out ....rm -f $(MKTMP)
再次提醒, 制表符出没注意. (可利用编辑器的全文替换, 4 点换成 1 制表符) 假如现在目录下有 main.cpp, class0.cpp, class1.cpp, 那么定义 DEP=main.d class0.d class1.d
将这句话插进上述源码中的开头位置然后 make 即可. h1. 怎么收拾掉乱七八糟的输出? 接脏活的临时工经常会反馈出一些无聊的信息, 比如进入这个离开那个的, 如果希望保持控制台的清洁, 那么把不想看的都扔进垃圾桶吧 make > /dev/null
不要担心看不到 warning 和 error, 它们是通过 stderr 输出的, 而上述重定向只会干扰 stdout.
Posted at Dec 07 2009 - 11:34:35
Permanent Link:
/p/63
Load full text
|
Post tags:
C
C++
Makefile
|
编译期数值计算程序设计思路
阅读这篇文章需要了解基本的 C++ 模板语法规则, 以及模板的泛化, 偏特化, 当然还包括完全特化这些基本概念. 这篇文章将给出基于 C++ 模板的 Metaprogramming 程序设计中需要注意的事项以及渐进式设计思路. 0. 基础这一段介绍 Metaprogramming 基础, 包括模板模式匹配规则, 使用模板实现循环或分支的基本方法. 对 Metaprogramming 已经有了解的同学可以跳过这一段. 本质上来说, 现代计算机的核心任务是数值计算, 周边任务是 I/O. 现代几个主流的编程语言, 如 C/C++/Java, 它们的语法组织方式与现代计算机的主流体系结构是 "平行" 的, 即, 语句的先后顺序表示它们的逻辑顺序, 而这种顺序与人的一贯思维顺序又是相同的 (在计算机中表达式的计算顺序会与书写顺序稍有不同, 但却很符合人类的思路); 可以说这是什么样的爹生什么样的崽, 什么样的人造什么样的语言和计算机. 然而, 在 C++ 模板世界中, 这个规则被打破了. 从分类上来说, Metaprogramming 更类似于函数式编程, 而不是传统的 C++ 程序设计. 在这个异世界中, 程序员不被允许使用循环或者分支语句, 包括函数返回语句都不允许: 在函数式编程中起码还有函数返回, 而在 Metaprogramming 中, 由于一切函数都没有被调用 (还在编译呢), 因此一切的值都谈不上返回, 它们只是存在于模板符号表中, 一旦编译结束便烟消云散. 当然, 没有循环, 分支这些编程语言中的基本元素, 并不意味着程序员只被允许设计顺序程序. 只不过, 在这里, 一切分流动作都被转化为了另一个语言特性: 模式匹配. (这一点与函数式编程非常相似) 下面一段代码展示了模式匹配的威力: Code Snippet 0-0
#include <iostream>
template <unsigned I> struct limit_to_2 { static unsigned const R = 2; };
template <> struct limit_to_2<1> { static unsigned const R = 1; };
template <> struct limit_to_2<0> { static unsigned const R = 0; };
int main(void) { std::cout << limit_to_2<0>::R << std::endl; std::cout << limit_to_2<1>::R << std::endl; std::cout << limit_to_2<2>::R << std::endl; std::cout << limit_to_2<3>::R << std::endl; return 0; }
模板 limit_to_2 为传入的整数设置了一个上限, 当传入模板的参数为 0 或者 1 时内部定义的 R 值与参数相同, 否则将 R 设置为 2. 这看起来很像是 switch-case 语句, 0 和 1 分别是两个 case, 而未特化的模板则是 default. 但是, 这样做有一些不方便, 如果所设的上限非常高, 那岂不是要为低于限制的情况写很多特化? 所以引入分支是非常必要的. 下面这个例子展示了如何利用模式匹配来实现编译期分支:
Posted at Dec 02 2009 - 03:00:11
Permanent Link:
/p/50
Load full text
|
Post tags:
Template
Metaprogramming
C++
|
划分问题与连续自然数幂和之通项公式
无限区间上 n 个不同的点可以把该区间分为多少段? 答案很明显, 当然是 (n + 1) 段啦. 另一个稍有难度的题目是, 无限平面上有n条直线, 问这些直线至多能把平面分成多少份? 在平面上画啊画就能归纳出解来的. 那么, 用 n 个平面, 最多能将无限三维空间划分成几个部分呢? 这个就略复杂了, 难道先建个 3D 模型, 然后归纳? 这个方法可行, 不过太浪漫和浪费了. 另外, 如果这个问题开始讨论维度更高的情形, 这种方法就行不通了. 那么, 问题来了: 使用 n 个 d 维 "*平整*" 的几何体, 来对无限 (d + 1) 维空间进行划分, 最多可以得到多少个部分? 不知道这个问题是否有官方名称了, 暂时称之为划分问题吧. 在这里, "平整" 指的是在该维度的空间中, 这些几何体的方程应该是线性的, 比如在 3 维空间中, 平面方程都可以表示为线性方程组 { $A_1 * x + B_1 * y = C_1$; $A_2 * x + B_2 * y = C_2$ }, 而在 1 维空间中的点就比较惨了, 就是 x = C, 不过还算是线性的. 其实大家只要有个基本的认识就行了, 不必这么刻板深究, 这篇文章中介绍的方法是没有严格证明的, 只是说说思路. 对能够画出来的各种维度进行一下归纳, 可以发现这样一个规律, 最开始开始的几次, 划分得到的空间区域是指数增长的: - 1 点分直线可以把直线分为 2 份
- 1 直线分平面可以把平面分为 2 份, 2直线分平面可以把平面分为 4 份
- 1 平面分空间可以把空间分为 2 份, 2平面分空间可以把空间分为 4 份, 3 平面分空间
可以把空间分为 8 份 这些规律可以*不完全归纳*假设为: n 个 d 维平整无限体分 (d + 1) 维无限体, 当 $n <= d$ 时, 可以分为 $2^n$ 份. 此外, 已知的结论有: - n 个点分直线至多将直线分为 (n + 1) 份;
- n 条直线分平面至多将平面分为 ($(n^2) / 2 + n / 2 + 1$) 份;
- n 个平面分空间至多将空间分为 ($(n^3) / 6 + 5 * n / 6 + 1$) 份;
所以再*不完全归纳*假设: n 个 d 维平整无限体分 (d + 1) 维无限体, 得到的份数 m 是 n 的一个幂多项式, 最高次项次数为 (d + 1). 由这些假设, 划分问题将可以用非常暴力的代数手段来解. n 个 d 维平整无限体分 (d + 1) 维无限体, 分得的空间数目 m 满足: $ m = a_d * n^(d+1) + a_(d-1) * n^d + ... + a_0 这里 $a_x$ 是该多项式的系数. 现在代入 (n, m) = {(0, 1), (1, 2), ..., (d, $2^d$)}, 得到一个 (d + 1) 元一次方程, 这样就可以唯一地解出 $a_d$, $a_(d-1)$, ..., $a_0$ 这 (d + 1) 个系数. 类似的 (未经证明的) 方法同样可以用来连续自然数幂求和问题: 对于自然数 m 和给定的自然数 n, 求通项公式 $ a(m) = 0^n + 1^n + 2^n + ... + m^n 同样, 设出通项公式方程 (注: 没有常数项) $ a(m) = a_k * m^(k+1) + a_(k-1) * m^k + ... + a_0 * m 然后根据没有化简的普通方程, 代入 m = { 1, ..., k }, 计算出前 k 个 a(m) (这个过程会很痛苦), 然后代入通项公式解方程 (唔, 这会更痛苦). 当然这只是另一个替代方案而已. Bernoulli 对自然数幂和公式的也做过研究, 他的方式是递推的, 运动量没有这个暴力方法大.
Posted at Nov 29 2009 - 01:39:18
Permanent Link:
/p/45
Load full text
|
Post tags:
Algebra
Algorithm
Geometry
|
泛型编程中的策略类
在编译期想要组合策略, 除开人肉内联不算, 有很多方式. 比如弄很多很多的 bool 参数 template <bool AllowDuplicate, bool SortElements, bool CheckOutOfRange> struct just_another_container;
这看起来就是一个参数灾难, 如果某个地方出点小的模板编译错误, 哼哼~ 当然, 另一种简单的替代方案就是把所有的 bool 整合在一起, 形成一个位段 template <unsigned Policy> struct just_another_container;
这种情况实际上缺点更多, 比如维护位域会很麻烦, 有可能在这个声明之前有这些枚举 enum { ALLOW_DUP_MASK = 1, SORT_ELE_MASK = 2, CHECK_OUT_OF_RANGE_MASK = 4, };
考虑这个容器有个 insert 函数, 它很可能需要考虑是否允许重复元素 template <unsigned AllowDuplicate> void insert(element_type e);
而令人郁闷的是, 在 C++ 中不允许给函数偏特化, 也就是说这样写 template <> void insert<0>(element_type e); template <> void insert<ALLOW_DUP_MASK>(element_type e);
是无法编译的! 要绕过这道坎, 得把 insert 函数放入一个模板结构体 template <unsigned AllowDuplicate> struct insert_s; template <> struct insert_s<ALLOW_DUP_MASK> { static void insert(just_a_container& container, element_type& e); };
这样做代价高昂, 首先, insert 被当作孤儿一样的抛弃, 那么类中的任何非 public 成员都不再对它开放, 当然, 为了这么个简单的小玩意儿声明 friend 也是可行的, 但是多了不觉得烦吗? 另外, 在调用策略行为进行特化时一般只针对特定的位, 那么将该策略位从组合策略中分离出来, 代码中将充斥着这样的运算 Policy & ALLOW_DUP_MASK Policy & CHECK_OUT_OF_RANGE_MASK
void another_member_function() { element_type ele; // wanna call insert function of policy = Policy insert_s<*Policy & ALLOW_DUP_MASK*>::insert(*this, ele); // ... }
这样做非常麻烦, 如果某个地方漏了 & 或者跟错误的掩码进行了运算, 哼哼~ 不过, 泛型程序设计有自己的方法, 那就是, 多继承! 不要吓到了, 是的, 在 C++ 远古时代, 多继承被认定为獠牙猛兽. 不过那都是跟 C++ 运行时多态相关的. 步入泛型新纪元的 C++ 又迎来了多继承第二春, 它可以显著改善上述问题. 将上面的声明编程 template <*typename Policy*> struct just_another_container;
struct policy_base {}; struct allow_dup : public policy_base {}; struct sort_ele : public policy_base {}; struct check_out_of_range : public policy_base {};
组合策略, 只需要声明一个策略类型继承想要的策略, 并把它传入容器就能达到目的, 比如
Posted at Nov 22 2009 - 08:56:30
Permanent Link:
/p/36
Load full text
|
Post tags:
Generic Programming
C++
Template
|
闰年判定
Posted at Nov 17 2009 - 00:33:38
Permanent Link:
/p/25
Load full text
|
Post tags:
Algorithm
|
已知两圆圆心坐标及半径求两圆交点
在一个二维平面上给定两个圆的圆心横纵坐标、半径共 6 个参数, 求交点. 即实现下面的 C 函数 int intersect(struct circle_t const circles[], struct point_t intersections[]);
其中 point_t 与 circle_t 的定义分别是 Code Snippet 0-0
struct point_t { double x; double y; };
struct circle_t { point_t center; double r; };
函数 intersect 的输入参数为两个圆, 返回交点个数, 另外, 交点详细信息将被存入另一个参数数组 intersections 中. 由于两个圆之多有 2 个交点, 因此该函数可以如下形式调用: Code Snippet 0-1
#include <stdio.h>
int main(void) { struct circle_t circles[2]; struct point_t points[2];
/* 从 stdin 输入圆参数 * 按照如下格式 * $(x_0, y_0, r_0)$ * $(x_1, y_1, r_1)$ */ scanf("%lf%lf%lf%lf%lf%lf", &circles[0].center.x, &circles[0].center.y, &circles[0].r, &circles[1].center.x, &circles[1].center.y, &circles[1].r);
// 如果两个圆相同 // *注意:* 由于 x, y, r 都是浮点数, 使用 == 进行判同可能导致问题 // 作为示例代码还是姑且这么写了 if (circles[0].center.x == circles[1].center.x && circles[0].center.y == circles[1].center.y && circles[0].r == circles[1].r) { puts("The circles are the same."); return 0; }
switch (*intersect(circles, points)*) { case 0: puts("No intersection."); break; case 1: printf("(%.3lf %.3lf)n", points[0].x, points[0].y); break; case 2: printf("(%.3lf %.3lf) (%.3lf %.3lf)n", points[0].x, points[0].y, points[1].x, points[1].y); } return 0; }
用程序实现求交点方法可以有多种, 比较极端的甚至可以用到二分逼近, 反正计算机的计算能力跟笔算是两个世界; 不过本文还是老实一点, 仍试着来解方程. 在求解过程中, 除了用到圆的标准方程 $ (x - x_0)^2 + (y - y_0)^2 = r_0^2 (其中 $(x_0, y_0)$ 是其中一个圆的圆心, $r_0$ 是其半径; 当然对另一圆也是如此, 此处省略之) 圆的参数方程也将会被用到 现在, 设其中其中至少有一个交点 (没有交点的情况可以简单利用圆心距大于半径之和来判定), 换言之存在某个 $A_s$ 使得存在对应的点 $(x_s, y_s)$ 于两个圆的方程都成立, 即
Posted at Nov 15 2009 - 14:56:09
Permanent Link:
/p/14
Load full text
|
Post tags:
Algorithm
C
Geometry
|
0
1
2
3
4
5
6
7
8
9
10
11
Page 12
|