02.uliweb开发入门

70
Uliweb发入门

Upload: modou-li

Post on 15-Jul-2015

75 views

Category:

Software


10 download

TRANSCRIPT

Uliweb开发入门

开发一个Todo程序

Uliweb安装

• 如果是稳定版本,可以使用 pip install uliweb

• 如果使用开发版本,可以:

git clone [email protected]:limodou/uliweb.git

还可以从oschina, csdn找到镜像

cd uliweb

python setup.py develop

创建项目

• uliweb makeproject todo_project

├── .gitignore

├── apps

│ ├── __init__.py

│ ├── local_settings.ini

│ └── settings.ini

├── requirements.txt

├── setup.py

└── wsgi_handler.py

自动忽略

用git来管理版本

• git init

• git add .

• git status

• git commit –m “message”

创建APP• cd todo_project

uliweb makeapp todo

├── apps

│ └── todo

│ ├── __init__.py

│ ├── conf.py

│ ├── info.ini

│ ├── static

│ │ └── readme.txt

│ ├── templates

│ │ └── readme.txt

│ └── views.py

MVC vs MVT

• M(Model) V(View) C(Control)

• uliweb采用:Model, View, Template

• View==Control+View的功能

• Template==页面展示

运行

• uliweb runserver –thread

uliweb help runserver

uliweb runserver –h 0.0.0.0 –p 8001

功能设计

• 显示待办

• 增加

• 完成

• 删除

将要用到的功能

• 模板

• 类方式的View

• ORM

• settings.ini配置

首页#coding=utf-8

from uliweb import expose, functions

@expose('/')

class TodoView(object):

@expose('')

def list(self):

return {}

views.py

编码声明

类方式

URL合并

返回值决定模板套用

View返回值处理

• 字典(dict)将自动套用模板,根据function的名字或类方法的名字

• 非dict将转为字符串返回

views.py

<!DOCTYPE html>

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<title>Todo</title>

<link href="/static/todo.css" rel="stylesheet" type="text/css" />

</head>

<body>

<div id="todos">

<h1>TODO</h1>

<div class="list">

</div>

<div class="footer">

Copyright&copy; 作者:</div>

</div>

</body>

</html>

TodoView/list.html

HTML5

UTF8编码

静态文件,可以使用link或url_for_static

可以传入配置或变量

views.py

[GLOBAL]

DEBUG = False

DEBUG_CONSOLE = False

DEBUG_TEMPLATE = False

INSTALLED_APPS = [

'uliweb.contrib.staticfiles',

'uliweb.contrib.template',

# 'uliweb.contrib.upload',

'uliweb.contrib.orm',

# 'uliweb.contrib.session',

# 'uliweb.contrib.cache',

# 'uliweb.contrib.auth',

'uliweb.contrib.i18n',

# 'uliweb.contrib.flashmessage',

'todo',

]

TodoView/list.html

调试相关

ORM

国际化

静态文件

USE, LINK

settings.ini

静态文件404

views.py

#todos {margin:0 auto;width:914px;height:100%;}

#todos h1 {text-align:center;}

#todos .footer {margin:0 auto;width:914px;height:80px;background-

color:whitesmoke;text-align:center;line-height:80px;}

TodoView/list.html settings.ini static/todo.css

模板修改

<div class="list">

<div class="tools">

<a href='/add'>添加</a>

</div>

<ul>

<li><input type="checkbox"></input>Todo1

<a href='/delete/id'>删除</a>

</li>

</ul>

</div>

TodoView/list.html

添加

完成/未完成

删除

CSS调整#todos {margin:0 auto;width:914px;height:100%;}

#todos h1 {text-align:center;}

#todos .footer {margin:0

auto;width:914px;height:80px;background-

color:whitesmoke;text-align:center;line-height:80px;}

#todos .tools a {text-decoration:none;}

#todos .tools a:hover {text-decoration:underline;}

#todos ul {list-style:none;}

#todos ul li {list-style:none;}

链接效果

取消列表效果

static/todo.css

模板变量

<title>{{block title}}Todo{{end}}</title>

<div class="footer">

Copyright&copy; 作者: {{=settings.TODO.auth}}

</div>

块定义

变量引用

模板基本语法• 模板变量引用 {{=xxx}}(转义) {{<<xxx}}(不转义)

• {{block name}}{{end}}块定义以及引用

• {{extend “template.html”}}引用父模板

• {{include “template.html”}}包含其它模板

• {{语句}}定义其它的python语句,缩近以{{pass}}结束,支持多行语句

• {{## ##}}多行注释 {{#}}单行注释

模板变量的获得

• 通过view return dict

• 通过模板内置的对象,如functions, settings

• 通过嵌入python代码

出错处理

代码与查看

关于local_settings.ini[GLOBAL]

DEBUG = True

DEBUG_CONSOLE = True

DEBUG_TEMPLATE = False

[GLOBAL]

DEBUG = False

DEBUG_CONSOLE = False

DEBUG_TEMPLATE = False

settings.ini

• local_settings.ini不会自动添加到git中,参见.gitignore

• 不同的环境可以有不同的local_settings.ini

• 调试功能在生产时建议关闭

• DEBUG_CONSOLE只在单进程时有效,对于使用uwsgi的无效。并且存在代码执行风险。

说明

控制台输出

日志调试

• 简单情况下使用print

• 还可以使用log

import logging

log = logging.getLogger(‘__name__’)

log.info(message)

log.debug(message)

log.error(message)

log.exception(e)

添加todo/settings.ini

[TODO]

auth = 'todo'

settings继承处理

• default_settings.ini

• app/settings.ini

• apps/settings.ini

• apps/local_settings.ini

• 同名替换或合并,根据值的类型,对于list, dict合并,不可变类型替换

模板继承

• 根据复用情况将模板进行切分

layout.html

list.html

{{block name}}{{end}}

{{extend “layout.html”}}

{{block name}}

内容{{end}}

<!DOCTYPE html>

<html>

<head>

<meta http-equiv="Content-Type" content="text/html;

charset=utf-8" />

<title>{{block title}}Todo{{end}}</title>

<link href="/static/todo.css" rel="stylesheet"

type="text/css" />

</head>

<body>

{{block content}}{{end}}

</body>

</html>

TodoView/layout.html

{{extend "TodoView/layout.html"}}

{{block content}}

<div id="todos">

<h1>TODO</h1>

<div class="list">

<div class="tools">

<a href='/add'>添加</a>

</div>

<ul>

<li><input type="checkbox"></input>Todo1

<a href='/delete/id'>删除</a>

</li>

</ul>

</div>

<div class="footer">

Copyright&copy; 作者: {{=settings.TODO.auth}}

</div>

</div>

{{end}}

TodoView/list.html

模板继承

块覆盖

使用数据库前准备

• 添加 ‘uliweb.contrib.orm’

• 安装数据库相关的包:sqlalchemy, mysqldb等

• 配置数据库连接

• 创建数据库,分配用户等

模型管理

• 在app下创建models.py,添加相关的Model类

• 在app/settings.ini下添加[MODELS]配置信息

• 使用uliweb syncdb或uliweb alembic来更新数据库

• 使用。。。

添加Todo类#coding=utf8

from uliweb.orm import *

class Todo(Model):

title = Field(str, max_length=256, verbose_name='标题')

finished = Field(bool, verbose_name='是否完成')

finished_time = Field(datetime.datetime,

verbose_name='完成时间')

models.py

导入相关对象

定义Model

定义字段

配置settings.ini

[TODO]

auth = 'todo'

[MODELS]

todo = 'todo.models.Todo'

建议小写 Model路径

todo/settings.ini

同步数据库• uliweb syncdb –v

• 当表不存在时创建,修改无效

• 缺省使用sqlite数据库,否则要手工配置CONNECTION

查询todos@expose('/')

class TodoView(object):

def __init__(self):

self.model = functions.get_model('todo')

@expose('')

def list(self):

todos = self.model.all()

return {'todos':todos} 获得所有记录

返回结果,传入模板

获得todo表

显示所有记录<li><input type="checkbox"></input>Todo1

<a href='/delete/id'>删除</a>

</li>

{{for todo in todos:}}

<li><input type="checkbox" {{if

todo.finished:}}checked{{pass}}></input>{{=todo.title}}

<a href='/delete/{{=todo.id}}'>删除</a>

</li>

{{pass #end of for}}

for循环

for循环结束

todo ID

判断

templates/list.html

关于Model(一)

• 自动创建ID字段(自增字段)

• 支持常见数据类型:varchar, char, decimal, text,

blob, datetime, integer等

• 可以创建唯一约束unique=True

• 可以创建单字段索引idnex=True或联合索引@classmethod

def OnInit(cls):

Index(‘name’, cls.c.field, cls.c.field, unique=True)

关于Model(二)

• Model相当于表,可以通过Model.tablename获得表名

• 实例相关于记录,可以通过Model.get(), Model.filter(),

Model.all()来获得单条或多条记录

• 还可以通过get_object(modelname, id)来获得记录

• 表级方法:filter(), all(), count()

• 实例级方法:save(), delete(), update()

关于结果集

• Model.filter(), Model.all()返回的是结果集,可以在结果集上再次调用结果集的方法:filter(), count(),

values(), fields()等

Model的底层结构

Model.table ====> Table

Model.property ====> Property

Model.c.property ====> Column

Model Table

Property Column

添加todo

def add(self):

if request.method == 'GET':

return {}

else:

todo = self.model(title=request.POST['title'])

todo.save()

return redirect(url_for(TodoView.list))

区分请求方法

没有expose,自动生成

创建实例

保存生效

重定向 反向获取URL

views.py

编写add.html{{extend "TodoView/layout.html"}}

{{block content}}

<form action="" method="POST">

<label for="field_title">Todo内容:</label>

<input type="text" name="title" id="field_title"></input>

<div>

<button type="submit">提交</button> <a href="/">返回</a>

</div>

</form>

{{end}}

TodoView/add.html

模板继承

删除处理

def delete(self, id):

todo = self.model.get(int(id))

todo.delete()

Redirect(’/')

带参数会生成 /delete/<id>

获得指定记录,id是字符串

删除记录,并提交

重定向

views.py

URL参数与Query_string

• URL的格式:http://domain:port/path?k=v

其中?后面是query_string

• URL参数是URL在解析时生成的,相关于只解析path

部分

• query_string则对应request.GET部分

完成Todo功能

• 使用jquery来处理前端交互,点击checkbox实现完成状态的切换

• 通过jquery与后台通讯

{{block content}}

{{link "jquery-1.11.1.min.js"}}

<div id="todos">

{{for todo in todos:}}

<li {{if todo.finished:}}class="finished"{{pass}}>

<input type="checkbox" {{if

todo.finished:}}checked{{pass}} data-

id={{=todo.id}}></input>

<span class="title">{{=todo.title}}</span>

<a href='/delete/{{=todo.id}}'>删除</a>

</li>

{{pass}}

TodoView/list.html

引用jquery

1

2

增加样式

使用span为了区分样式

保存ID

TodoView/list.html

<script>

$(function(){

$('#todos :checkbox').click(function(e){

var $this = $(this);

var checked = $this.is(':checked');

var id = $this.data('id');

var parent = $($this.parents('li')[0]);

$.post('/update', {id:id, finished:checked}).success(function(r){

if(r.success){

if(checked)

parent.addClass('finished');

else

parent.removeClass('finished');

}else{

alert(r.message);

}

});

});

});

</script>

3

后台交互

添加finished的样式

#todos ul li.finished .title{text-decoration:line-through;}

todo.css

更新完成状态def update(self):

from uliweb.utils improt date

id = request.POST['id']

finished = request.POST['finished'] == 'true'

todo = self.model.get(int(id))

todo.finished = finished

if finished:

todo.finished_time = date.now()

else:

todo.finished_time = None

todo.save()

return json({'success':True})

views.py

填写当前时间

增加创建时间和完成时间#coding=utf8

from uliweb.orm import *

class Todo(Model):

title = Field(str, max_length=256, verbose_name='

标题')

finished = Field(bool, verbose_name='是否完成')

created_time = Field(datetime.datetime,

verbose_name='创建时间’, auto_now_add=True)

finished_time = Field(datetime.datetime,

verbose_name='完成时间')

models.py

自动填充时间

更新表结构

• 简单可以使用uliweb dump

uliweb reset

uliweb load

• 建议使用 alembic

pip install uliweb-alembic

uliweb alembic init

uliweb alembic diff

uliweb alembic upgrade

修改list.html(一){{for todo in todos:}}

<li {{if todo.finished:}}class="finished"{{pass}}>

<input type="checkbox" {{if

todo.finished:}}checked{{pass}} data-

id={{=todo.id}}></input>

<span class="title">{{=todo.title}}</span>

<span

class="time">({{=todo.created_time.strftime("%Y/%m/%

d")}}-{{=todo.finished_time and

todo.finished_time.strftime("%Y/%m/%d") or ''}})</span>

<a href='/delete/{{=todo.id}}'>删除</a>

</li>

{{pass}}TodoView/list.html

增加时间显示

修改list.html(二)$.post('/update', {id:id, finished:checked}).success(function(r){

if(r.success){

if(checked)

parent.addClass('finished');

else

parent.removeClass('finished');

var time = parent.find('.time');

var t = time.text().split('-');

t[1] = r.finished_time;

time.text(t.join('-')+') ');

}else{

alert(r.message);

}

});

TodoView/list.html

更新完成时间

修改todo.css

#todos ul li .time{color:gray;font-size:80%;}

todo.css

修改updatedef update(self):

from uliweb.utils import date

id = request.POST['id']

finished = request.POST['finished'] == 'true'

todo = self.model.get(int(id))

todo.finished = finished

if finished:

todo.finished_time = date.now()

finished_time = todo.finished_time.strftime('%Y/%m/%d')

else:

todo.finished_time = None

finished_time = ''

todo.save()

return json({'success':True, 'finished_time':finished_time})

views.py

处理完成时间

├── apps

│ ├── __init__.py

│ ├── local_settings.ini

│ ├── settings.ini

│ └── todo

│ ├── __init__.py

│ ├── conf.py

│ ├── info.ini

│ ├── models.py

│ ├── settings.ini

│ ├── static

│ │ ├── jquery-1.11.1.min.js

│ │ └── todo.css

│ ├── templates

│ │ └── TodoView

│ │ ├── add.html

│ │ ├── layout.html

│ │ └── list.html

│ └── views.py

├── .gitignore

├── requirements.txt

├── setup.py

└── wsgi_handler.py

相关资源

• 文档: http://limodou.github.io/uliweb-

doc/zh_CN/basic.html

Q&A