欢迎回到本系列的第二部分,在这我们将用Go的Beego这个web开发框架来加速开发。如果你错过了第一部分,我建议你去读一下,因为它是这一系列的基础。 在第一部分中,我们有了一个好的开始,通过安装Beego及命令行的Bee了解并实际使用了Beego,创建一个基本的项目,添加一个控制行为,创建了一个基本的视图模板,添加一个自定义路由并以学习如何使用请求参数为结尾。 在第二部分中,我们将进入更有趣的部分,构建一个结合数据库的Web应用,使用的是Sqlite3,还要研究一下模型、表单以及验证。我希望你已经准备就绪了,下面让我们一块愉快的走到最后。 |
Garfielt
|
两步视图你会注意到manage控制器里的几个函数,代码如下: manage.Layout = "basic-layout.tpl" manage.LayoutSections = make(map[string]string) manage.LayoutSections["Header"] = "header.tpl" manage.LayoutSections["Footer"] = "footer.tpl" 这些代码做的是建立了一个两步视图布局。你可能还不熟悉这个术语,它是指你在外部一直显示布局的地方,如侧边栏,导航,header、footer以及那些基于被执行动作的可变内容。
我用上图来说明我的意思。绿色区域是在外部,封装视图和红色部分是基于执行动作内容将要改变的。 通过参考Layout和LayoutSections,我们能够指定外部布局的视图模板,basic-layout.tpl,以及其他的子模板,在我们的例子中为一个header和footer,分别为header.tpl和footer.tpl。 这样做的话,我们行为模板生成的内容将被插入到封装视图模板中,如通过指定{{.LayoutContent}},而header和footer分别为{{.Header}}和{{.Footer}}。 |
Garfielt
|
模型为添加数据库支持,我们需要做的几件事。首先,我们需要建立一些模型。模型基本上只是一些拥有额外信息的结构。下面是一个模型文件,在models/models.go中,我们将在应用的剩余部分中一直使用它。 package models type Article struct { Id int `form:"-"` Name string `form:"name,text,name:" valid:"MinSize(5);MaxSize(20)"` Client string `form:"client,text,client:"` Url string `form:"url,text,url:"` } func (a *Article) TableName() string { return "articles" } 你可以看到里面有一个模型,Article,一个简单的网站文章模型,其包含四个属性: Id, Name, Client 和 Url。你需要注意的是每个属性都有额外的数据,上面提到的form 和valid。 这是将模型用来同时处理生成和验证的一个非常简单的方法。让我们通过实际使用这四个属性解释每个的作用。 Id int `form:"-"` 在我们的数据库中,ID是一个自递增字段。当添加新记录时这个值会自动生成,当删除,更新或查找记录时需要提供这个值。所以对于form:"-",我们要说的是Id不是必需的。 Name string `form:"name,text,name:" valid:"MinSize(5);MaxSize(20)"` |
Garfielt
|
我们这里有一个稍微复杂一些的例子,让我们分解开来,以"name,text,name:"开头。它的意思是当表单被解析的时候,我们将会看到:
接下来,让我们看一下valid:"MinSize(5);MaxSize(20)"。它指定了两个校验规则:MinSize和MaxSize。效果是,该值至少有5个字符,至多不能超过20个字符。 这里有多个校验规则供你使用,包括区间(Range),Email,IP,Mobile,Base64以及电话号码。 Client string `form:"client,text,client:"` Url string `form:"url,text,url:"` 在上面的两个例子中,Client将会读取表单字段client的值,是一个文本字段,并且字段的标签是client:,Url会读取表单字段url的值,同样是一个文本字段,标签是url:。现在轮到TableName函数了。 我之所以添加它是因为表article的名字和结构体的名字不一致,叫做articles。如果两者一样,Beego的ORM会自动找到它。 但是,我在这里故意修改了名字,因为我想向你演示一下当结构体(struct)和表的名字不一致时该怎么做。现在,我们要讨论一下表的结构。它应该包括下面这些。 CREATE TABLE "articles" ( "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(200) NOT NULL, "client" varchar(100), "url" varchar(400) DEFAULT NULL, "notes" text, UNIQUE (name) ); |
中奖啦
|
在应用中整合模型
|
AndyLam
|
CRUD 操作做好这些,我们现在可以将数据库的支持集成到我们的应用程序中。让我们开始与两个简单的CRUD操作,删除和更新。这些都不使用表单,因为我想保持这一节更注重ORM代码,而不是形式和验证码。我会在后面说道这些。 删除一条记录我们试图从数据库中基于id删除一篇文章。在Inrouters/routers.go中,向你的function中添加一条: beego.Router("/manage/delete/:id([0-9]+)", &controllers.ManageController{}, "*:Delete") 然后将代码添加到controllers/manage.go,也就是: func (manage *ManageController) Delete() { // convert the string value to an int articleId, _ := strconv.Atoi(manage.Ctx.Input.Param(":id")) 在这里,我们试图取回id参数,并从String转换成int,然后使用STRCONV包中的Atoi方法就行了。这是一个简单的例子,所以我跳过这可能会引发任何错误,包括acticleId的解析错误。 o := orm.NewOrm() o.Using("default") article := models.Article{} |
似年
|
接着,我们初始化一个新的ORM实例并确认我们使用了缺省的数据库。我们可以设置任意数量的数据库连接,例如一个用于读,一个用于写等。最后,我们创建一个新的,空的,Article模型实例。 // Check if the article exists first if exist := o.QueryTable(article.TableName()).Filter("Id", articleId).Exist(); exist { if num, err := o.Delete(&models.Article{Id: articleId}); err == nil { beego.Info("Record Deleted. ", num) } else { beego.Error("Record couldn't be deleted. Reason: ", err) } } else { beego.Info("Record Doesn't exist.") } } 首先,我们查询article表,检查是否有一篇文章的Id和传入的Id参数值匹配。如果存在记录,我们调用ORM的Delete方法,传入文章的Id。 如果没有错误返回,表示文章已经删除,然后调用beego.Info,用Info方法记录删除日志。如果不能删除此记录,将调用Error方法,传入err对象,显示文章不能被删除的原因。 |
地狱星星
|
更新一条记录以上是删除一条记录,现在让我们更新一条记录;这次我将会使用flash信使。 func (manage *ManageController) Update() { o := orm.NewOrm() o.Using("default") flash := beego.NewFlash() 像以前一样,我们初始化一个ORM实例并指定默认数据库。然后我们取得一个Beego Flash对象的句柄,它可以在请求间存储信息。 // convert the string value to an int if articleId, err := strconv.Atoi(manage.Ctx.Input.Param(":id")); err == nil { article := models.Article{Id: articleId} 这次我们尝试取得一个id参数并且当它存在时初始化一个新的Article模型。 if o.Read(&article) == nil { article.Client = "Sitepoint" article.Url = "http://www.google.com" if num, err := o.Update(&article); err == nil { flash.Notice("Record Was Updated.") flash.Store(&manage.Controller) beego.Info("Record Was Updated. ", num) } 接下来我们调用Read方法,传入这个Article对象,如果有一条记录与Article.Id指定的id相匹配,它会尝试从数据库中加载此article的其他属性。 假设数据库中有这个Id对应的记录,我们在这个article对象上设置了Client和Url属性并且将它传递给了Update方法,它会在数据库中更新这个记录。 |
--zxp
|
假设没有发生错误,接下来我们调用Flash对象上的Notice函数并传入一个简单的消息,然后调用Store来持久化这个消息. } else { flash.Notice("Record Was NOT Updated.") flash.Store(&manage.Controller) beego.Error("Couldn't find article matching id: ", articleId) } } else { flash.Notice("Record Was NOT Updated.") flash.Store(&manage.Controller) beego.Error("Couldn't convert id from a string to a number. ", err) } 如果出了点错,例如不能更新记录或者我们不能将id参数转换成integer类型,我们要在flash信息和log信息中加以标记。 // redirect afterwards manage.Redirect("/manage/view", 302) } 最后,我们调用Redirect方法,传入我们要重定向的url和http状态码。这样,不论我们能否更新此记录,我们都会被重定向到/manage/view,在这里我们可以看到定义的结果。 |
--zxp
|
查看所有记录
|
--zxp
|
插入一条记录
|
--zxp
|
结尾
|
--zxp
|
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们
有疑问加站长微信联系(非本文作者)