02.uliweb开发入门
TRANSCRIPT
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
自动忽略
创建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==页面展示
首页#coding=utf-8
from uliweb import expose, functions
@expose('/')
class TodoView(object):
@expose('')
def list(self):
return {}
views.py
编码声明
类方式
URL合并
返回值决定模板套用
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© 作者:</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
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© 作者: {{=settings.TODO.auth}}
</div>
块定义
变量引用
模板基本语法• 模板变量引用 {{=xxx}}(转义) {{<<xxx}}(不转义)
• {{block name}}{{end}}块定义以及引用
• {{extend “template.html”}}引用父模板
• {{include “template.html”}}包含其它模板
• {{语句}}定义其它的python语句,缩近以{{pass}}结束,支持多行语句
• {{## ##}}多行注释 {{#}}单行注释
关于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)
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© 作者: {{=settings.TODO.auth}}
</div>
</div>
{{end}}
TodoView/list.html
模板继承
块覆盖
模型管理
• 在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
查询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的底层结构
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部分
{{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
后台交互
更新完成状态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
更新完成时间
修改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