概述
最美代碼
web2py官方文檔翻譯
2016年2月10日css
啓動html
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公開你的網絡接口。python
若是你不提供管理員密碼,管理界面是禁用的。 這是一個安全措施,以防止公開揭露管理界面。
管理界面, 管理 ,只能從本地主機訪問,除非你使用mod_proxy運行背後web2py Apache。 若是 管理 檢測到一個代理,會話cookie設置爲安全 管理 登陸不工做,除非客戶端和代理之間的通訊在HTTPS;這是一個安全措施。 全部客戶端之間的通訊 管理 必須是本地或加密;不然攻擊者可以執行一我的中間人攻擊和重放攻擊和在服務器上執行任意代碼。
管理密碼已經設置後,web2py啓動web瀏覽器在頁面:
http://127.0.0.1:8000/
若是計算機沒有一個默認的瀏覽器,打開一個web瀏覽器並輸入URL。c++
點擊「管理界面」帶你去管理界面登陸頁面。web
管理員密碼是您選擇在啓動時的密碼。 請注意,只有一個管理員,所以只有一個管理員密碼。 出於安全緣由,開發人員被要求選擇一個新密碼每次web2py開始,除非指定的 <回收> 選項。 這是有別於web2py應用程序的身份驗證機制。
管理員登陸web2py以後,瀏覽器重定向到「網站」頁面。
ajax
這個頁面列出了全部web2py安裝應用程序和容許管理員管理。 web2py有三個應用程序:sql
• 一個 管理 應用程序,如今您正在使用。 • 一個 例子 與在線交互式應用程序,文檔和web2py官方網站的副本。 • 一個 歡迎 應用程序。 這是基本的任何其餘web2py應用程序的模板。 它被稱爲腳手架應用程序。 這也是歡迎用戶在啓動的應用程序。
被稱爲web2py即食web2py應用程序 電器 。 你能夠下載許多免費的電器 ( 電器 ] 。 web2py鼓勵用戶提交新的家電,不管是開源仍是閉源(編譯和打包)形式。
從 管理 應用程序的 網站 頁面中,您能夠執行如下操做:
• 安裝 應用程序經過完成表單頁面的右下角。 嚮應用程序提供一個名稱,選擇文件包含一個打包的應用程序或應用程序所在的URL,並單擊「提交」。
• 卸載 應用程序經過單擊相應的按鈕。 有一個確認頁面。
• 建立 一個新的應用程序,選擇一個名稱並單擊「建立」。
• 包 申請分佈經過單擊相應的按鈕。 一個包含全部的下載應用程序是一個tar文件,包括數據庫。 你不該該將此文件解壓,安裝時由web2py自動散裝的 管理 。
• 清理 應用程序的臨時文件,如會議、錯誤和緩存文件。
• 編輯 一個應用程序。
當您建立一個新的應用程序使用 管理 ,它開始做爲一個克隆的「歡迎」腳手架應用「模型/ db。 py」建立了一個SQLite數據庫,鏈接到它,實例化Auth,Crud和服務、配置它們。 它還提供了一個「控制器/違約。 py」公開行動」指數」、「下載」、「用戶」爲用戶管理、和「調用」服務。 在下面,咱們假設這些文件已經被刪除,咱們將從頭開始建立應用程序。
web2py還附帶了一個 嚮導 描述在本章後面,能夠編寫另外一個腳手架代碼基於佈局和web上可用的插件和基於高水平的描述模型。
說「你好」
在這裏,做爲一個例子,咱們建立一個簡單的web應用程序,它顯示消息「你好MyApp」給用戶。 咱們將調用這個應用程序「myapp」。 咱們還將添加一個計數器計數多少次相同的用戶訪問頁面。
您能夠建立一個新的應用程序,只需輸入它的名字的右上方 網站 頁 管理 。shell
你按下【建立】後,應用程序建立內置歡迎應用程序的副本。數據庫
運行新的應用程序,請訪問:
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」(與行動相關聯的視圖文件)和徹底替換現有的文件內容以下:
用於調試目的你能夠隨時添加
{{=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)
如今修改視圖添加一行顯示計數器的值:
櫃檯與每一個訪問者相關聯,並增長訪問者每次從新加載頁面。 不一樣的遊客看到不一樣的計數器。
說個人名字
如今建立兩頁(第一和第二),在第一頁建立一個表單,問客人的名字,和重定向到第二頁,迎接客人的名字。
寫相應的操做在默認的控制器:
def first():
return dict()
def second():
return dict()
而後建立一個視圖「默認/第一。 html「第一行動,並輸入:
{{extend 'layout.html'}}
What is your name?
並提交表單,您將收到一個祝福:
回發
表單提交以前,咱們使用的機制是很常見的,但它不是良好的編程實踐。 應驗證全部輸入,在上面的例子中,驗證的負擔將落在第二個行動。 所以,行動執行驗證不一樣於生成表單的動做。 這每每致使代碼冗餘。
表單提交的一個更好的模式是生成它們的提交形式相同的動做,在咱們的示例中「第一」。 「第一」的行動應該接收的變量,處理它們,將它們存儲的服務器端,並將用戶重定向到「第二」頁面,它檢索變量。 這種機制被稱爲 回發 。
修改默認的控制器來實現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?
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'}}
若是你點擊圖像名稱連接,你直接:
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'}}
{{for comment in comments:}}
{{=comment.author}} says {{=comment.body}}
當訪問者經過此頁面提交評論,評論存儲在數據庫和附加到頁面的底部。
添加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'}}
建立、更新和刪除照片和評論:
配置佈局
您能夠配置默認佈局經過編輯「視圖/佈局。 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',
_onkeyup="ajax('callback', ['keyword'], 'target');")),
target_div=DIV(_id='target'))
def callback():
"an ajax callback that returns a
這是「默認/ index . html」視圖的代碼:
{{extend 'layout.html'}}
這是「默認/ show.html」視圖的代碼:
{{extend 'layout.html'}}
{{=db.auth_user[comment.created_by].first_name}} on {{=comment.created_on}}
says {{=comment.body}}
這是「默認/ edit.html」視圖的代碼:
{{extend 'layout.html'}}
最後這裏的代碼視圖「默認/ search.html」:
{{extend 'layout.html'}}
你也能夠嘗試經過訪問直接調用回調的動做,例如,如下網址:
http://127.0.0.1:8000/mywiki/default/callback?keyword=wiki
若是你看你看到返回的HTML頁面來源回調:
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'}}
你獲得如下機票:
注意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)} } 顯示菜單。