Web2py 快速指南



Web2py - 简介

web2py 定义为一个免费的、开源的敏捷开发 Web 框架,涉及数据库驱动的 Web 应用程序;它用 Python 编写,并可以用 Python 编程。它是一个全栈框架;它包含构建一个完全功能的 Web 应用程序所需的所有必要组件。

web2py 框架遵循模型-视图-控制器模式运行 Web 应用程序,这与传统的模式不同。

  • 模型是应用程序的一部分,其中包含数据逻辑。模型中的对象用于从数据库中检索和存储数据。

  • 视图是应用程序的一部分,它有助于将数据显示呈现给最终用户。数据显示是从模型中获取的。

  • 控制器是应用程序的一部分,它处理用户交互。控制器可以读取视图中的数据,控制用户输入,并将输入数据发送到特定的模型。

Web2py Appliance
  • web2py 具有管理 Cookie 和会话的内置功能。在提交事务(以 SQL 术语)后,会话也会同时存储。

  • web2py 能够在完成某些操作后以预定的时间间隔运行任务。这可以通过CRON实现。

web2py – 工作流程

请查看以下工作流程图。

Workflow

工作流程图如下所述。

  • 模型视图控制器组件构成了用户 web2py 应用程序。

  • 可以在 web2py 的同一实例中托管多个应用程序。

  • 浏览器将 HTTP 请求发送到服务器,服务器与模型控制器视图交互以获取必要的输出。

  • 箭头表示与数据库引擎的通信。数据库查询可以用原始 SQL 编写,也可以使用 web2py 数据库抽象层(将在后面的章节中讨论)编写,以便web2py 应用程序代码独立于任何数据库引擎。

  • 模型建立与数据库的数据库连接并与控制器交互。另一方面,控制器视图交互以呈现数据显示。

  • 调度程序将 HTTP 响应中给定的请求 URL 映射到控制器中的函数调用。函数的输出可以是字符串或哈希表。

  • 数据由视图呈现。如果用户请求 HTML 页面(默认值),则数据将呈现为 HTML 页面。如果用户以 XML 格式请求同一页面,web2py 会尝试查找可以以 XML 格式呈现字典的视图。

  • web2py 支持的协议包括 HTML、XML、JSON、RSS、CSV 和 RTF。

模型-视图-控制器

web2py 的模型-视图-控制器表示如下:

模型

"db.py" is the model:
db = DAL('sqlite://storage.sqlite')
db.define_table(employee, Field('name'), Field(‘phone’))

模型包含应用程序数据的逻辑。它连接到如上图所示的数据库。假设正在使用 SQLite 并且存储在storage.sqlite文件中,其中定义了一个名为 employee 的表。如果表不存在,web2py 会通过创建相应的表来提供帮助。

控制器

程序"default.py"控制器

def employees():
   grid = SQLFORM.grid(db.contact, user_signature = False)
   return locals()

web2py中,URL 映射有助于访问函数和模块。对于以上示例,控制器包含一个名为 employees 的单个函数(或“操作”)。

控制器采取的操作返回一个字符串或一个 Python 字典,它是一组键值对,包括一组局部变量。

视图

"default/contacts.html"视图

{{extend 'layout.html'}}
<h1>Manage My Employees</h1>
{{=grid}}

对于给定的示例,视图在关联的控制器函数执行后显示输出。

视图的目的是呈现字典中的变量,这些变量采用 HTML 格式。视图文件是用 HTML 编写的,但它使用{{ 和 }}分隔符嵌入 Python 代码。

嵌入到 HTML 中的代码包含字典中的 Python 代码。

开始使用 web2py

web2py 以二进制包的形式提供,适用于所有主要的操作系统,如 Windows、UNIX 和 Mac OS X。

安装 web2py 很容易,因为:

  • 它包含 Python 解释器,因此您无需预先安装它。还有一个在所有操作系统上运行的源代码版本。

  • 以下链接包含web2py的二进制包,供用户根据需要下载:www.web2py.com

  • 与其他框架不同,web2py框架无需预先安装。用户需要下载 zip 文件并根据操作系统要求解压缩。

  • web2py框架是用 Python 编写的,Python 是一种完整的动态语言,无需任何编译或复杂的安装即可运行。

  • 它使用虚拟机,就像其他编程语言(如 Java 或 .net)一样,它可以透明地字节编译开发人员编写的源代码。

操作系统 命令
Unix 和 Linux(源代码分发版) python web2py.py
OS X(二进制分发版) open web2py.app
Windows(二进制 web2py 分发版) web2py.exe
Windows(源代码 web2py 分发版) c:/Python27/python.exe web2py.py

Web2py - Python 语言

Python 可以定义为面向对象和交互式语言的组合。它是一个开源软件。Guido van Rossum 在 20 世纪 80 年代后期构思了 Python。

Python 是一种类似于 PERL(实用提取和报告语言)的语言,由于其清晰的语法和可读性而广受欢迎。

Python 的主要显著特点如下:

  • 据说 Python 相对容易学习且可移植。它的语句可以很容易地在许多操作系统中解释,包括基于 UNIX 的系统、Mac OSMS-DOSOS/2和各种版本的 Windows。

  • Python 可移植到所有主要操作系统。它使用易于理解的语法,使程序对用户友好。

  • 它附带一个大型标准库,支持许多任务。

Scripting Languages

从上图可以清楚地看出,Python 是脚本语言和编程语言的组合。它们在另一个程序中解释,就像脚本语言一样。

Python 版本

Python 有三个生产质量的实现,称为 CPython、Jython 和 IronPython。这些也被称为 Python 版本。

  • 经典 Python 又名 CPython 是一个编译器、解释器,包含用标准 C 语言实现的内置和可选扩展模块。

  • Jython 是针对 Java 虚拟机 (JVM) 的 Python 实现。

  • IronPython 由微软设计,包含公共语言运行时 (CLR)。它通常被称为 .NET。

启动

任何操作系统中的基本 Python 程序都以标题开头。程序以.py扩展名存储,并使用 Python 命令运行程序。

例如,python_rstprogram.py将为您提供所需的输出。如果存在错误,它也会生成错误。

Python 使用缩进分隔代码块。一个块以以冒号结尾的行开头,并继续以与下一行相同或更高的缩进方式对所有行执行。

# Basic program in Python
print "Welcome to Python!\n"

程序的输出将是:

Welcome to Python!

缩进

程序的缩进在 Python 中非常重要。对于 Python 初学者来说,关于 Python 的缩进规则存在一些偏见和神话。

所有程序员的经验法则:

“在 Python 源代码中,空格很重要。”

前导空格,包括 Python 代码行开头的空格和制表符,计算该行的缩进级别。

注意

  • 缩进级别也决定了语句的分组。

  • 通常使用四个空格,即每个缩进级别使用一个制表符。

  • 最好不要混合使用制表符和空格,这可能会导致混乱,而这种混乱是不可见的。

如果缺少缩进,Python 也会生成编译时错误。

IndentationError: expected an indented block

控制流语句

Python 程序的控制流受条件语句、循环和函数调用的控制。

  • If 语句在指定条件下执行代码块,以及 else 和 elif(else-if 的组合)。

  • For 语句迭代对象,将每个元素捕获到局部变量中,供附加的代码块使用。

  • While 语句在条件为True时执行代码块。

  • With 语句将代码块包含在上下文管理器中。它作为try/finally语句的可读性更高的替代方案被添加。

# If statement in Python
   x = int(raw_input("Please enter an integer: ")) #Taking input from the user
if x<0:
   print "1 - Got a negative expression value"
   print x
else:
   print "1 - Got a positive expression value"
   print x
print "Good bye!"

输出

sh-4.3$ python main.py
Please enter an integer: 4
1 - Got a positive expression value
4
Good bye!

函数

典型 Python 程序中的语句以特定格式组织和分组,称为“函数”。函数是一组语句,根据请求执行操作。Python 提供了许多内置函数,并允许程序员定义自己的函数。

在 Python 中,函数是像编程语言中的其他对象一样处理的值。

def语句是定义函数最常见的方式。def是一个单子句复合语句,具有以下语法:

def function-name (parameters):statement(s)

以下示例演示了一个生成器函数。它可以用作可迭代对象,以类似的方式创建其对象。

def demo ():
   for i in range(5):
      yield (i*i)
	
for j in demo():
   print j

输出

sh-4.3$ python main.py
0
1
4
9
16

特殊属性、方法和运算符

类中以双下划线开头的属性、方法和运算符通常在行为上是私有的。其中一些是保留关键字,具有特殊含义。

其中三个列出如下:

  • __len__

  • __getitem__

  • __setitem__

其他特殊运算符包括 __getattr__ 和 __setattr__,它们定义了类的getset属性。

文件 I/O 函数

Python 包括打开和关闭特定文件的功能。这可以通过open()write()close()函数来实现。

以下是一些用于文件输入输出的命令:

序号 命令及功能
1

open()

用于打开文件或文档

2

write()

用于向文件或文档中写入字符串

3

read()

用于读取现有文件中的内容

4

close()

此方法关闭文件对象。

示例

假设有一个名为“demo.txt”的文件,其中已经存在文本“This is a demo file”。

#!/usr/bin/python
# Open a file
fo = open("demo.txt", "wb")
fo.write( "Insering new line \n");
# Close opend file
fo.close()

打开文件后可用的字符串将为:

This is a demo file
Inserting a new line

Web2py - 框架概述

web2py是一个全栈Web框架,开发人员可以使用它来完整地开发Web应用程序。它包括SQL数据库集成和多线程Web服务器,用于设计程序。

用于设计用户程序的Web界面

根据操作系统执行命令后,web2py会显示一个启动窗口,然后显示一个GUI小部件,提示用户选择:

  • 一次性管理员密码,
  • 要用于Web服务器的网络接口的IP地址,
  • 以及用于提供请求的端口号。

管理员拥有添加和编辑任何新Web应用程序的所有权限。

默认情况下,web2py在其Web服务器上运行127.0.0.1:8000(本地主机上的8000端口),但用户可以根据需要在任何可用的IP地址和端口上运行它。

web2py GUI小部件将显示如下。

GUI Widget

密码用于在管理界面中对新模块进行任何更改。

用户设置管理员密码后,web2py将在以下URL的页面上启动Web浏览器:http://127.0.0.1:8000/

框架的欢迎页面将显示如下。

Framework

在web2py中设计基本程序

启动web2py应用程序后,使用上述URL,我们可以使用管理界面创建新的模块,例如“helloWorld”

管理界面将要求输入密码以进行身份验证,因为管理员拥有添加和编辑任何新Web应用程序的所有权限。

Web2py Applications

上面给出的快照包含页面详细信息,其中列出了所有已安装的web2py应用程序,并允许管理员管理它们。默认情况下,web2py框架带有三个应用程序。它们是:

  • 用户当前正在实现的admin应用程序。

  • 一个examples应用程序,其中包含在线交互式文档和web2py官方网站的实例。

  • 一个welcome应用程序。它包含任何其他web2py应用程序的基本模板。它也被称为脚手架应用程序。该应用程序还在启动时欢迎用户。

假设新应用程序的名称为“helloWorld”

创建新应用程序后,用户将被重定向到一个包含相应应用程序的视图、模型和控制器的页面。

Edit Application

用户可以通过提及以下URL查看新创建的应用程序:http://127.0.0.1:8000/helloWorld

默认情况下,用户在点击上述URL时可以看到以下屏幕。

要打印给定Web应用程序“helloWorld”的消息,需要在default.py控制器中进行更改。

Web Application

名为“index”的函数是用于返回值并显示必要输出的默认函数。如上所述,字符串“Hello World- Welcome to my first web application”用作返回值,它在屏幕上显示输出。

输出显示如下:

Output

回发

验证表单输入的机制非常常见,并且不被认为是一种良好的编程实践。每次都会验证输入,这对验证来说是一种负担。

web2py中更好的模式是将表单提交到生成它们的相同操作。这种机制称为“回发”,它是web2py的主要功能。简而言之,在回发中实现了自我提交。

def first():
   if request.vars.visitor_name: #if visitor name exists
      session.visitor_name = request.vars.visitor_name
      redirect(URL('second'))#postback is implemented
   return dict()

CRUD应用程序

web2py包括执行创建、检索、更新和删除功能的应用程序。CRUD循环描述了持久性数据库的基本功能。

所有应用程序逻辑都写在模型中,这些模型由控制器检索,并借助视图显示给用户。

appadmin

对于PHP,应用程序服务器包括在phpmyadmin下列出所有数据库。类似地,web2py提供了一个用于管理、创建和删除表或数据库的界面,称为“appadmin”

在实现表背后的逻辑之前,有必要创建数据库及其关联的表。

访问appadmin的URL:

http://127.0.0.1:8000/applicationname/appadmin

点击URL后,用户将获得与给定应用程序关联的表的列表。

List Of Tables

此界面并非旨在公开使用。它旨在轻松访问数据库。它包含两个文件,即控制器“appadmin.py”和视图“appadmin.html”

它可以一次最多分页100条记录。“appadmin”的使用将在后续章节中讨论。

Web2py - 核心

命令行选项

在上一章中,我们学习了如何使用GUI小部件启动web2py服务器。

可以通过从命令行提示符启动服务器来跳过此小部件。

python web2py.py -a 'your password' -i 127.0.0.1 -p 8000

每当web2py服务器启动时,它都会创建一个文件“parameters_8000.py”,其中所有密码都以哈希形式存储。

出于额外的安全目的,可以使用以下命令行:

python web2py.py -a '<recycle>' -i 127.0.0.1 -p 8000

对于上述场景,web2py会重用存储在“parameters_8000.py”中的哈希密码。

如果意外删除或由于其他原因删除了文件“parameters_8000.py”,则web2py中的基于Web的管理界面将被禁用。

URL映射/调度

web2py的功能基于模型-视图-控制器,它以特定形式映射URL:http://127.0.0.1:8000/a/d/f.html

它路由到名为“a”的应用程序下控制器d.py中提到的函数“f()”。如果应用程序中不存在控制器,则web2py使用名为“default.py”的默认控制器。

如果URL中给定的函数不存在,则使用名为init()的默认函数。URL的工作原理如下图所示。

Function Init

扩展名.html对于URL是可选的。扩展名确定呈现控制器中定义的函数输出的视图的扩展名。相同的内容以多种格式提供,例如html、xml、json、rss等。

请求基于接受参数并向用户提供适当输出的函数传递。它是控制器,它与应用程序的模型和视图交互,以根据用户的需要提供输出。

web2py – 工作流程

web2py的工作流程如下:

  • Web服务器在其自己的线程中同时管理每个HTTP请求。

  • HTTP请求标头被解析并传递给调度程序。

  • 调度程序管理应用程序请求并将URL中的PATH_INFO映射到函数调用。每个函数调用都表示在URL中。

  • 直接管理静态文件夹中包含的所有文件的请求,并将大型文件流式传输到客户端。

  • 除了静态文件之外的所有请求都映射到一个操作。

  • 如果请求标头包含应用程序的会话cookie,则检索会话对象;否则,将创建会话ID。

  • 如果操作返回字符串值,则将其返回给客户端。

  • 如果操作返回可迭代对象,则将其用于循环并将数据流式传输到客户端。

条件模型

在上一章中,我们看到了控制器的功能。web2py在其每个应用程序中都使用模型、视图和控制器。因此,了解模型的功能也很有必要。

与任何其他MVC应用程序不同,web2py中的模型被视为条件模型。子文件夹中的模型根据其控制器的使用情况执行。这可以通过以下示例演示:

考虑URL:http://127.0.0.1:8000/a/d/f.html

在这种情况下,“a”是应用程序的名称,“d”是控制器的名称,f()是与控制器关联的函数。将执行的模型列表如下:

applications/a/models/*.py
applications/a/models/d/*.py
applications/a/models/d/f/*.py

web2py包括库,这些库作为对象公开给所有应用程序。这些对象在名为“gluon”的目录下的核心文件中定义。

许多模块(如DAL模板)没有依赖项,可以在web2py框架之外实现。它还维护单元测试,这被认为是一种良好的实践。

应用程序

web2py应用程序在下面的图表中显示。

Diagrammatic Form

在web2py中开发的应用程序由以下部分组成:

  • 模型 - 表示数据和数据库表。

  • 控制器 - 描述应用程序逻辑和工作流程。

  • 视图 - 帮助呈现数据的显示。

  • 语言 - 描述如何将应用程序中的字符串翻译成各种支持的语言。

  • 静态文件 - 不需要处理(例如图像、CSS样式表等)。

  • ABOUTREADME - 项目的详细信息。

  • 错误 - 存储应用程序生成的错误报告。

  • 会话 - 存储与每个特定用户相关的信息。

  • 数据库 - 存储SQLite数据库和其他表信息。

  • 缓存 - 存储缓存的应用程序项。

  • 模块 - 模块是其他可选的Python模块。

  • 私有 - 包含的文件可被控制器访问,但开发人员不能直接访问。

  • 上传 - 文件可被模型访问,但开发人员不能直接访问。

API

在web2py中,模型控制器视图在导入某些对象的开发人员环境中执行。

全局对象 - request、response、session、cache。

助手 - web2py包括助手类,可用于以编程方式构建HTML。它对应于HTML标签,称为“HTML助手”

例如,A、B、FIELDSET、FORM等。

会话

会话可以定义为服务器端信息的存储,这些信息在用户与整个Web应用程序交互的过程中持续存在。

web2py中的会话是存储类的实例。

例如,可以在会话中存储变量,如下所示

session.myvariable = "hello"

此值可以检索如下

a = session.myvariable

只要同一用户在同一会话中执行代码,就可以检索变量的值。

web2py中用于会话的重要方法之一是“forget”

session.forget(response);

它指示web2py不要保存会话。

在后台运行任务

HTTP请求到达Web服务器,Web服务器在其自己的线程中并行处理每个请求。正在进行的任务发生在前景中,而其他任务则保留在后台。管理后台任务也是web2py的主要功能之一。

耗时的任务最好放在后台。一些管理后台任务的机制列出如下:

  • CRON

  • 队列

  • 调度程序

CRON

在web2py中,CRON能够在指定的时间间隔内运行任务。每个应用程序都包含一个CRON文件,该文件定义其功能。

调度程序

内置调度程序通过设置优先级帮助在后台运行任务。它提供了一种创建、调度和修改任务的机制。

计划的事件在模型中列出,文件名是“scheduler.py”

构建应用程序

我们概述了在web2py中创建模型和控制器。在这里,我们将重点关注名为“Contacts”的应用程序的创建。该应用程序需要维护公司列表和在这些公司工作的员工列表。

创建模型

此处,数据字典中表的标识是模型。联系人应用程序的模型将在“models”文件夹下创建。该文件存储在models/db_contacts.py中。

# in file: models/db_custom.py
db.define_table('company', Field('name', notnull = True, unique = True), format = '%(name)s')
db.define_table(
   'contact',
   Field('name', notnull = True),
   Field('company', 'reference company'),
   Field('picture', 'upload'),
   Field('email', requires = IS_EMAIL()),
   Field('phone_number', requires = IS_MATCH('[\d\-\(\) ]+')),
   Field('address'),
   format = '%(name)s'
)

db.define_table(
   'log',
   Field('body', 'text', notnull = True),
   Field('posted_on', 'datetime'),
   Field('contact', 'reference contact')
)

创建上述文件后,可以通过URL http://127.0.0.1:8000/contacts/appadmin访问这些表。

控制器创建

控制器将包含一些用于列出、编辑和删除联系人的函数。

# in file: controllers/default.py
def index():return locals()
def companies():companies = db(db.company).select(orderby = db.company.name)
return locals()

def contacts():company = db.company(request.args(0)) or redirect(URL('companies'))
contacts = db(db.contact.company == company.id).select(orderby = db.contact.name)
return locals()

@auth.requires_login()
def company_create():form = crud.create(db.company, next = 'companies')
return locals()

@auth.requires_login()
def company_edit():company = db.company(request.args(0)) or redirect(URL('companies'))
form = crud.update(db.company, company, next='companies')
return locals()

@auth.requires_login()
def contact_create():db.contact.company.default = request.args(0)
form = crud.create(db.contact, next = 'companies')
return locals()

@auth.requires_login()
def contact_edit():contact = db.contact(request.args(0)) or redirect(URL('companies'))
form = crud.update(db.contact, contact, next = 'companies')
return locals()

def user():return dict(form = auth())

视图的创建及其输出将在下一章中讨论。

Web2py - 视图

web2py框架在其应用程序中使用模型控制器视图。它在视图中包含了略微修改的Python语法,以便在不限制正确使用Python的情况下获得更易读的代码。

web2py视图的主要目的是将python代码嵌入到HTML文档中。但是,它面临一些问题,如下所示:

  • 在HTML文档中转义嵌入的python代码。
  • 遵循基于Python的缩进,这可能会影响HTML规则。

为了解决这些问题,web2py在视图部分使用分隔符{{..}}。这些分隔符有助于转义嵌入的python代码。它还有助于遵循HTML的缩进规则。

包含在{{..}}分隔符内的代码包含意外的Python代码。由于Python通常使用缩进分隔代码块,因此分隔符内的意外代码应以正确的方式维护。为了克服这个问题,web2py使用“pass”关键字。

以行开头并以冒号结尾的代码块以以pass开头的行结束。

注意 - pass是Python关键字,它不是web2py关键字。

以下代码显示了pass关键字的实现:

{{
   if num > 0:
      response.write('positive number')
   else:
      response.write('negative number')
      pass
}}

HTML助手

web2py包含助手类,可用于以编程方式构建HTML程序。它对应于HTML标签,称为“HTML助手”。

例如:

[(A('Home', _href = URL('default', 'home')), False, None, []), ...]

这里,A是对应于HTML锚<a>标签的助手。它以编程方式构建HTML锚<a>标签。

HTML助手由两种类型组成,即位置命名参数。

  • 位置参数被解释为包含在HTML开始和结束标签之间的对象。

  • 以下划线开头的命名参数被解释为HTML标签。

助手在字符串序列化中也很有用,使用_str_和xml方法。例如:

>>> print str(DIV(“hello world”))

输出

<div> hello world </div>

注意 - HTML助手提供了文档对象模型(DOM)的服务器端表示。

XML助手

XML被称为一个对象,它封装了不应该转义的文本。文本可能包含也可能不包含有效的XML。

例如,对于下面提到的代码,它可能包含JavaScript。

>>> print XML('<script>alert("unsafe!")</script>')

输出

<script> alert(“unsafe!”)</script>

内置助手

web2py中使用了许多内置助手。一些HTML内置助手如下所示。

名称 用法 示例
A 此助手用于构建链接。它对应于锚标签
[
(A('Home', _href = URL('default', 'home')), False, None, []),
...]
B 此助手有助于使文本内容加粗。
B('<hello>', XML('<i>world</i>'), _class = 'test', _id = 0)
BODY 此助手创建页面的主体。它还包含一个乘法运算符以增加换行符的数量。
BR()
CODE 它对Python、C、C++和web2py代码执行语法高亮显示。此助手还可以链接API文档。
CODE('print "hello"', language = 'python').xml()
FIELDSET 它创建输入字段及其标签。
FIELDSET('Height:', INPUT(_name = 'height'), _class = 'test')
HEAD 它有助于标记HTML页面的<head>标签。
HEAD(TITLE('<hello>'))
IMG 它有助于为给定的HTML页面嵌入图像。
IMG(_src = 'http://example.com/image.png',_alt = 'test')

自定义助手

这些助手用于根据需要自定义标签。web2py使用以下自定义助手:

TAG

web2py使用TAG作为通用标签生成器。它有助于生成自定义XML标签。通用语法如下:

{{ = TAG.name('a', 'b', _c = 'd')}}

它生成以下XML代码:<name c = "d">ab</name>

TAG是一个对象,而TAG.nameTAG['name']是一个返回临时助手类的函数。

MENU

此助手列出列表项或菜单项的值,生成一个树状结构来表示菜单。菜单项列表的形式为response.menu。例如:

print MENU([['One', False, 'link1'], ['Two', False, 'link2']])

输出将显示如下:

<ul class = "web2py-menu web2py-menu-vertical">
   <li><a href = "link1">One</a></li>
   <li><a href = "link2">Two</a></li>
</ul>

BEAUTIFY

它有助于构建复合对象的表示形式,包括列表和字典。例如,

{{ = BEAUTIFY({"a": ["hello", XML("world")], "b": (1, 2)})}}

它返回一个可序列化为XML的XML对象,并包含其构造函数参数的表示形式。在这种情况下,表示形式将是:

{"a": ["hello", XML("world")], "b": (1, 2)}

输出将呈现为:

<table>
   <tr>
      <td>a</td>
      <td>:</td>
      <td>hello<br />world</td>
   </tr>
   
   <tr>
      <td>b</td>
      <td>:</td>
      <td>1<br />2</td>
   </tr>
</table>

服务器端DOM渲染

服务器端渲染允许用户预渲染web2py组件的初始状态。所有派生的助手都提供搜索元素和元素以在服务器端渲染DOM。

element返回与指定条件匹配的第一个子元素。另一方面,elements返回所有匹配子元素的列表。两者使用相同的语法。

这可以通过以下示例演示:

a = DIV(DIV(DIV('a', _id = 'target',_class = 'abc')))
d = a.elements('div#target')
d[0][0] = 'changed'
print a

输出如下:

<div><div><div id = "target" class = "abc">changed</div></div></div>

页面布局

视图用于将输出显示给最终用户。它可以扩展也可以包含其他视图。这将实现一个树状结构。

例如 - “index.html”扩展到“layout.html”,它可以包含“menu.html”,而“menu.html”又包含“header.html”

{{extend 'layout.html'}}
<h1>Hello World</h1>
{{include 'page.html'}}

示例

在前面的章节中,我们为公司模块创建了模型和控制器。现在,我们将重点关注视图的创建,它有助于呈现数据的显示。

默认情况下,web2py中的视图包括layout.htmlindex.html,它们定义了显示数据的整体部分。

{{extend 'layout.html'}}
<h2>Companies</h2>

<table>
   {{for company in companies:}}
   <tr>
      <td>{{ = A(company.name, _href = URL('contacts', args = company.id))}}</td>
      <td>{{ = A('edit', _href = URL('company_edit', args = company.id))}}</td>
   </tr>
   
   {{pass}}
   <tr>
      <td>{{ = A('add company', _href = URL('company_create'))}}</td>
   </tr>
	
</table>

输出将如下所示:

View Creation

Web2py - 数据库抽象层

数据库抽象层(DAL)被认为是web2py的主要优势。DAL向底层SQL语法公开了简单的应用程序编程接口(API)。

在本章中,我们将了解DAL的一些非平凡应用,例如构建查询以有效地按标签搜索以及构建分层类别树。

DAL的一些重要特性包括:

  • web2py包含一个数据库抽象层(DAL),这是一个将Python对象映射到数据库对象的API。数据库对象可以是查询、表和记录。

  • DAL使用为数据库后端指定的方言实时动态生成SQL,因此开发人员不必编写完整的SQL查询。

  • 使用DAL的主要优势在于,应用程序可以与不同类型的数据库移植。

DAL入门

web2py中的大多数应用程序都需要数据库连接。因此,构建数据库模型是应用程序设计的第一个步骤。

考虑名为“helloWorld”的新创建的应用程序。数据库在应用程序的模型下实现。所有相应应用程序的模型都包含在名为models/db_custom.py的文件中。

实现DAL使用以下步骤:

步骤1 - DAL构造函数

建立数据库连接。这是使用DAL对象创建的,该对象也称为DAL构造函数。

db = DAL ('sqlite://storage.sqlite')

DAL的一个显著特点是它允许与同一个数据库或不同的数据库建立多个连接,甚至可以与不同类型的数据库建立连接。可以观察到,此行已存在于models/db.py文件中。因此,您可能不需要它,除非您删除了它或需要连接到不同的数据库。默认情况下,web2py连接到存储在storage.sqlite文件中的SQLite数据库。

此文件位于应用程序的databases文件夹中。如果该文件不存在,则在第一次执行应用程序时由web2py创建。

SQLite速度很快,并将所有数据存储在一个文件中。这意味着您的数据可以轻松地从一个应用程序传输到另一个应用程序。事实上,SQLite数据库与应用程序一起打包在web2py中。它提供完整的SQL支持,包括翻译、联接和聚合。

SQLite有两个缺点。

  • 一个是它不强制执行列类型,并且除了添加和删除列之外,没有ALTER TABLE。

  • 另一个缺点是,任何需要写访问权限的事务都会锁定整个数据库。

步骤2 - 表构造函数

一旦与数据库建立连接,我们就可以使用define_table方法来定义新表。

例如:

db.define_table('invoice',Field('name'))

上述方法也在表构造函数中使用。表构造函数的语法相同。第一个参数是表名,后面跟着一个字段(Field)列表。字段构造函数采用以下参数:

序号 参数和用法
1

字段名称

表中字段的名称。

2

字段类型

采用具有任何数据类型的值,例如字符串(默认)、文本、布尔值、整数等。

3

长度

定义最大长度。

4

default = None

这是插入新记录时的默认值。

5

update = None

此功能与default相同,但该值仅在更新时使用,而不是在插入时使用。

6

Notnull

这指定字段值是否可以为NULL。

7

readable = True

这指定字段是否在表单中可读。

8

writable = True

这指定字段是否在表单中可写。

9

label = "Field Name"

这是在表单中用于此字段的标签。

define_table方法还采用三个命名参数:

语法

db.define_table('....',migrate=True, fake_migrate=False, format = '%(id)s')
  • migrate = True - 这指示web2py在表不存在时创建它,或者在它与模型定义不匹配时更改它。

  • fake_migrate = False - 如果模型与数据库表内容匹配,则将fake_migrate设置为True,这有助于web2py重建数据。

  • format = '%(id)s' - 这是一个格式字符串,用于确定如何表示给定表上的记录。

生成原始SQL

使用DAL,我们可以建立与数据库的连接,并使用表构造函数和字段构造函数创建新表及其字段。

有时,需要生成SQL语句以符合必要的输出。web2py包含各种函数,这些函数有助于生成原始SQL,如下所示:

_insert

它有助于为给定表获取插入语句。例如,

print db.person._insert(name ='ABC')

它将检索名为“person”表的插入语句。

SQL语句输出:

INSERT INTO person(name) VALUES ('ABC');

_count

它有助于获取SQL语句,该语句给出记录的数量。例如,考虑一个名为“person”的表,我们需要查找姓名为“ABC”的人员数量。

print db(db.person.name ==' ABC ')._count()

SQL语句输出:

SELECT count(*) FROM person WHERE person.name = ' ABC ';

_select

它有助于获取select SQL语句。例如,考虑一个名为“person”的表,我们需要查找姓名为“ABC”的人员列表。

print db(db.person.name == ' ABC ')._select()

SQL语句输出:

SELECT person.name FROM person WHERE person.name = ' ABC ';

_delete

它有助于获取delete SQL语句。例如,考虑名为“person”的表,我们需要删除姓名为“ABC”的语句。

print db(db.person.name == ' ABC ')._delete()

SQL语句输出:

DELETE FROM person WHERE person.name = ' ABC ';4

_update

它有助于获取更新的SQL语句。例如,考虑名为“person”的表,我们需要将列名更新为其他值。

print db(db.person.name == ' ABC ')._update()

SQL语句输出:

UPDATE person SET WHERE person.name = ’Alex’;

DAL问题(注意事项)

SQLite

SQLite缺乏删除或更改列的支持。从表中删除字段会使其在数据库中保持活动状态,因此web2py将不会意识到所做的任何更改。

在这种情况下,有必要将fake_migrate = True设置为True,这将有助于重新定义元数据,以便任何更改(例如更改或删除)都将在web2py的了解范围内。

SQLite不支持布尔类型。为此,web2py在内部将布尔值映射到1个字符字符串,其中'T'和'F'分别表示trueFalse

MySQL

MySQL 不支持 ALTER TABLE 功能。因此,数据库迁移涉及多个提交。可以通过在定义数据库时设置参数fake_migrate = True来避免这种情况,这将保留所有元数据。

Oracle

Oracle 不支持记录分页功能。它也不支持 OFFSET 或 limit 关键字。为此,web2py 通过使用复杂的 DAL 三重嵌套选择来实现分页。如果使用了 Oracle 数据库,DAL 需要自行处理分页。

Web2py - 表单 & 验证器

web2py 带有强大的表单生成功能。在 web2py 中构建表单的四种不同方法如下:

  • FORM - 就 HTML 助手而言,它被认为是低级实现。FORM 对象知道其字段内容。

  • SQLFORM - 它为现有数据库提供创建、更新和删除的功能。

  • SQLFORM.factory - 它被认为是 SQLFORM 之上的抽象层,它生成类似于 SQLFORM 的表单。这里不需要创建新的数据库。

  • CRUD 方法 - 顾名思义,它提供了基于 SQLFORM 的具有类似功能的创建、检索、更新和删除功能。

FORM

考虑一个应用程序,它接受用户的输入并有一个“提交”按钮来提交响应。

控制器

“default.py”控制器将包含以下关联函数

def display_form():
   return dict()

视图

关联视图“default/display_form.html”将以 HTML 渲染表单的显示如下:

{{extend 'layout.html'}}
<h2>Basic Form</h2>

<form enctype = "multipart/form-data" action = "{{= URL()}}" method = "post">
   Your name:
   <input name = "name" />
   <input type = "submit" />
</form>

<h2>Submitted variables</h2>
{{= BEAUTIFY(request.vars)}}

以上示例是普通的 HTML 表单,它请求用户输入。可以使用 FORM 对象等助手生成相同的表单。

控制器

def display_form():
   form = FORM('Value:', INPUT(_value = 'name'), INPUT(_type = 'submit'))
   return dict(form = form)

“default.py”控制器中的上述函数包含 FORM 对象(HTML 助手),它有助于创建表单。

视图

{{extend 'layout.html'}}
<h2>Basic form</h2>

{{= form}}
<h2>Submitted variables</h2>

{{= BEAUTIFY(request.vars)}}

语句{{= form}}生成的表单序列化 FORM 对象。当用户填写表单并点击提交按钮时,表单会自行提交,并且变量request.vars.value及其输入值会显示在底部。

SQLFORM

它有助于为现有数据库创建表单。下面讨论了其实现步骤。

使用 DAL 建立与数据库的连接,这是使用 DAL 对象创建的,也称为 DAL 构造函数。建立连接后,用户可以创建相应的表。

db = DAL('sqlite://storage.sqlite')
db.define_table('employee', Field('name', requires = IS_NOT_EMPTY()))

因此,我们创建了一个名为“employee”的表。控制器使用以下语句构建表单和按钮:

form = SQLFORM(
   db.mytable,
   record = mytable_index,
   deletable = True,
   submit_button = T('Update')
)

因此,对于创建的 employee 表,控制器中的修改将是:

def display_form():
   form = SQLFORM(db.person)

视图中没有修改。在新控制器中,需要构建一个 FORM,因为在模型中定义的 SQLFORM 构造函数从表 db.employee 构建了一个。新表单序列化后,显示如下:

<form enctype = "multipart/form-data" action = "" method = "post">
   
   <table>
      <tr id = "employee_name__row">
         <td>
            <label id = "person_name__label" for = "person_name">Your name: </label>
         </td>
         
         <td>
            <input type = "text" class = "string" name = "name" value = "" id = "employee_name" />
         </td>
         
         <td></td>
      </tr>

      <tr id = "submit_record__row">
         <td></td>
         <td><input value = "Submit" type = "submit" /></td>
         <td></td>
      </tr>
		
   </table>

   <input value = "9038845529" type = "hidden" name = "_formkey" />
   <input value = "employee" type = "hidden" name = "_formname" />
	
</form>

表单中的所有标签都具有从表和字段名称派生的名称。

SQLFORM 对象还可以处理“上传”字段,方法是将上传的文件保存在“uploads”文件夹中。这是自动完成的。SQLFORM 使用复选框显示“布尔”值,并使用“textareas”显示文本值。

SQLFORM 还使用 process 方法。如果用户希望保留与关联的 SQLFORM 关联的值,则需要这样做。

如果form.process(keepvalues = True),则接受。

示例

def display_form():
   form = SQLFORM(db.employee)
if form.process().accepted:
   response.flash = 'form accepted'

elif form.errors:
   response.flash = 'form has errors'
else:
   response.flash = 'please fill out the form'

return dict(form = form)

SQLFORM.factory

有时,用户需要以一种方式生成表单,即存在一个现有数据库表,但没有实现数据库。用户只是想利用 SQLFORM 的功能。

这是通过form.factory完成的,它保存在会话中。

def form_from_factory():
   form = SQLFORM.factory(
      Field('your_name', requires = IS_NOT_EMPTY()),
      Field('your_image', 'upload'))

   if form.process().accepted:
      response.flash = 'form accepted'
      session.your_name = form.vars.your_name
      session.your_image = form.vars.your_image
   elif form.errors:
      response.flash = 'form has errors'

   return dict(form = form)

该表单将显示为 SQLFORM,其字段为名称和图像,但数据库中不存在这样的表。

“default/form_from_factory.html”视图将表示为:

{{extend 'layout.html'}}
{{= form}}

CRUD 方法

CRUD 是在 SQLFORM 之上使用的 API。顾名思义,它用于创建、检索、更新和删除相应的表单。

与 web2py 中的其他 API 相比,CRUD 未公开;因此,必须导入它。

from gluon.tools import Crud
crud = Crud(db)

上面定义的 CRUD 对象提供了以下 API:

序号 API & 功能
1

crud.tables()

返回数据库中定义的表列表。

2

crud.create(db.tablename)

返回表 tablename的创建表单。

3

crud.read(db.tablename, id)

返回tablename和记录 id 的只读表单。

4

crud.delete(db.tablename, id)

删除记录

5

crud.select(db.tablename, query)

返回从表中选择的记录列表。

6

crud.search(db.tablename)

返回一个元组 (form, records),其中 form 是搜索表单。

7

crud()

根据 request.args() 返回上述内容之一。

表单创建

让我们创建一个表单。请按照以下代码操作。

模型

在应用程序的models文件夹下创建一个新的模型。文件名为“dynamic_search.py”

def build_query(field, op, value):
   if op == 'equals':
      return field == value
   
   elif op == 'not equal':
      return field != value
   
   elif op == 'greater than':
      return field > value
   
   elif op == 'less than':
      return field < value
   
   elif op == 'starts with':
      return field.startswith(value)
   
   elif op == 'ends with':
      return field.endswith(value)
   
   elif op == 'contains':
      return field.contains(value)

def dynamic_search(table):
   tbl = TABLE()
   selected = []
   ops = ['equals', 
      'not equal',
      'greater than',
      'less than',
      'starts with',
      'ends with',
      'contains']
		
query = table.id > 0

for field in table.fields:
   chkval = request.vars.get('chk'+field,None)
   txtval = request.vars.get('txt'+field,None)
   opval = request.vars.get('op'+field,None)
	
row = TR(TD(INPUT(_type = "checkbox",_name = "chk"+field,value = chkval == 'on')),
   TD(field),TD(SELECT(ops,_name = "op"+field,value = opval)),
   TD(INPUT(_type = "text",_name = "txt"+field,_value = txtval)))
	
tbl.append(row)

if chkval:
   if txtval:
      query &= build_query(table[field], opval,txtval)
      selected.append(table[field])
      form = FORM(tbl,INPUT(_type="submit"))
      results = db(query).select(*selected)
   return form, results

控制器

控制器部分名为“dynamic_search.py”的关联文件将包含以下代码:

def index():
   form,results = dynamic_search(db.things)
   return dict(form = form,results = results)

视图

我们可以使用以下视图呈现它。

{{extend 'layout.html'}}
{{= form}}
{{= results}}

它看起来像这样:

View

Web2py - 邮件 & 短信

web2py 包括向用户发送电子邮件和短信的功能。它使用库来发送电子邮件和短信。

设置电子邮件

名为gluon.tools.Mail的内置类用于在 web2py 框架中发送电子邮件。邮件服务器可以使用此类定义。

from gluon.tools import Mail
mail = Mail()
mail.settings.server = 'smtp.example.com:25'
mail.settings.sender = '[email protected]'
mail.settings.login = 'username:password'

每次发送电子邮件时,都会对上述示例中提到的发件人电子邮件及其密码进行身份验证。

如果用户需要进行实验或用于某些调试目的,可以使用以下代码实现。

mail.settings.server = 'logging'

现在,所有电子邮件都不会发送,但会记录在控制台中。

发送电子邮件

一旦我们使用邮件对象设置了电子邮件的配置设置,就可以向许多用户发送电子邮件。

mail.send()的完整语法如下:

send(
   to, subject = 'Abc',
   message = 'None', attachments = [],
   cc = [], bcc = [], reply_to = [],
   sender = None, encoding = 'utf-8',
   raw = True, headers = {}
)

mail.send()的实现如下所示。

mail.send(
   to = ['[email protected]'], subject = 'hello',
   reply_to = '[email protected]',
   message = 'Hello ! How are you?'
)

Mail根据邮件服务器的响应返回一个布尔表达式,即最终用户是否收到邮件。如果成功向用户发送电子邮件,则返回True

属性 to、ccbcc包含要发送邮件的有效电子邮件地址列表。

发送短信

在 web2py 框架中,发送短信的实现与发送电子邮件不同,因为它需要第三方服务来将消息转发给接收者。第三方服务不是免费服务,并且显然会因地理区域(从国家到国家)而异。

web2py 使用一个模块来帮助发送短信,过程如下:

from gluon.contrib.sms_utils
import SMSCODES, sms_email
email = sms_email('1 (111) 111-1111','T-Mobile USA (abc)')
mail.send(to = email, subject = 'test', message = 'test')

在以上示例中,SMSCODES是 web2py 维持的字典,它将主要电话公司的名称映射到电子邮件地址后缀。

电话公司通常将来自第三方服务的电子邮件视为垃圾邮件。更好的方法是电话公司自己转发短信。每个电话公司在其存储中为每个手机号码包含一个唯一的电子邮件地址,并且可以将短信直接发送到该电子邮件。

在以上示例中,

  • sms_email函数接收一个电话号码(作为字符串),返回该电话的电子邮件地址。

  • 脚手架应用程序包含多个文件。其中一个是 models/db.py,它导入了四个。

  • 来自gluon.tools的类也包括邮件库,并定义了各种全局对象。

  • 脚手架应用程序还定义了 auth 对象所需的表,例如db.auth_user。默认脚手架应用程序旨在最大程度地减少文件数量,而不是模块化。特别是模型文件db.py包含配置,在生产环境中,最好将其保存在单独的文件中。

在这里,我们建议创建一个配置文件:

from gluon.storage import Storage
   settings = Storage()
   settings.production = False
   
   if
      settings.production:
      settings.db_uri = 'sqlite://production.sqlite'
      settings.migrate = False
   else:
      settings.db_uri = 'sqlite://development.sqlite'
      settings.migrate = True
      settings.title = request.
      settings.subtitle = 'write something here'
		
      settings.author = 'you'
      settings.author_email = '[email protected]'
		
      settings.keywords = ''
      settings.description = ''
      settings.layout_theme = 'Default'
      settings.security_key = 'a098c897-724b-4e05-b2d8-8ee993385ae6'
		
      settings.email_server = 'localhost'
      settings.email_sender = '[email protected]'
      settings.email_login = ''
		
      settings.login_method = 'local'
      settings.login_config = ''

Web2py - 访问控制

身份验证

几乎每个应用程序都需要能够对用户进行身份验证并设置权限。web2py 带有一个广泛且可定制的基于角色的访问控制机制.web2py。它还支持 CAS、OpenID、OAuth 1.0、LDAP、PAM、X509 等协议。

web2py 包含一种称为基于角色的访问控制机制 (RBAC) 的机制,这是一种限制授权用户访问系统的方法。实现 RBAC 的 web2py 类称为 Auth。

查看下面的模式。

Auth

Auth定义了以下表:

序号 表名 & 描述
1

auth_user

存储用户的姓名、电子邮件地址、密码和状态。

2

auth_group

以多对多的结构存储用户的组或角色

3

auth_membership

以多对多的结构存储用户和组链接的信息

4

auth_permission

该表链接组和权限。

5

auth_event

记录其他表中的更改和成功访问

6

auth_cas

它用于中央身份验证服务

自定义 Auth

有两种方法可以自定义 Auth。

  • 从头开始定义自定义db.auth_user表。

  • 让 web2py 定义auth表。

让我们看看定义auth表的最后一种方法。在db.py模型中,替换以下行:

auth.define_tables()

将其替换为以下代码:

auth.settings.extra_fields['auth_user'] = [
   Field('phone_number',requires = IS_MATCH('\d{3}\-\d{3}\-\d{4}')),
   Field('address','text')
]

auth.define_tables(username = True)

假设每个用户都包含电话号码、用户名和地址。

auth.settings.extra_fields是额外字段的字典。键是要向其添加额外字段的 auth 表的名称。值是额外字段的列表。在这里,我们添加了两个额外字段,phone_number 和 address

username必须以特殊方式处理,因为它涉及身份验证过程,该过程通常基于电子邮件字段。通过将 username 参数传递给以下行,它会通知 web2py 我们想要 username 字段,并且我们希望使用它来登录而不是电子邮件字段。它充当主键。

auth.define_tables(username = True)

用户名被视为唯一值。在某些情况下,注册可能发生在正常的注册表单之外。这种情况也可能发生,新用户被迫登录以完成注册。

这可以通过一个虚拟字段complete_registration来完成,该字段默认设置为False,并在他们更新个人资料时设置为True

auth.settings.extra_fields['auth_user'] = [
   Field('phone_number',requires = IS_MATCH('\d{3}\-\d{3}\-\d{4}'),
   comment = "i.e. 123-123-1234"),
   Field('address','text'),
   Field('complete_registration',default = False,update = True,
   writable = False, readable = False)
]

auth.define_tables(username = True)

这种情况可能意在让新用户在登录后完成注册。

db.py(models 文件夹中),我们可以追加以下代码:

if auth.user and not auth.user.complete_registration:
if not (request.controller,request.function) == ('default','user'):
   redirect(URL('default','user/profile'))

这将强制新用户根据需要编辑其个人资料。

授权

它是授予某些访问权限或向用户授予某些权限的过程。

在 web2py 中,一旦创建或注册了新用户,就会创建一个新组来包含该用户。新用户的角色通常称为“user_[id]”,其中 id 是用户的唯一标识。

创建新组的默认值为:

auth.settings.create_user_groups = "user_%(id)s"

可以通过以下方式禁用用户之间组的创建:

auth.settings.create_user_groups = None

创建、授予特定成员的访问权限和权限可以通过 appadmin 的帮助以编程方式实现。

一些实现列出如下:

序号 命令 & 用法
1

auth.add_group('role', 'description')

返回新创建组的 id。

2

auth.del_group(group_id)

删除具有指定 id 的组

3

auth.del_group(auth.id_group('user_7'))

删除具有给定标识的用户组。

4

auth.user_group(user_id)

返回与给定用户唯一关联的组 id 的值。

5

auth.add_membership(group_id, user_id)

返回给定 group_id 的 user_id 值

6

auth.del_membership(group_id, user_id)

撤销给定 member_id(即 user_id)对给定组的访问权限。

7

auth.has_membership(group_id, user_id, role)

检查用户ID是否属于给定组。

中央认证服务 (CAS)

web2py 提供了一个行业标准,即客户端认证服务 - CAS,用于 web2py 中的客户端和服务器内置功能。它是一个第三方身份验证工具。

它是一个用于分布式身份验证的开放协议。CAS 的工作原理如下:

  • 如果用户访问网站,该协议会检查用户是否已通过身份验证。

  • 如果用户未通过应用程序的身份验证,则协议会重定向到用户可以在其中注册或登录应用程序的页面。

  • 如果注册完成,用户会收到一封电子邮件。除非用户验证电子邮件,否则注册不完整。

  • 注册成功后,用户将使用 CAS 设备使用的密钥进行身份验证。

  • 该密钥用于通过 HTTP 请求获取用户凭据,该请求在后台设置。

Web2py - 服务

web2py 支持各种协议,如 XML、JSON、RSS、CSV、XMLRPC、JSONRPC、AMFRPC 和 SOAP。每种协议都以多种方式支持,我们区分以下两种情况:

  • 以给定格式呈现函数的输出。
  • 远程过程调用。

呈现字典

考虑以下维护会话计数的代码。

def count():
   session.counter = (session.counter or 0) + 1
   return dict(counter = session.counter, now = request.now)

上述函数在用户访问页面时增加计数。假设给定函数在 web2py 应用程序的“default.py”控制器中定义。可以使用以下 URL 请求该页面:http://127.0.0.1:8000/app/default/count

web2py 可以通过向 URL 添加扩展名,以不同的协议呈现上述页面,例如:

http://127.0.0.1:8000/app/default/count.html

http://127.0.0.1:8000/app/default/count.xml

http://127.0.0.1:8000/app/default/count.json

上述操作返回的字典将以 HTML、XML 和 JSON 格式呈现。

远程过程调用

web2py 框架提供了一种机制,可以将函数转换为 Web 服务。此处描述的机制与之前描述的机制不同,因为:

  • 在函数中包含参数。
  • 函数必须在模型中定义。
  • 它强制执行更严格的 URL 命名约定。
  • 它适用于一组固定的协议,并且易于扩展。
  • 要使用此功能,需要导入并初始化服务对象。

要实现此机制,首先必须导入并实例化服务对象。

from gluon.tools import Service
service = Service()

这在脚手架应用程序的“db.py”模型文件中实现。“Db.py”模型是 web2py 框架中的默认模型,它与数据库和控制器交互,以向用户提供所需的输出。

实现后,可以根据需要从控制器访问模型中的服务。

以下示例显示了使用 Web 服务实现远程过程调用的各种方法,以及更多方法。

Web 服务

Web 服务可以定义为使用 XML、SOAP、WSDL 和 UDDI 等协议集成基于 Web 的应用程序的标准化方法。

web2py 支持其中大多数,但集成将非常棘手。

使用 jQuery 使用 web2py JSON 服务

从 web2py 返回 JSON 形式的方法有很多,但这里我们考虑 JSON 服务的情况。例如:

def consumer():return dict()@service.json
def get_days():return ["Sun", "Mon", "Tues", "Wed", "Thurs", "Fri", "Sat"]
def call():return service()

在这里,我们观察到:

  • 该函数仅返回一个空字典以呈现视图,该视图将使用该服务。

  • get_days 定义了服务,并且函数调用公开了所有注册的服务。

  • get_days 不需要在控制器中,也可以在模型中。

  • call 始终位于 default.py 脚手架控制器中。

包含使用者操作的视图如下:

{{extend 'layout.html'}}
<div id = "target"></div>

<script>
   jQuery.getJSON("{{= URL('call',args = ['json','get_days'])}}",
      function(msg){
         jQuery.each(msg, function(){ jQuery("#target").
         append(this + "<br />"); } )
      }
   );
</script>

jQuery.getJSON 的第一个参数是以下服务的 URL:http://127.0.0.1:8000/app/default/call/json/get_days

这始终遵循以下模式:

http://<domain>/<app>/<controller>/call/<type>/<service>

URL 位于{{...}}之间,因为它是服务器端解析的,而其他所有内容都在客户端执行。jQuery.getJSON 的第二个参数是一个回调函数,它将传递 JSON 响应。

在这种情况下,回调函数遍历响应中的每个项目(作为字符串的星期列表),并将每个字符串附加到<div id = "target">后面,并在后面加上<br/>

这样,web2py 使用jQuery.getJSON管理 Web 服务的实现。

Web2py - 添加 Ajax 效果

在本章中,我们将讨论jQuery插件与web2py集成的示例。这些插件有助于使表单和表格对用户更具交互性和友好性,从而提高应用程序的可用性。

特别是,我们将学习

  • 如何使用交互式添加选项按钮改进多选下拉列表,

  • 如何用滑块替换输入字段,以及

  • 如何使用jqGridWebGrid显示表格数据。

尽管 web2py 是一个服务器端开发组件,但welcome脚手架应用程序包含基本jQuery库。此脚手架 web2py 应用程序“welcome”包含一个名为views/web2py_ajax.html的文件。

视图的内容如下:

<script type = "text/javascript"><!--

   // These variables are used by the web2py_ajax_init function in web2py_ajax.js 
      (which is loaded below).
		
   var w2p_ajax_confirm_message = "{{= T('Are you sure you want to delete this object?')}}";
   var w2p_ajax_disable_with_message = "{{= T('Working...')}}";
   var w2p_ajax_date_format = "{{= T('%Y-%m-%d')}}";
   var w2p_ajax_datetime_format = "{{= T('%Y-%m-%d %H:%M:%S')}}";
   
   var ajax_error_500 = '{{=T.M('An error occured, please [[reload %s]] the page') %
	
      URL(args = request.args, vars = request.get_vars) }}'
		
//--></script>

{{
   response.files.insert(0,URL('static','js/jquery.js'))
   response.files.insert(1,URL('static','css/calendar.css'))
   response.files.insert(2,URL('static','js/calendar.js'))
   response.files.insert(3,URL('static','js/web2py.js'))
   response.include_meta()
   response.include_files()
}}

该文件包含 JavaScript 和 AJAX 实现。web2py 将阻止用户使用其他 AJAX 库(如 Prototype、ExtJS),因为它始终观察到实现此类库更容易。

JQuery 效果

<select multiple = "true">..</select>的默认呈现被认为使用起来不太直观,尤其是在需要选择非连续选项时。这不能称为 HTML 的缺点,而是大多数浏览器的设计不佳。可以使用 JavaScript 覆盖多选的显示方式。这可以使用名为jquery.multiselect.js的 jQuery 插件来实现。

为此,用户应从http://abeautifulsite.net/2008/04/jquery-multiselect下载插件jquery.muliselect.js,并将相应的文件放入static/js/jquery.multiselect.jsstatic/css/jquery.multiselect.css

示例

应在相应的视图中{{extend ‘layout.html’}}之前添加以下代码

{{
   response.files.append('https://ajax.googleapis.com/ajax\
      /libs/jqueryui/1.8.9/jquery-ui.js')
   
   response.files.append('https://ajax.googleapis.com/ajax\
      /libs/jqueryui/1.8.9/themes/ui-darkness/jquery-ui.css')
   
   response.files.append(URL('static','js/jquery.multiSelect.js'))
   response.files.append(URL('static','css/jquery.\multiSelect.css'))
}}

将以下内容放在{{extend 'layout.html'}}之后:

<script>
   jQuery(document).ready(function(){jQuery('[multiple]').multiSelect();});
</script>

这将有助于为给定表单设置multiselect的样式

控制器

def index():
   is_fruits = IS_IN_SET(['Apples','Oranges','Bananas','Kiwis','Lemons'], multiple = True)
   form = SQLFORM.factory(Field('fruits','list:string', requires = is_fruits))
   
   if form.accepts(request,session):response.flash = 'Yummy!'
return dict(form = form)

可以使用以下视图尝试此操作:

{{
   response.files.append('https://ajax.googleapis.com/ajax\
      /libs/jqueryui/1.8.9/jquery-ui.js')
   
   response.files.append('https://ajax.googleapis.com/ajax\
      /libs/jqueryui/1.8.9/themes/ui-darkness/jquery-ui.css')
   
   response.files.append(URL('static','js/jquery.multiSelect.js'))
   response.files.append(URL('static','css/jquery.\multiSelect.css'))
}}

{{extend 'layout.html}}
<script>
   jQuery(document).ready(function(){jQuery('[multiple]'). multiSelect();});
</script>
{{= form}}

输出的屏幕截图如下:

controller view

下表列出了一些有用的 Jquery 事件:

序号 事件及用法
1

onchange

元素更改时运行

2

onsubmit

提交表单时运行

3

onselect

选择元素时运行

4

onblur

元素失去焦点时运行

5

onfocus

元素获得焦点时运行

JQuery 和 Ajax-jqGrid

jqGrid 是一个基于 jQuery 构建的启用 Ajax 的 JavaScript 控件,它提供了一种表示和操作表格数据的解决方案。jqGrid是一个客户端解决方案,它通过 Ajax 回调动态加载数据,从而提供分页、搜索弹出窗口、内联编辑等功能。

jqGrid 集成到 PluginWiki 中,但在这里,我们将它作为 web2py 程序(不使用该插件)的独立程序进行讨论。jqGrid 值得专门写一本书,但在这里我们只讨论其基本功能和最简单的集成。

jqGrid 的语法如下:

def JQGRID(
   table, fieldname = None,
   fieldvalue = None, col_widths = [],
   colnames = [], _id = None, fields = [],
   col_width = 80, width = 700,
   height = 300, dbname = 'db'
):

Web2py - 组件

组件定义为 Web 页面的功能部分,它可以自主工作。它可以由嵌入在 Web 页面中的模块、控制器和视图组成。应用程序中的组件必须是本地化的标签,并且性能被认为独立于模块。

在 web2py 中,主要关注的是使用加载到页面中并通过 AJAX 与组件控制器通信的组件。

web2py 包含一个名为LOAD的函数,该函数使组件的实现变得容易,无需显式使用 JavaScript 或 AJAX 编程。

考虑一个名为“test”的简单 Web 应用程序,该应用程序使用文件“models/db_comments.py”中的自定义模型扩展 web2py 应用程序。

db.define_table(
   'comment_post', Field('body','text',
   label = 'Your comment'),auth.signature
)

以上代码将创建一个名为“comment_post”的表,并具有正确的表定义。该操作将借助“controllers/comments.py”中的函数来实现。

def post():
   return dict(
      form = SQLFORM(db.comment_post).process(),
      comments = db(db.comment_post).select()
   )

相应的视图将显示为:

{{extend 'layout.html'}}
{{for post in comments:}}

<div class = "post">
   On {{= post.created_on}} {{= post.created_by.first_name}}
   says <span class = "post_body">{{= post.body}}</span>
</div>

{{pass}}
{{= form}}

可以使用给定 URL 访问该页面:http://127.0.0.1:8000/test/comments/post

上面提到的方法是访问视图的传统方法,可以通过实现 LOAD 函数来更改它。

这可以通过创建一个扩展名为“.load”的新视图来实现,该视图不扩展布局。

创建的新视图将为"views/comments/post.load"

<div class = "post">
   On {{= post.created_on}} {{= post.created_by.first_name}}
   says <blockquote class = "post_body">{{= post.body}}</blockquote>
</div>

{{pass}}
{{= form}}

访问该页面的 URL 将为:http://127.0.0.1:8000/test/comments/post.load

LOAD 组件可以嵌入到 web2py 应用程序的任何其他页面中。这可以通过使用以下语句来完成。

{{= LOAD('comments','post.load',ajax = True)}}

例如,可以编辑控制器如下:

def index():
   return dict()

视图中,我们可以添加组件:

{{extend 'layout.html'}}
{{= LOAD('comments','post.load',ajax = True)}}

可以使用 URL 访问该页面:http://127.0.0.1:8000/test/default/index

组件插件

组件插件是唯一定义组件的插件。组件直接使用其模型定义访问数据库。

如前面的示例中所述,可以在模型部分将注释组件转换为comments_plugin

"models/plugin_comments.py":

db.define_table(
   'plugin_comments_comment',
   Field('body','text', label = 'Your comment'),
   auth.signature
)

控制器将包含以下插件:

def plugin_comments():
   return LOAD('plugin_comments','post',ajax = True)

Web2py - 部署

在 Ubuntu(Linux)中安装 web2py

以下步骤用于在 Ubuntu 桌面中安装 web2py。

步骤 1 - 下载 web2py

cd /home
mkdir www-dev

cd www-dev
wget http://www.web2py.com/examples/static/web2py_src.zip

步骤 2 - 下载完成后,解压缩它。

unzip -x web2py_src.zip

步骤 3 - 可选地为 Python 安装 tk 库,如果您需要访问 GUI。

sudo apt-get install python-tk

步骤 4 - 要启动 web2py,请访问 web2py 目录并运行 web2py。

cd web2py
python web2py.py

GUI 将如下所示:

Web2py Server

安装完成后,每次运行web2py时,都会提示您选择密码。此密码是您的管理员密码。如果密码为空,则管理员界面将被禁用。

服务器启动后,web2py将重定向到以下URL所示的屏幕:http://127.0.0.1:8000/

这将表明web2py在Ubuntu桌面中完美运行。

Ubuntu生产环境部署

步骤1 - 安装运行web2py所需的所有模块。

安装postgreSQL

sudo apt-get install postgresql

解压缩并打开ssh-server

sudo apt-get install unzip
sudo apt-get install openssh-server

安装Apache 2和mod-wsgi

sudo apt-get install apache2
sudo apt-get install libapache2-mod-wsgi

步骤2 - 将web2py安装到/home/www-data

这有助于在生产环境中正确部署。

sudo apt-get install unzip
sudo apt-get install openssh-server
cd /home
sudo mkdir www-data
cd www-data

从web2py网站获取web2py源代码 -

sudo wget http://web2py.com/examples/static/web2py_src.zip
sudo unzip web2py_src.zip
sudo chown -R www-data:www-data web2py

步骤3 - 创建自签名证书。SSL证书应从受信任的证书颁发机构获取。在SSL文件夹中维护证书。

步骤4 - 根据生产环境的要求编辑Apache配置。

步骤5 - 重启Apache服务器并验证给定IP地址的生产环境是否有效。

在Windows上安装web2py

虽然Windows环境存在二进制发行版(打包可执行文件和标准库),但web2py是开源的,可以与普通的Python安装一起使用。

这种方法允许使用web2py的最新版本,并自定义要使用的Python模块。

步骤1 - 从web2py官方网站下载源代码包 - http://www.web2py.com/examples/static/web2py_src.zip 并解压缩。

由于web2py不需要安装,用户可以将其解压缩到任何文件夹中。

步骤2 - 要启动它,请双击web2py.py。从控制台 -

cd c:\web2py
c:\python27\python.exe web2py.py

步骤3 - 这里可以添加命令行参数(-a设置管理员密码,-p指定备用端口)。启动选项可以通过 -

C:\web2py>c:\python27\python.exe web2py.py --help

注意

  • web2py是用Python编写的,Python是一种可移植的、解释型的、动态的语言,不需要编译或复杂的安装即可运行。

  • 它使用虚拟机(如Java和.Net),并且可以在您运行脚本时动态地透明地将您的源代码字节编译。

web2py在数据库和测试方面的功能

它是一个名为SQLDesigner的软件,有助于创建web2py模型并生成相应的代码。下面是一些截图 -

SQL Designer

SQLDesigner有助于以简单的方式维护表之间的关系,并在给定应用程序的模型中生成相应的代码。

SQL Designer Table

功能测试

功能测试涉及测试组件或整个系统的功能。它可以基于需求和业务流程。

web2py带有一个名为gluon.contrib.webclient的模块,它可以在远程和本地web2py应用程序中执行功能测试。它基本上是为了理解web2py会话和回发而设计的。

它只需要导入包,这样功能测试就可以在给定的模块上实现。

导入包的语法如下 -

from gluon.contrib.webclient import WebClient

Web2py - 安全性

在前面的章节中,对web2py与各种工具的集成进行了完整的介绍。开发web2py应用程序的主要关注点包括从用户的角度考虑安全性。

web2py的独特功能如下 -

  • 用户可以轻松学习实现。它不需要安装和依赖项。

  • 自发布之日起就一直稳定。

  • web2py轻量级,包含数据抽象层和模板语言库。

  • 它借助Web服务器网关接口工作,该接口充当Web服务器和应用程序之间的通信桥梁。

开放式Web应用程序安全项目(OWASP)是一个社区,它列出了Web应用程序的安全漏洞。

安全漏洞

关于OWASP,下面讨论了与Web应用程序相关的问题以及web2py如何克服这些问题。

跨站点脚本

也称为XSS。每当应用程序获取用户提供的数据并将其发送到用户的浏览器而没有对内容进行编码或验证时,就会发生这种情况。攻击者执行脚本以使用跨站点脚本注入蠕虫和病毒。

web2py通过阻止视图中所有呈现的变量来帮助防止XSS。

信息泄露

有时,应用程序会泄漏有关内部工作原理、隐私和配置的信息。攻击者利用此信息来破坏敏感数据,这可能导致严重攻击。

web2py通过票据系统防止这种情况。它记录所有错误,并向注册错误的用户发出票据。这些错误只有管理员可以访问。

身份验证错误

帐户凭据通常不受保护。攻击者会危及密码、身份验证令牌以窃取用户的身份。

web2py提供了一种用于管理界面的机制。当客户端不是“localhost”时,它还会强制使用安全会话。

不安全的通信

有时应用程序无法加密网络流量。必须管理流量以保护敏感通信。

web2py提供启用SSL的证书来提供通信加密。这也有助于维护敏感通信。

URL访问限制

Web应用程序通常通过阻止向某些用户显示链接和URL来保护敏感功能。攻击者可以通过使用某些信息操纵URL来尝试破坏某些敏感数据。

在wb2py中,URL映射到模块和函数,而不是给定的文件。它还包括一个机制,该机制指定哪些函数是公开的,哪些函数保持私有。这有助于解决问题。

广告