概述
最美代码
web2py官方文档翻译
2016年2月10日
启动
web2py进来二进制包为Windows和Mac OS x包括Python解释器,所以你不需要预装。 还有一个源代码版本运行在Windows,Mac,Linux和其他Unix系统。 Windows和mac OS X的二进制版本包括必要的Python解释器。 Python源代码包假设已经安装在电脑上。
web2py不需要安装。 首先,解压缩下载的zip文件的特定的操作系统和相应的执行 web2py 文件。
在Windows上,运行:
web2py.exe
在OS X上,运行:
open web2py.app
Unix和Linux上运行从源通过键入:
python2.5 web2py.py
在Windows上运行web2py首先从源代码安装 马克·哈蒙德的“Windows扩展Python 然后运行:
python2.5 web2py.py
web2py程序接受各种命令行选项稍后讨论。
默认情况下,在启动时,web2py显示启动窗口,然后显示一个GUI窗口小部件,要求你选择一个一次性的管理员密码,网络接口的IP地址用于web服务器,和一个服务请求的端口号。 默认情况下,web2py 127.0.0.1:8000上运行的web服务器(本地主机端口8000上),但是您可以运行在任何可用的IP地址和端口。 您可以查询您的网络接口的IP地址,打开一个命令行和打字 ipconfig 在Windows或 ifconfig 在OS X和Linux。 从现在开始我们假设web2py在本地主机上运行(127.0.0.1:8000)。 使用0.0.0.0:80运行web2py公开你的网络接口。
如果你不提供管理员密码,管理界面是禁用的。 这是一个安全措施,以防止公开揭露管理界面。
管理界面, 管理 ,只能从本地主机访问,除非你使用mod_proxy运行背后web2py Apache。 如果 管理 检测到一个代理,会话cookie设置为安全 管理 登录不工作,除非客户端和代理之间的通信在HTTPS;这是一个安全措施。 所有客户端之间的通信 管理 必须是本地或加密;否则攻击者能够执行一个人中间人攻击和重放攻击和在服务器上执行任意代码。
管理密码已经设置后,web2py启动web浏览器在页面:
http://127.0.0.1:8000/
如果计算机没有一个默认的浏览器,打开一个web浏览器并输入URL。
点击“管理界面”带你去管理界面登录页面。
管理员密码是您选择在启动时的密码。 请注意,只有一个管理员,因此只有一个管理员密码。 出于安全原因,开发人员被要求选择一个新密码每次web2py开始,除非指定的选项。 这是有别于web2py应用程序的身份验证机制。
管理员登录web2py之后,浏览器重定向到“网站”页面。
这个页面列出了所有web2py安装应用程序和允许管理员管理。 web2py有三个应用程序:
• 一个 管理 应用程序,现在您正在使用。
• 一个 例子 与在线交互式应用程序,文档和web2py官方网站的副本。
• 一个 欢迎 应用程序。 这是基本的任何其他web2py应用程序的模板。 它被称为脚手架应用程序。 这也是欢迎用户在启动的应用程序。
被称为web2py即食web2py应用程序 电器 。 你可以下载许多免费的电器 ( 电器 ] 。 web2py鼓励用户提交新的家电,无论是开源还是闭源(编译和打包)形式。
从 管理 应用程序的 网站 页面中,您可以执行以下操作:
• 安装 应用程序通过完成表单页面的右下角。 向应用程序提供一个名称,选择文件包含一个打包的应用程序或应用程序所在的URL,并单击“提交”。
• 卸载 应用程序通过单击相应的按钮。 有一个确认页面。
• 创建 一个新的应用程序,选择一个名称并单击“创建”。
• 包 申请分布通过单击相应的按钮。 一个包含所有的下载应用程序是一个tar文件,包括数据库。 你不应该将此文件解压,安装时由web2py自动散装的 管理 。
• 清理 应用程序的临时文件,如会议、错误和缓存文件。
• 编辑 一个应用程序。
当您创建一个新的应用程序使用 管理 ,它开始作为一个克隆的“欢迎”脚手架应用“模型/ db。 py”创建了一个SQLite数据库,连接到它,实例化Auth,Crud和服务、配置它们。 它还提供了一个“控制器/违约。 py”公开行动”指数”、“下载”、“用户”为用户管理、和“调用”服务。 在下面,我们假设这些文件已经被删除,我们将从头开始创建应用程序。
web2py还附带了一个 向导 描述在本章后面,可以编写另一个脚手架代码基于布局和web上可用的插件和基于高水平的描述模型。
说“你好”
在这里,作为一个例子,我们创建一个简单的web应用程序,它显示消息“你好MyApp”给用户。 我们将调用这个应用程序“myapp”。 我们还将添加一个计数器计数多少次相同的用户访问页面。
您可以创建一个新的应用程序,只需输入它的名字的右上方 网站 页 管理 。
你按下【创建】后,应用程序创建内置欢迎应用程序的副本。
运行新的应用程序,请访问:
http://127.0.0.1:8000/myapp
现在你有一个受欢迎的应用程序的副本。
编辑应用程序,点击 设计 为新创建的应用程序按钮。
的 编辑 页面告诉你什么是内部应用程序。 每个web2py应用程序包含某些文件,其中大部分落入isx类别之一:
• 模型 :描述数据表示。
• 控制器 :描述应用程序逻辑和工作流。
• 的观点 :描述数据表示。
• 语言 :描述如何翻译应用程序演示其他语言。
• 模块 :Python模块属于应用程序。
• 静态文件 :静态图像、CSS文件 ( css-w、css-o css-school ] JavaScript文件 ( js-w,js-b ] 等。
• 插件 :组文件旨在一起工作。
所有东西都是整齐有序的模型-视图-控制器设计模式。 每个部分的 编辑 页面对应于应用程序文件夹的子文件夹。
注意小节标题将切换他们的内容。 文件夹名称下的静态文件也可折叠。
节中列出的每个文件对应一个文件物理位置的子文件夹。 任何操作上执行一个文件通过 管理 接口(创建、编辑、删除)可以直接从shell执行使用您喜欢的编辑器。
应用程序包含其他类型的文件(数据库、会议文件、错误文件,等等),但他们不上市 编辑 页,因为他们不是管理员创建或修改的;他们创建和修改应用程序本身。
控制器包含应用程序的逻辑和工作流。 每个URL被映射到调用一个函数控制器(行动)。 有两个默认控制器:“appadmin。 py”和“default.py”。 appadmin 提供数据库管理界面,我们现在不需要它。 “默认。 py”是您需要编辑控制器,一个叫做默认情况下当没有控制器在URL中指定。 编辑“指数”功能如下:
def index():
return "Hello from MyApp"
这是在线编辑器是什么样子:
保存它并回到 编辑 页面。 单击索引访问新创建的页面的链接。
当你访问的URL
http://127.0.0.1:8000/myapp/default/index
索引操作在默认myapp应用程序的控制器。 它返回一个字符串,我们的浏览器显示。 它应该是这样的:
现在,编辑“指数”功能如下:
def index():
return dict(message="Hello from MyApp")
也从 编辑 “默认/索引页面,编辑视图。 html”(与行动相关联的视图文件)和完全替换现有的文件内容如下:
{{=message}}
现在定义一个操作返回一个字典 消息 。 当一个动作返回一个字典,web2py查找视图的名称
[控制]/[功能]。(扩展)
并执行它。 (扩展)是所请求的扩展。 如果没有指定扩展,它默认为“html”,这就是我们将假定。 在这种假设下,视图是一个HTML文件,它嵌入Python代码使用特殊的{ { } }标记。 特别是,在这个例子中, { { =消息} } 指示web2py标记代码替换的值 消息 返回的行动。 请注意, 消息 这里不是web2py字但中定义的行动。 到目前为止,我们没有使用任何web2py关键词。
如果web2py没有找到所请求的视图,它使用“通用。 html”视图,每个应用程序。
如果指定“html”以外的一个扩展(例如“json”)和视图文件”[控制]/[功能]。 json”不是发现,web2py查找视图”generic.json”。 web2py通用。 html,通用。 json,通用的。 xml和generic.rss。 这些通用视图可以修改单独为每个应用程序,可以轻松地添加和额外的视图。
通用视图是一个开发工具。 在生产中每一个行动都应该有自己的观点。 实际上,默认情况下,通用视图只能从本地主机启用。
您还可以指定一个视图 响应。 视图= '默认/ something.html '
在第十章阅读更多关于这个主题。
如果你回到“编辑”,点击指数,现在,您将看到以下HTML页面:
用于调试目的你可以随时添加
{{=response.toolbar()}}
代码在一个视图,它将向您展示一些有用的信息,包括请求、响应和会话对象,与他们的时间列出所有数据库查询。
让我们数
现在让我们将一个计数器添加到这个页面,将数多少次相同的访问者显示页面。
web2py自动、透明地追踪访客使用会话和饼干。 为每个新访客,它会创建一个会话,并分配一个独一无二的“session_id”。 会话变量,存储服务器端是一个容器。 惟一的id发送给浏览器通过一个饼干。 当访问者请求另一个页面相同的应用程序中,浏览器发送cookie,它由web2py检索,和相应的会话恢复。
使用会话,修改默认的控制器:
def index():
if not session.counter:
session.counter = 1
else:
session.counter += 1
return dict(message="Hello from MyApp", counter=session.counter)
请注意, 计数器 不是web2py字但 会话 是多少。 我们要求web2py检查是否有一个计数器变量在会话中,如果没有的话,创建一个设置为1。 如果计数器是那里,我们问web2py增加计数器加1。 最后我们将计数器的值传递给视图。
更紧凑的代码相同的功能的方法是这样的:
def index():
session.counter = (session.counter or 0) + 1
return dict(message="Hello from MyApp", counter=session.counter)
现在修改视图添加一行显示计数器的值:
{{=message}}
Number of visits: {{=counter}}
当你再次访问索引页面(再一次)你应该得到以下HTML页面:
柜台与每个访问者相关联,并增加访问者每次重新加载页面。 不同的游客看到不同的计数器。
说我的名字
现在创建两页(第一和第二),在第一页创建一个表单,问客人的名字,和重定向到第二页,迎接客人的名字。
写相应的操作在默认的控制器:
def first():
return dict()
def second():
return dict()
然后创建一个视图“默认/第一。 html“第一行动,并输入:
{{extend 'layout.html'}}
What is your name?
最后,创建一个视图“默认/秒。 html”第二个行动:
{{extend 'layout.html'}}
Hello {{=request.vars.visitor_name}}
在这两种观点都有扩展的基本布局。 伴随着web2py的html”视图。 布局视图使两页一致的外观和感觉。 布局文件可以很容易地编辑和取代,因为它主要包含HTML代码。
如果你现在访问的第一个页面,输入你的名字:
并提交表单,您将收到一个祝福:
回发
表单提交之前,我们使用的机制是很常见的,但它不是良好的编程实践。 应验证所有输入,在上面的例子中,验证的负担将落在第二个行动。 因此,行动执行验证不同于生成表单的动作。 这往往导致代码冗余。
表单提交的一个更好的模式是生成它们的提交形式相同的动作,在我们的示例中“第一”。 “第一”的行动应该接收的变量,处理它们,将它们存储的服务器端,并将用户重定向到“第二”页面,它检索变量。 这种机制被称为 回发 。
修改默认的控制器来实现self-submission:
def first():
if request.vars.visitor_name:
session.visitor_name = request.vars.visitor_name
redirect(URL('second'))
return dict()
def second():
return dict()
然后修改“默认/第一。 html”观点:
{{extend 'layout.html'}}
What is your name?
和“默认/秒。 html”视图需要检索的数据 会话 而不是从 request.vars :
{{extend 'layout.html'}}
Hello {{=session.visitor_name or "anonymous"}}
从游客的角度,self-submission行为前实现一模一样。 我们没有添加验证,但现在清楚的是,验证应该首先执行的行动。
这种方法也更好,因为客人的名称保持在会话中,并且可以访问所有操作和视图的应用程序,而不必被显式传递。
注意,如果“第二”行动是以前称为访客的名字,它会显示“你好匿名”,因为 session.visitor_name 返回 没有一个 。 或者我们可以添加下面的代码在控制器(内 第二个 函数):
if not request.function=='first' and not session.visitor_name:
redirect(URL('first'))
这是一个通用的机制,您可以使用控制器执行授权,但见第9章为一个更强大的方法。
web2py我们可以移动一步,问web2py生成表单,包括验证。 web2py提供帮手(形式输入,文本区域,并选择/选项)以相同的名称为等价的HTML标记。 他们可以用来建造形式在控制器或视图。
例如,这是一个可能的方式改写第一个行动:
def first():
form = FORM(INPUT(_name='visitor_name', requires=IS_NOT_EMPTY()),
INPUT(_type='submit'))
if form.process().accepted:
session.visitor_name = form.vars.visitor_name
redirect(URL('second'))
return dict(form=form)
我们说的形式标记包含两个输入标签。 输入标签的属性指定的命名参数开始凸显。 的 需要 参数不是一个标签属性(因为它不首先强调)但这集的验证器visitor_name的价值。
这是另一个更好的窟创建相同的形式:
def first():
form = SQLFORM.factory(Field('visitor_name', requires=IS_NOT_EMPTY()))
if form.process().accepted:
session.visitor_name = form.vars.visitor_name
redirect(URL('second'))
return dict(form=form)
的 形式 对象可以很容易地序列化在HTML中嵌入在“默认/。 html”视图。
{{extend 'layout.html'}}
What is your name?
{{=form}}
的 form.process() 方法应用验证器并返回形式本身。 的 form.accepted 变量设置为True如果表单处理并通过验证。 如果self-submitted形式通过验证,它将变量存储在会话和重定向。 如果表单没有通过验证,错误消息插入到表单并显示给用户,如下:
在下一节中我们将展示形式可以从模型自动生成。
一个图像的博客
这里,作为另一个例子,我们希望创建一个web应用程序,允许管理员发布图片和给他们一个名字,并允许web站点的访问者查看指定的图像并提交评论。
和之前一样,从 网站 页 管理 ,创建一个新的应用程序 图片 ,并导航到 编辑 页面:
我们首先创建一个模型,持久数据在应用程序的表示(上传的图片,他们的名字和注释)。 首先,您需要创建/编辑的模型文件,缺乏想象力,我们称之为“db.py”。 我们假设以下代码将取代任何现有代码“db.py”。 模型和控制器必须有一个 . py 因为它们是Python代码扩展。 如果不提供扩展,它由web2py附加。 相反,有一个观点 . html 因为他们主要包含HTML代码扩展。
编辑db。 py”文件,点击相应的“编辑”按钮:
输入以下:
db = DAL("sqlite://storage.sqlite")
db.define_table('image',
Field('title', unique=True),
Field('file', 'upload'),
format = '%(title)s')
db.define_table('comment',
Field('image_id', db.image),
Field('author'),
Field('email'),
Field('body', 'text'))
db.image.title.requires = IS_NOT_IN_DB(db, db.image.title)
db.comment.image_id.requires = IS_IN_DB(db, db.image.id, '%(title)s')
db.comment.author.requires = IS_NOT_EMPTY()
db.comment.email.requires = IS_EMAIL()
db.comment.body.requires = IS_NOT_EMPTY()
db.comment.image_id.writable = db.comment.image_id.readable = False
让我们逐行分析。
第一行定义了一个全局变量 db 表示数据库连接。 在这种情况下,它是一个连接到一个SQLite数据库中存储的文件“应用程序/图片/数据库/ storage.sqlite”。 在SQLite的情况下,如果数据库不存在,就创建一个。 你可以改变文件的名称,以及全局变量的名称 db ,但它是方便给他们相同的名称,使它容易记住。
3 - 5行定义一个表“形象”。 define_table 的方法吗 db 对象。 “形象”,第一个参数是我们定义的表的名称。 其他参数是属于该表的字段。 这个表有一个字段称为“标题”,一个字段称为“文件”,“id”字段作为表主键(“id”不是显式声明,因为所有表都有一个id字段默认情况下)。 “标题”是一个字符串,和类型的字段“文件”“上传”。 “上传”是一种特殊类型的字段web2py所使用的数据抽象层(DAL)来存储上传的文件的名称。 web2py知道如何上传文件(通过流媒体如果他们大),重命名它们安全,存储它们。
当一个表定义,web2py几个可能的行动之一:
• 如果表不存在,创建表;
• 如果表存在,不对应的定义、表相应改变,如果一个领域有不同的类型,web2py试图将其内容;
• 如果表存在,对应于定义,web2py什么也不做。
这种行为被称为“迁移”。 在web2py迁移是自动的,但可以为每个表通过被禁用 迁移= False 作为最后一个参数 define_table 。
第6行定义了一个格式字符串表。 它决定了如何记录应表示为一个字符串。 请注意, 格式 参数也可以是一个函数,它接受一个记录,并返回一个字符串。 例如:
format=lambda row: row.title
8 - 12行定义另一个表称为“评论”。 评论“作者”,“电子邮件”(我们打算存储评论作者的电子邮件地址),一个“文本”类型的“身体”(我们打算用它来存储实际的作者评论),和一个“image_id”字段类型的引用指向 db.image 通过“id”字段。
在第14行, db.image.title 代表该领域的“标题”表“形象”。 属性 需要 允许你设置需求/约束,将执行web2py形式。 在这里我们要求“标题”是独一无二的:
db.image.title IS_NOT_IN_DB(db)
请注意这是可选的,因为它考虑到自动设置 字段(“标题”,独特的= True) 。
代表这些约束的对象被称为验证器。 多个验证器可以分组列表中。 验证器执行的顺序出现。 IS_NOT_IN_DB(a,b) 是一种特殊的验证器,检查一个字段的值 b 不是已经在新记录 一个 。
第15行要求字段“image_id”表“评论” db.image.id 。 作为数据库而言,我们已经宣布这个当我们定义表“评论”。 现在我们明确告诉模型,这种情况应该由web2py强制执行,也在表单处理级别在发布新的评论,所以无效值从输入表单不传播到数据库。 我们也要求“image_id”所代表的“标题”, “%(标题)” ,相应的记录。
第20行表明,表的字段“image_id”“评论”不应该显示在形式, 可写= False 甚至不是以只读的形式, 可读= False 。
验证器的意义在15 - 17行应该是显而易见的。
注意,验证器
db.comment.image_id.requires = IS_IN_DB(db, db.image.id, '%(title)s')
可以省略(自动)如果我们指定为引用表的格式:
db.define_table('image', ..., format='%(title)s')
的格式可以是一个字符串或一个函数,它接受一个记录,并返回一个字符串。
一旦定义了一个模型,如果没有错误,web2py创建一个应用程序管理界面来管理数据库。 你访问它通过“数据库管理”链接 编辑 页面或直接:
http://127.0.0.1:8000/images/appadmin
这是一个截图 appadmin 接口:
这个接口是控制器称为“appadmin编码。 py appadmin.html“和相应的视图。 从现在开始,我们将参考这个接口简单 appadmin 。 它允许管理员插入新的数据库记录,编辑和删除现有记录,浏览表和执行数据库连接。
第一次 appadmin 执行访问,模型和创建的表。 web2py木豆将Python代码转换为SQL语句特定于所选数据库后端(在这个例子中SQLite)。 你可以看到的生成的SQL 编辑 页面点击“sql。 日志”链接在“模型”。 注意,链接不存在,直到创建了表。
如果你要编辑模型和访问 appadmin 再次,web2py改变现有表生成SQL。 生成的SQL登录“sql.log”。
现在回到 appadmin 并试图插入一个新的图像记录:
web2py翻译了 db.image.file “上传”字段为一个文件上传表单。 当提交表单和一个图像文件上传,文件重命名以安全的方式保存扩展,它与应用程序下的新名称保存“上传”文件夹,并存储在新的名称 db.image.file 字段。 这个过程的目的是防止目录遍历的攻击。
请注意,每个字段类型的呈现 小部件 。 默认widget可以覆盖。
当你点击一个表名 appadmin ,web2py执行选择当前表的所有记录,发现的木豆查询
db.image.id > 0
并呈现结果。
你可以选择一组不同的记录通过编辑SQL查询和按[提交]。
编辑或删除单个记录,点击记录id号码。
因为 IS_IN_DB 验证器,参考字段“image_id”呈现一个下拉菜单。 下拉的物品存储为键( db.image.id ),但由他们 db.image.title 指定的验证器。
验证器是强大的对象知道如何表示字段,字段值进行过滤,生成错误,格式从字段中提取的值。
下图显示了当你提交一个表单,没有通过验证:
相同的形式自动生成的 appadmin 也可以以编程方式生成通过吗 SQLFORM 助手在用户应用程序和嵌入式。 这些形式是CSS-friendly,可以定制。
每个应用程序都有自己的 appadmin ,因此, appadmin 本身可以被修改而不影响其他应用程序。
到目前为止,应用程序知道如何存储数据,我们看到了如何通过访问数据库 appadmin 。 访问 appadmin 仅限于管理员,它并不打算作为一个生产应用程序的web接口;因此这个演练的下一部分。 特别是我们想创建:
• 一个“索引”页面,这个页面列出所有可用的图像按标题和链接页面的图像细节。
• “显示/(id)”页面显示访问者请求的形象和允许访问者浏览和发表评论。
• “下载/[名字]”动作下载上传图像。
这是代表示意图:
回到 编辑 页面和编辑“默认。 py”控制器,取代其内容如下:
def index():
images = db().select(db.image.ALL, orderby=db.image.title)
return dict(images=images)
该操作返回一个字典。 项的键在字典里解释为变量传递给视图相关的行动。 如果没有看来,当开发动作呈现“通用。 html”视图,提供每个web2py应用程序。
所有字段的索引操作执行选择( db.image.ALL )从表形象,下令 db.image.title 。 选择的结果是a 行 包含记录的对象。 将它分配给一个局部变量 图片 返回的行动到视图。 图片 iterable,其元素被选中的行。 为每一行的列可以访问字典: 图像0 或相当于 [0].title图像 。
如果你不写一个视图,通过“视图/通用呈现字典。 html”和调用索引行动看起来像这样:
你还没有为这个操作创建一个视图,因此web2py呈现在普通的表格形式的记录。
继续创建一个视图索引行动。 返回管理,编辑“默认/索引。 html”和它的内容替换为以下几点:
{{extend 'layout.html'}}
Current Images
{{for image in images:}}
{{=LI(A(image.title, _href=URL("show", args=image.id)))}}
{{pass}}
首先要注意的是,视图是纯HTML有特殊{ {… } }标记。 代码嵌入在{ {… } }是纯Python代码有一个前提:缩进是无关紧要的。 代码块开始行结束在冒号(:)和结束行关键字开始 通过 。 在某些情况下阻止显而易见的上下文和使用 通过 不是必需的。
行5 - 7遍历图像行和为每一行图像显示:
LI(A(image.title, _href=URL('show', args=image.id))
这是一个 …< /李> 标记包含一个 < a href = "…" >…< / > 标签包含了 image.title 。 超文本的价值参考(href属性):
URL('show', args=image.id)
即。 URL在相同的应用程序和控制器的当前请求调用函数称为“秀”,一个参数传递给函数, args = image.id 。 李 , 一个 等web2py帮手,映射到相应的HTML标记。 他们未具名参数解释为对象进行序列化和插入标记的innerHTML。 命名参数从一个下划线(例如开始 _href )解释为标记属性但没有下划线。 例如 _href 是 href 属性, _class 是 类 属性,等等。
例如,以下语句:
{{=LI(A('something', _href=URL('show', args=123))}}
呈现为:
something
少量的助手( 输入 , 文本区域 , 选项 和 选择 )也支持一些特殊的命名属性不是从下划线( 价值 , 需要 )。 他们是重要的构建定制的形式和将在稍后讨论。
回到 编辑 页面。 现在表明“默认。 py暴露指数”。 通过点击“索引”,你可以访问新创建的页面:
http://127.0.0.1:8000/images/default/index
这看起来像:
如果你点击图像名称链接,你直接:
http://127.0.0.1:8000/images/default/show/1
这导致一个错误,因为你还没有创建一个动作被称为“控制器”default.py“秀”。
我们编辑”违约。 py”控制器和其内容替换为:
def index():
images = db().select(db.image.ALL, orderby=db.image.title)
return dict(images=images)
def show():
image = db(db.image.id==request.args(0)).select().first()
db.comment.image_id.default = image.id
form = SQLFORM(db.comment)
if form.process().accepted:
response.flash = 'your comment is posted'
comments = db(db.comment.image_id==image.id).select()
return dict(image=image, comments=comments, form=form)
def download():
return response.download(request, db)
控制器包含两个动作:“秀”和“下载”。 “秀”行动选择的图像 id 解析从请求参数和所有评论相关的图片。 “显示”,然后将一切传递给视图“违约/ show.html”。
映像id引用:
URL('show', args=image.id)
在“默认/索引。 html”,可以访问:
request.args(0)
从“秀”行动。
“下载”行动预计一个文件名 request.args(0) ,建立一个路径,文件的位置应该是,并将其发送回客户机。 如果文件太大,它流文件,而没有引起任何内存开销。
请注意以下语句:
• 第7行创建一个插入SQLFORM的形式 db.comment 只使用指定的表字段。
• 第8行集引用字段的值,而不是输入表单的一部分,因为它不是在列表中指定的字段。
• 第9行流程提交的表单(提交的表单变量 request.vars )在当前会话(会话用于防止双提交,执行导航)。 如果提交的表单变量进行验证,新插入的评论 db.comment 表,否则修改表单包含错误消息(例如,如果作者的电子邮件地址是无效的)。 这都是在第9行!
• 10号线只是执行如果表单被接受,记录后插入到数据库表中。 response.flash 是一个web2py变量显示在视图和用于通知游客,发生了一件事。
• 第11行选择引用当前图像的所有评论。
“下载”行动已经定义在“默认。 py”脚手架应用程序的控制器。
“下载”行动不返回一个字典,所以它不需要一个视图。 “秀”行动,应该有一个视图,所以返回 管理 并创建一个名为“违约/ show.html”的新观点。
编辑这个新文件和替换其内容如下:
{{extend 'layout.html'}}
Image: {{=image.title}}
{{if len(comments):}}
Comments
{{for comment in comments:}}
{{=comment.author}} says {{=comment.body}}
{{pass}}
{{else:}}
No comments posted yet
{{pass}}
Post a comment
{{=form}}
这个视图显示了 image.file 通过调用一个内部的“下载”行动 < img… / > 标签。 如果有注释,它循环遍历并显示每一个。
这是一切都会出现游客。
当访问者通过此页面提交评论,评论存储在数据库和附加到页面的底部。
添加CRUD
web2py还提供了一个CRUD(创建/读取/更新/删除)API简化形式。 使用CRUD需要定义的地方,比如在文件“db.py”:
from gluon.tools import Crud
crud = Crud(db)
这两条线已经在脚手架应用程序。
的 crud 对象提供了高级的方法,例如:
form = crud.create(table)
可以用来取代编程模式:
form = SQLFORM(table)
if form.process().accepted:
session.flash = '...'
redirect('...')
在这里,我们使用crud重写前面的“秀”行动,使更多的改进:
def show():
image = db.image(request.args(0)) or redirect(URL('index'))
db.comment.image_id.default = image.id
form = crud.create(db.comment,
message='your comment is posted',
next=URL(args=image.id))
comments = db(db.comment.image_id==image.id).select()
return dict(image=image, comments=comments, form=form)
首先注意我们使用语法
db.image(request.args(0)) or redirect(...)
获取所需的记录。 自 “表(id) 没有找到返回,如果没有一个记录,我们可以使用 或重定向(…) 在这种情况下在一行。
的 下一个 的观点 crud.create 是URL重定向到接受表单之后。 的 消息 参数是要显示一个验收。 你可以阅读更多关于CRUD在第7章。
添加身份验证
web2py API基于角色的访问控制是相当复杂的,但现在我们将限制限制访问显示行动经过身份验证的用户,推迟第9章更详细的讨论。
限制对经过身份验证的用户访问,我们需要完成三个步骤。 在一个模型中,例如“db。 py”,我们需要添加:
from gluon.tools import Auth
auth = Auth(db)
auth.define_tables()
在我们的控制器,我们需要添加一个动作:
def user():
return dict(form=auth())
这足以使登录、注册、注销等页面。 默认的布局也会显示选项对应的页的右上角。
我们现在可以装饰我们想限制的功能,例如:
@auth.requires_login()
def show():
image = db.image(request.args(0)) or redirect(URL('index'))
db.comment.image_id.default = image.id
form = crud.create(db.comment, next=URL(args=image.id),
message='your comment is posted')
comments = db(db.comment.image_id==image.id).select()
return dict(image=image, comments=comments, form=form)
任何试图访问
http://127.0.0.1:8000/images/default/show/[image_id]
需要登录。 如果用户没有登录,用户将被重定向到
http://127.0.0.1:8000/images/default/user/login
的 用户 函数也暴露等,以下行为:
http://127.0.0.1:8000/images/default/user/logout
http://127.0.0.1:8000/images/default/user/register
http://127.0.0.1:8000/images/default/user/profile
http://127.0.0.1:8000/images/default/user/change_password
http://127.0.0.1:8000/images/default/user/request_reset_password
http://127.0.0.1:8000/images/default/user/retrieve_username
http://127.0.0.1:8000/images/default/user/retrieve_password
http://127.0.0.1:8000/images/default/user/verify_email
http://127.0.0.1:8000/images/default/user/impersonate
http://127.0.0.1:8000/images/default/user/not_authorized
现在,第一次用户需要注册才能登录并读或发表评论。
这两个 身份验证 对象和 用户 已经搭建应用程序中定义的函数。 的 身份验证 对象是高度可定制的,并且可以处理电子邮件验证,注册批准,验证码,通过插件和备用登录方法。
添加网格
我们可以进一步改善这种使用 SQLFORM.grid 和 SQLFORM.smartgrid 产品为我们的应用程序创建一个管理界面:
@auth.requires_membership('manager')
def manage():
grid = SQLFORM.smartgrid(db.image)
return dict(grid=grid)
“视图/违约/ manage.html”相关
{{extend 'layout.html'}}
Management Interface
{{=grid}}
使用appadmin创建一组“经理”,使一些用户组的成员。 他们将不能访问
http://127.0.0.1:8000/images/default/manage
和浏览、搜索:
创建、更新和删除照片和评论:
配置布局
您可以配置默认布局通过编辑“视图/布局。 html”,但您还可以配置它没有编辑的html。 事实上,“静态/基地。 css样式表是记录和第五章中描述。 你可以改变颜色,列,大小、边框和背景没有编辑的HTML。 如果你想编辑菜单,标题或副标题,可以在任何模型文件。 脚手架应用,设置默认值的参数文件中的“模型/ menu.py”:
response.title = request.application
response.subtitle = T('customize me!')
response.meta.author = 'you'
response.meta.description = 'describe your app'
response.meta.keywords = 'bla bla bla'
response.menu = [ [ 'Index', False, URL('index') ] ]
一个维基
在本节中,我们建立一个wiki,从头开始,没有使用提供的扩展功能plugin_wiki第12章中描述。 参观者将能够创建页面、搜索(标题),和编辑它们。 游客还可以发表评论(正如在前面的应用程序),并发布文档(作为附件页)和链接页面。 作为一个惯例,我们采用Markmin语法维基语法。 我们还将使用Ajax实现一个搜索页面,页面的RSS提要,并通过xml - rpc处理程序来搜索页面 ( xmlrpc ] 。
下图列出了行动,我们需要实现,我们打算建立它们之间的联系。
首先创建一个新的脚手架应用,给它命名“mywiki”。
该模型必须包含三个表:页面,评论,和文档。 注释和文档引用页面,因为他们属于页面。 一个文档包含一个文件字段类型的上传与前面的图片应用程序。
这是完整的模型:
db = DAL('sqlite://storage.sqlite')
from gluon.tools import *
auth = Auth(db)
auth.define_tables()
crud = Crud(db)
db.define_table('page',
Field('title'),
Field('body', 'text'),
Field('created_on', 'datetime', default=request.now),
Field('created_by', db.auth_user, default=auth.user_id),
format='%(title)s')
db.define_table('comment',
Field('page_id', db.page),
Field('body', 'text'),
Field('created_on', 'datetime', default=request.now),
Field('created_by', db.auth_user, default=auth.user_id))
db.define_table('document',
Field('page_id', db.page),
Field('name'),
Field('file', 'upload'),
Field('created_on', 'datetime', default=request.now),
Field('created_by', db.auth_user, default=auth.user_id),
format='%(name)s')
db.page.title.requires = IS_NOT_IN_DB(db, 'page.title')
db.page.body.requires = IS_NOT_EMPTY()
db.page.created_by.readable = db.page.created_by.writable = False
db.page.created_on.readable = db.page.created_on.writable = False
db.comment.body.requires = IS_NOT_EMPTY()
db.comment.page_id.readable = db.comment.page_id.writable = False
db.comment.created_by.readable = db.comment.created_by.writable = False
db.comment.created_on.readable = db.comment.created_on.writable = False
db.document.name.requires = IS_NOT_IN_DB(db, 'document.name')
db.document.page_id.readable = db.document.page_id.writable = False
db.document.created_by.readable = db.document.created_by.writable = False
db.document.created_on.readable = db.document.created_on.writable = False
“默认编辑控制器。 py”和创建以下行动:
• 指数:列出所有维基页面
• 创建:另一个wiki页面
• 显示:显示一个wiki页面及其评论,并追加评论
• 编辑:编辑现有页面
• 文档:管理文件附加到页面
• 下载:下载文档(如图片)
• 搜索:显示一个搜索框,通过一个Ajax回调,返回所有匹配的标题作为访问者类型
• 回调:Ajax回调函数。 它返回的HTML嵌入在搜索页面,而访问者类型。
这是“默认。 py”控制器:
def index():
""" this controller returns a dictionary rendered by the view
it lists all wiki pages
>>> index().has_key('pages')
True
"""
pages = db().select(db.page.id,db.page.title,orderby=db.page.title)
return dict(pages=pages)
@auth.requires_login()
def create():
"creates a new empty wiki page"
form = crud.create(db.page, next=URL('index'))
return dict(form=form)
def show():
"shows a wiki page"
this_page = db.page(request.args(0)) or redirect(URL('index'))
db.comment.page_id.default = this_page.id
form = crud.create(db.comment) if auth.user else None
pagecomments = db(db.comment.page_id==this_page.id).select()
return dict(page=this_page, comments=pagecomments, form=form)
@auth.requires_login()
def edit():
"edit an existing wiki page"
this_page = db.page(request.args(0)) or redirect(URL('index'))
form = crud.update(db.page, this_page,
next=URL('show',args=request.args))
return dict(form=form)
@auth.requires_login()
def documents():
"browser, edit all documents attached to a certain page"
page = db.page(request.args(0)) or redirect(URL('index'))
db.document.page_id.default = page.id
db.document.page_id.writable = False
grid = SQLFORM.grid(db.document.page_id==page.id,args=[page.id])
return dict(page=page, grid=grid)
def user():
return dict(form=auth())
def download():
"allows downloading of documents"
return response.download(request, db)
def search():
"an ajax wiki search page"
return dict(form=FORM(INPUT(_id='keyword',_name='keyword',
_οnkeyup="ajax('callback', ['keyword'], 'target');")),
target_div=DIV(_id='target'))
def callback():
"an ajax callback that returns a
- of links to wiki pages"
query = db.page.title.contains(request.vars.keyword)
pages = db(query).select(orderby=db.page.title)
links = [A(p.title, _href=URL('show',args=p.id)) for p in pages]
return UL(*links)
行2 - 6提供了一个索引行动发表评论。 行4 - 5在评论解读为python测试代码(doctest)。 测试可以运行通过管理界面。 在这种情况下,测试验证索引操作运行没有错误。
行18日,27日,35试图取回 页面 记录的id request.args(0) 。
13、20行定义和流程创建表单新页面和一个新的评论。
28行定义和流程更新wiki页面的形式。
38行创建一个 网格 对象,该对象允许浏览器,添加和更新的评论链接到页面。
会发生一些神奇的51。 的 onkeyup 属性输入标记的“关键字”是集。每次客人释放的关键,内部的JavaScript代码 onkeyup 执行属性,客户端。 这是JavaScript代码:
ajax('callback', ['keyword'], 'target');
ajax 是一个JavaScript函数中定义文件”web2py。 js layout.html“默认包含的。 需要三个参数:行动的URL执行同步回调,变量的ID的列表发送给回调(["关键字"])和反应要插入的ID(“目标”)。
一旦你输入在搜索框并释放一个关键的东西,客户端调用服务器和发送的内容“关键字”字段,当服务器响应,响应是嵌入在页面本身的“目标”标记的innerHTML。
“目标”中定义的标签是一个DIV 52。 它可以被定义在视图中。
这是“默认/ create.html”视图的代码:
{{extend 'layout.html'}}
Create new wiki page
{{=form}}
如果你访问 创建 页面,您将看到以下:
这是“默认/ index . html”视图的代码:
{{extend 'layout.html'}}
Available wiki pages
[ {{=A('search', _href=URL('search'))}} ]
- {{for page in pages:}}
{{=LI(A(page.title, _href=URL('show', args=page.id)))}}
{{pass}}
[ {{=A('create page', _href=URL('create'))}} ]
它生成以下页面:
这是“默认/ show.html”视图的代码:
{{extend 'layout.html'}}
{{=page.title}}
[ {{=A('edit', _href=URL('edit', args=request.args))}}
| {{=A('documents', _href=URL('documents', args=request.args))}} ]
{{=MARKMIN(page.body)}}
Comments
{{for comment in comments:}}
{{=db.auth_user[comment.created_by].first_name}} on {{=comment.created_on}}
says {{=comment.body}}
{{pass}}
Post a comment
{{=form}}
如果你想使用减记语法而不是markmin语法:
from gluon.contrib.markdown import WIKI
和使用 维基 而不是 MARKMIN 帮手。 或者,您可以选择接受原始HTML而不是markmin语法。 在这种情况下,你将取代:
{{=MARKMIN(page.body)}}
:
{{=XML(page.body)}}
(这样的XML不逃,因为默认情况下web2py行为)。
这可以做的更好:
{{=XML(page.body, sanitize=True)}}
通过设置 sanitize = True ,你告诉web2py逃避不安全的XML标记,如“> <脚本”,从而防止XSS漏洞。
如果,从索引页面,点击一个页面标题,您可以看到您创建的页面:
这是“默认/ edit.html”视图的代码:
{{extend 'layout.html'}}
Edit wiki page
[ {{=A('show', _href=URL('show', args=request.args))}} ]
{{=form}}
它生成一个页面创建页面看起来几乎相同。
这是“默认/ documents.html”视图的代码:
{{extend 'layout.html'}}
Documents for page: {{=page.title}}
[ {{=A('show', _href=URL('show', args=request.args))}} ]
Documents
{{=grid}}
从“秀”页面,如果你点击文件,您现在可以管理文件附加到页面。
最后这里的代码视图“默认/ search.html”:
{{extend 'layout.html'}}
Search wiki pages
[ {{=A('listall', _href=URL('index'))}}]
{{=form}}
{{=target_div}}
下列哪生成Ajax搜索表单:
你也可以尝试通过访问直接调用回调的动作,例如,以下网址:
http://127.0.0.1:8000/mywiki/default/callback?keyword=wiki
如果你看你看到返回的HTML页面来源回调:
- I made a Wiki
从存储页面生成RSS提要使用web2py很容易因为web2py包括 gluon.contrib.rss2 。 只是附加以下行动默认控制器:
def news():
"generates rss feed form the wiki pages"
reponse.generic_patterns = ['.rss']
pages = db().select(db.page.ALL, orderby=db.page.title)
return dict(
title = 'mywiki rss feed',
link = 'http://127.0.0.1:8000/mywiki/default/index',
description = 'mywiki news',
created_on = request.now,
items = [
dict(title = row.title,
link = URL('show', args=row.id),
description = MARKMIN(row.body).xml(),
created_on = row.created_on
) for row in pages])
当你访问的页面
http://127.0.0.1:8000/mywiki/default/news.rss
你看到提要(具体的输出取决于提要阅读器)。 注意关键字自动转换为RSS,多亏了。 rss URL中的扩展。
web2py实现feedparser阅读还包括第三方提要。
最后,让我们添加一个xml - rpc处理程序,允许搜索维基编程:
service = Service()
@service.xmlrpc
def find_by(keyword):
"finds pages that contain keyword for XML-RPC"
return db(db.page.title.contains(keyword).select().as_list()
def call():
"exposes all registered services, including XML-RPC"
return service()
在这里,处理程序操作简单发布(通过xml - rpc),列表中指定的功能。 在这种情况下, find_by 。 find_by 不是一个行动(因为它接受一个参数)。 它将查询数据库 .select() 然后提取记录的列表 .response 并返回列表。
这里是一个例子如何访问xml - rpc处理程序从外部Python程序。
import xmlrpclib
server = xmlrpclib.ServerProxy(
'http://127.0.0.1:8000/mywiki/default/call/xmlrpc')
for item in server.find_by('wiki'):
print item['created_on'], item['title']
处理程序可以访问许多其他编程语言,理解xml - rpc,包括C,c++,c#和Java。
在 日期 , datetime 和 时间 格式
有三种不同的表示为每个字段类型 日期 , datetime 和 时间 :
• 数据库的表示
• 内部web2py prepresentation
• 的字符串表示形式和表
数据库的表示是一个内部问题,不影响代码。 在内部,在web2py层面,它们被存储为 datetime.date , datetime.datetime 和 datetime.time 对象分别和他们可以这样操作:
for page in db(db.page).select():
print page.title, page.day, page.month, page.year
当日期转换为字符串形式转换使用ISO表示
%Y-%m-%d %H:%M:%S
然而,这表示在国际化和您可以使用admin stranslation页面格式更改为另一种。 例如:
%m/%b/%Y %H:%M:%S
注意,默认情况下英语不是翻译因为web2py假设应用程序已经用英语写的。 如果你想英语国际化工作你需要创建所需要的翻译文件(使用admin)和声明应用程序当前的语言不是英语,例如:
T.current_languages = ['null']
更多关于 管理
管理界面提供了额外的功能,这里我们简要回顾。
网站
这个页面列出了所有已安装的应用程序。 底部有两种形式。
其中第一个允许通过指定其名称创建一个新的应用程序。
第二种形式允许上传一个现有的应用程序从本地文件或远程URL。 当你上传一个应用程序中,您需要指定一个名称。 这可能是原来的名字,但不需要。 这允许安装同一应用程序的多个副本。 例如,你可以试着上传的CMS的即时新闻由马丁Mulone:
http://code.google.com/p/instant-press/
Web2py文件包 .w2p 文件。 这些的是焦油gzip文件。 Web2py使用 .w2p 扩展而不是 . tgz 扩展在防止浏览器解压缩下载。 他们可以手动压缩 焦油zxvf(文件名) 虽然这是没有必要的。
成功上传,web2py显示上传文件的MD5校验和。 您可以使用它来验证在上传文件没有损坏。 InstantPress名称将出现在已安装的应用程序的列表。
单击InstantPress名字管理运行起来。
你可以阅读更多关于即时新闻在以下网址:
http://code.google.com/p/instant-press/
为每个应用程序的 网站 页面允许您:
• 卸载应用程序。
• 跳转到 关于 下面的页面(读)。
• 跳转到 编辑 下面的页面(读)。
• 跳转到 错误 下面的页面(读)。
• 清理临时文件(会议、错误和缓存。 磁盘文件)。
• 包。 这返回一个tar文件,其中包含应用程序的完整副本。 我们建议您清理临时文件之前包装应用程序。
• 编译应用程序。 如果没有错误,这个选项将bytecode-compile所有模型、控制器和视图。 因为视图可以扩展和包括其他视图树,字节码编译之前,每个控制器的视图树倒塌成一个单一的文件中。 净效应是bytecode-compiled应用程序更快,因为没有更多的解析模板或字符串替换在运行时发生。
• 包编译。 这个选项只有bytecode-compiled应用程序。 它允许包装应用程序没有源代码和闭源分布。 注意Python(和其他编程语言)技术可以反编译,因此编译不提供完整的源代码的保护。 然而,反编译是很困难的,可以是非法的。
• 删除编译。 它只是消除了字节码编译模型、视图和控制器的应用程序。 如果应用程序在本地与源代码打包或编辑,是没有害处的移除bytecode-compiled文件,和应用程序将继续工作。 如果应用程序被安装的形式打包编译文件,那么这是不安全的,因为没有源代码回到,和应用程序将不再工作。
从web2py管理网站页面所有可用的功能也可以通过模块中定义的API以编程方式 胶子/ admin.py 。 只是打开一个python shell和导入这个模块。
关于
的 关于 选项卡允许编辑的描述应用程序及其许可。 这些分别写的关于和许可证文件在应用程序文件夹中。
您可以使用 MARKMIN ,或 gluon.contrib.markdown.WIKI 这些文件中描述ref的语法。 ( markdown2 ] 。
编辑
你有使用 编辑 页面已经在这一章。 这里我们想指出的几个功能 编辑 页面。
• 如果你点击任何文件的名字,您可以看到文件的内容和语法高亮显示。
• 如果你点击编辑,您可以编辑该文件通过一个web界面。
• 如果你点击删除,可以删除文件(永久)。
• 如果你点击测试,web2py将运行测试。 测试是开发人员使用Python文档写的,和每个函数都应该有自己的测试。
• 您可以添加语言文件,扫描应用程序发现所有字符串,通过web界面翻译和编辑字符串。
• 如果静态文件被组织在文件夹和子文件夹,文件夹层次结构可以连接通过点击一个文件夹的名字。
下图显示了欢迎的输出测试页面的应用程序。
下图显示了语言欢迎应用程序选项卡。
下图显示了如何编辑语言文件,在这种情况下,“它”(意大利语)欢迎应用程序的语言。
壳牌
如果你点击控制器选项卡下的“壳”链接 编辑 ,web2py将打开一个基于web的Python shell,并将为当前应用程序执行模型。 这允许您交互式地跟您的应用程序。
定时任务
还在控制器选项卡下 编辑 有一个“crontab”链接。 通过点击这个链接您可以编辑web2py crontab文件。 在此之前相同的语法unix crontab但不依赖于unix。 事实上,它只需要web2py,它在Windows中工作。 它允许您注册操作,在预定的时间需要在后台执行。 关于此的更多信息,见下一章。
错误
web2py编程时,你将不可避免地犯错误和引入bug。 web2py有助于在两个方面:1)它允许您创建测试每一个函数,可以在浏览器中运行的 编辑 页面;2)当一个错误表现,一张票发行访客和错误记录。
有意引入一个错误在图像应用程序如下所示:
def index():
images = db().select(db.image.ALL,orderby=db.image.title)
1/0
return dict(images=images)
当你访问的索引操作,得到以下的机票:
只有管理员可以访问的机票:
票显示了回溯,导致问题,文件的内容和完整的系统(变量、请求、会话等等)。 如果错误发生在一个视图,web2py显示了视图从HTML转换为Python代码。 这允许轻松地识别文件的逻辑结构。
默认情况下门票由回溯存储在文件系统和组。 管理界面提供了一种聚合视图(类型的回溯和发生的数量)和一个详细视图id)(列出所有门票票。 管理员可以在两个视图之间进行切换。
请注意,无处不在 管理 显示了syntax-highlighted代码(例如,错误报告,web2py关键词橙色)所示。 如果你点击一个web2py关键字,重定向到一个文档页面的关键字。
如果你固定的除虫指数行动并介绍一个在index视图:
{{extend 'layout.html'}}
Current Images
- {{for image in images:}} {{1/0}} {{=LI(A(image.title, _href=URL("show", args=image.id)))}} {{pass}}
你得到以下机票:
注意web2py已经从HTML视图转换为Python文件,和机票是指描述的错误生成的Python代码,而不是到原始视图文件:
这似乎令人困惑,但实际上它更容易调试,因为Python缩进了代码的逻辑结构中嵌入视图。
代码显示在同一页面的底部。
列出所有门票在管理的 错误 为每个应用程序页:
水银
如果您正在运行从源代码,你安装的版本控制库:
easy_install mercurial
然后管理界面显示一个菜单项被称为“善变”。 它会自动为应用程序创建一个本地Mercurial存储库。 按下“提交”按钮在页面将提交当前应用程序。 Mercurial创建和存储的信息在代码中您所作的改变成一个隐藏文件夹”。 hg”在应用程序文件夹中。 每个应用程序都有自己的”。 hg”文件夹和自己的”。 hgignore”文件(告诉Mercurial忽略哪些文件)。
Mercurial web接口允许您浏览以前的承诺和diff文件,但是我们建议你直接使用Mercurial的外壳或可能基于gui的善变的客户因为他们更强大。 例如他们会允许你用远程数据源同步应用程序存储库:
你可以在这里阅读更多关于水银:
http://mercurial.selenic.com/
管理向导(实验)
的 管理 接口包括一个向导可以帮助您创建一个新的应用程序。 您可以访问向导的“网站”页面,下图所示。
向导将指导您完成创建一个新的应用程序所涉及的一系列步骤:
• 为应用程序选择一个名称
• 配置应用程序并选择所需的插件
• 建立所需的模型(它将为每个模型创建的CRUD页面)
• 允许您编辑这些页面使用MARKMIN语法的观点
下图显示了这个过程的第二步。
你可以看到一个插件(从下拉框中选择一个布局 web2py.com/layouts ),检查其他插件(多项选择下拉 web2py.com/plugins )和一个“登录配置”字段,把名为Janrain“域:关键”。
其他步骤都是不言而喻的。
向导适用于它,但它被认为是一个 实验功能 有两个原因:
• 应用程序手动创建向导和编辑,由向导之后不能修改。
• 向导的界面会随着时间改变,包括支持更多的功能和更容易视觉发展。
在任何情况下,向导是一个方便的工具,用于快速原型和它可以用来引导一个新的应用程序与另一个布局和可选插件。
配置 管理
通常不需要进行任何配置的管理,但一些定制成为可能。 在您登录到管理员可以编辑管理通过URL配置文件:
http://127.0.0.1:8000/admin/default/edit/admin/models/0.py
请注意, 管理 可用于编辑本身。 事实上 管理 和其他任何一个应用程序。
文件“0。 py”是非常自我记录,如果你打开你可能已经知道你在寻找什么。 反正有一些定制比其他人更重要:
GAE_APPCFG = os.path.abspath(os.path.join('/usr/local/bin/appcfg.py'))
这应该指向“appcfg的位置。 py”文件,Google App Engine SDK。 如果你有SDK您可能想要将这个配置参数更改为正确的值。 它将允许您将部署到GAE从管理界面。
你也可以设置web2py管理在演示模式下:
DEMO_MODE = True
FILTER_APPS = ['welcome']
只有过滤应用程序中列出的应用程序访问,他们将只能以只读模式。
如果你是一个老师,要公开管理界面,这样学生可以共享一个管理界面的项目(一个虚拟实验室)认为,可以通过设置:
MULTI_USER_MODE = True
这样学生将被要求登录,只能够访问通过管理自己的应用程序。 当第一个用户/老师,你将能够访问它们。
注意,这个机制仍然假定所有的用户都是可信的。 创建的所有应用程序在管理下运行相同的凭证在相同的文件系统。 可以为应用程序创建一个学生来访问数据和应用程序由另一个学生的来源。
更多关于 appadmin
appadmin 不打算暴露给公众。 它的目的是帮助你通过提供一个简单的访问数据库。 它只包含两个文件:appadmin控制器”。 py appadmin和一个视图。 html”中所使用的所有操作控制器。
的 appadmin 控制器是相对较小的,可读的,它提供了设计一个数据库接口的一个例子。
appadmin 显示可用的数据库,每个数据库表存在。 你可以单独为每个表插入记录,所有记录列表。 appadmin 分页输出100条记录。
一旦选定一组记录,标题页的变化,允许您更新或删除所选的记录。
更新记录,查询字符串字段中输入SQL任务:
title = 'test'
在必须括在单引号字符串值。 可以将多个字段之间用逗号分隔。
删除一条记录,点击相应的复选框以确认你确定。
appadmin 还可以执行连接如果SQL筛选包含SQL条件涉及到两个或两个以上的表中。 例如,尝试:
db.image.id == db.comment.image_id
web2py经过这沿着木豆,它明白两个表的查询链接,因此,选择两个表内连接。 这是输出:
如果你点击一个id字段的数量,你得到一个编辑页面的记录与相应的id。
如果你点击一个引用字段的数量,一个编辑页面引用的记录。
你不能更新或删除行选择加入,因为他们涉及来自多个表的记录,这将是模棱两可的。
除了它的数据库管理功能, appadmin 还使您能够查看内容的应用程序的详细信息 缓存 (在 / yourapp appadmin / ccache )以及当前的内容 请求 , 响应 , 会话 对象(在 / yourapp / appadmin /状态 )。
appadmin 替换 response.menu 有自己的菜单,它提供了应用程序的链接 编辑 页 管理 , db (数据库管理)页面 状态 页面, 缓存 页面。 如果您的应用程序的布局并不生成菜单使用 response.menu ,那么你将不会看到 appadmin 菜单。 在这种情况下,您可以修改appadmin。 html文件并添加 { { =菜单(response.menu)} } 显示菜单。