About
RSS

Bit Focus


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, 让它将表单数据存入数据库, 并重定向回到首页

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, 在里面加一句话

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.

Permanent Link: /p/63 Load full text

Post tags:

 C
 C++
 Makefile

编译期数值计算程序设计思路

阅读这篇文章需要了解基本的 C++ 模板语法规则, 以及模板的泛化, 偏特化, 当然还包括完全特化这些基本概念. 这篇文章将给出基于 C++ 模板的 Metaprogramming 程序设计中需要注意的事项以及渐进式设计思路.

0.0.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.

但是, 这样做有一些不方便, 如果所设的上限非常高, 那岂不是要为低于限制的情况写很多特化? 所以引入分支是非常必要的. 下面这个例子展示了如何利用模式匹配来实现编译期分支:

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 对自然数幂和公式的也做过研究, 他的方式是递推的, 运动量没有这个暴力方法大.

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 {};

组合策略, 只需要声明一个策略类型继承想要的策略, 并把它传入容器就能达到目的, 比如

Permanent Link: /p/36 Load full text

Post tags:

 Generic Programming
 C++
 Template

闰年判定

已经转移到

http://zlo.gs/p/neuront/leap-year-test-algorithm

Permanent Link: /p/25 Load full text

Post tags:

 Algorithm

已知两圆圆心坐标及半径求两圆交点

在一个二维平面上给定两个圆的圆心横纵坐标、半径共 6 个参数, 求交点. 即实现下面的 C 函数

int intersect(struct circle_t const circles[], struct point_t intersections[]);

其中 point_tcircle_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$ 是其半径; 当然对另一圆也是如此, 此处省略之) 圆的参数方程也将会被用到

$ x = r_0 * cos(A) + x_0

$ y = r_0 * sin(A) + y_0

现在, 设其中其中至少有一个交点 (没有交点的情况可以简单利用圆心距大于半径之和来判定), 换言之存在某个 $A_s$ 使得存在对应的点 $(x_s, y_s)$ 于两个圆的方程都成立, 即

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


. Back to Bit Focus
NijiPress - Copyright (C) Neuron Teckid @ Bit Focus
About this site