diff --git a/utils/pagination/controller.go b/utils/pagination/controller.go
new file mode 100644
index 00000000..28473f8a
--- /dev/null
+++ b/utils/pagination/controller.go
@@ -0,0 +1,26 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package pagination
+
+import (
+ "github.com/astaxie/beego/context"
+)
+
+// Instantiates a Paginator and assigns it to context.Input.Data["paginator"].
+func SetPaginator(context *context.Context, per int, nums int64) (paginator *Paginator) {
+ paginator = NewPaginator(context.Request, per, nums)
+ context.Input.Data["paginator"] = paginator
+ return
+}
diff --git a/utils/pagination/doc.go b/utils/pagination/doc.go
new file mode 100644
index 00000000..df0fa3b7
--- /dev/null
+++ b/utils/pagination/doc.go
@@ -0,0 +1,59 @@
+/*
+
+The pagination package provides utilities to setup a paginator within the
+context of a http request.
+
+Usage
+
+In your beego.Controller:
+
+ package controllers
+
+ import "github.com/astaxie/beego/utils/pagination"
+
+ type PostsController struct {
+ beego.Controller
+ }
+
+ func (this *PostsController) ListAllPosts() {
+ // sets this.Data["paginator"] with the current offset (from the url query param)
+ postsPerPage := 20
+ paginator := pagination.SetPaginator(this.Ctx, postsPerPage, CountPosts())
+
+ // fetch the next 20 posts
+ this.Data["posts"] = ListPostsByOffsetAndLimit(paginator.Offset(), postsPerPage)
+ }
+
+
+In your view templates:
+
+ {{if .paginator.HasPages}}
+
+ {{end}}
+
+See also
+
+http://beego.me/docs/mvc/view/page.md
+
+*/
+package pagination
diff --git a/utils/pagination/paginator.go b/utils/pagination/paginator.go
new file mode 100644
index 00000000..f89e878e
--- /dev/null
+++ b/utils/pagination/paginator.go
@@ -0,0 +1,189 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package pagination
+
+import (
+ "math"
+ "net/http"
+ "net/url"
+ "strconv"
+)
+
+// Paginator within the state of a http request.
+type Paginator struct {
+ Request *http.Request
+ PerPageNums int
+ MaxPages int
+
+ nums int64
+ pageRange []int
+ pageNums int
+ page int
+}
+
+// Returns the total number of pages.
+func (p *Paginator) PageNums() int {
+ if p.pageNums != 0 {
+ return p.pageNums
+ }
+ pageNums := math.Ceil(float64(p.nums) / float64(p.PerPageNums))
+ if p.MaxPages > 0 {
+ pageNums = math.Min(pageNums, float64(p.MaxPages))
+ }
+ p.pageNums = int(pageNums)
+ return p.pageNums
+}
+
+// Returns the total number of items (e.g. from doing SQL count).
+func (p *Paginator) Nums() int64 {
+ return p.nums
+}
+
+// Sets the total number of items.
+func (p *Paginator) SetNums(nums interface{}) {
+ p.nums, _ = ToInt64(nums)
+}
+
+// Returns the current page.
+func (p *Paginator) Page() int {
+ if p.page != 0 {
+ return p.page
+ }
+ if p.Request.Form == nil {
+ p.Request.ParseForm()
+ }
+ p.page, _ = strconv.Atoi(p.Request.Form.Get("p"))
+ if p.page > p.PageNums() {
+ p.page = p.PageNums()
+ }
+ if p.page <= 0 {
+ p.page = 1
+ }
+ return p.page
+}
+
+// Returns a list of all pages.
+//
+// Usage (in a view template):
+//
+// {{range $index, $page := .paginator.Pages}}
+//
+// {{$page}}
+//
+// {{end}}
+func (p *Paginator) Pages() []int {
+ if p.pageRange == nil && p.nums > 0 {
+ var pages []int
+ pageNums := p.PageNums()
+ page := p.Page()
+ switch {
+ case page >= pageNums-4 && pageNums > 9:
+ start := pageNums - 9 + 1
+ pages = make([]int, 9)
+ for i, _ := range pages {
+ pages[i] = start + i
+ }
+ case page >= 5 && pageNums > 9:
+ start := page - 5 + 1
+ pages = make([]int, int(math.Min(9, float64(page+4+1))))
+ for i, _ := range pages {
+ pages[i] = start + i
+ }
+ default:
+ pages = make([]int, int(math.Min(9, float64(pageNums))))
+ for i, _ := range pages {
+ pages[i] = i + 1
+ }
+ }
+ p.pageRange = pages
+ }
+ return p.pageRange
+}
+
+// Returns URL for a given page index.
+func (p *Paginator) PageLink(page int) string {
+ link, _ := url.ParseRequestURI(p.Request.RequestURI)
+ values := link.Query()
+ if page == 1 {
+ values.Del("p")
+ } else {
+ values.Set("p", strconv.Itoa(page))
+ }
+ link.RawQuery = values.Encode()
+ return link.String()
+}
+
+// Returns URL to the previous page.
+func (p *Paginator) PageLinkPrev() (link string) {
+ if p.HasPrev() {
+ link = p.PageLink(p.Page() - 1)
+ }
+ return
+}
+
+// Returns URL to the next page.
+func (p *Paginator) PageLinkNext() (link string) {
+ if p.HasNext() {
+ link = p.PageLink(p.Page() + 1)
+ }
+ return
+}
+
+// Returns URL to the first page.
+func (p *Paginator) PageLinkFirst() (link string) {
+ return p.PageLink(1)
+}
+
+// Returns URL to the last page.
+func (p *Paginator) PageLinkLast() (link string) {
+ return p.PageLink(p.PageNums())
+}
+
+// Returns true if the current page has a predecessor.
+func (p *Paginator) HasPrev() bool {
+ return p.Page() > 1
+}
+
+// Returns true if the current page has a successor.
+func (p *Paginator) HasNext() bool {
+ return p.Page() < p.PageNums()
+}
+
+// Returns true if the given page index points to the current page.
+func (p *Paginator) IsActive(page int) bool {
+ return p.Page() == page
+}
+
+// Returns the current offset.
+func (p *Paginator) Offset() int {
+ return (p.Page() - 1) * p.PerPageNums
+}
+
+// Returns true if there is more than one page.
+func (p *Paginator) HasPages() bool {
+ return p.PageNums() > 1
+}
+
+// Instantiates a paginator struct for the current http request.
+func NewPaginator(req *http.Request, per int, nums interface{}) *Paginator {
+ p := Paginator{}
+ p.Request = req
+ if per <= 0 {
+ per = 10
+ }
+ p.PerPageNums = per
+ p.SetNums(nums)
+ return &p
+}
diff --git a/utils/pagination/utils.go b/utils/pagination/utils.go
new file mode 100644
index 00000000..5932647d
--- /dev/null
+++ b/utils/pagination/utils.go
@@ -0,0 +1,34 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package pagination
+
+import (
+ "fmt"
+ "reflect"
+)
+
+// convert any numeric value to int64
+func ToInt64(value interface{}) (d int64, err error) {
+ val := reflect.ValueOf(value)
+ switch value.(type) {
+ case int, int8, int16, int32, int64:
+ d = val.Int()
+ case uint, uint8, uint16, uint32, uint64:
+ d = int64(val.Uint())
+ default:
+ err = fmt.Errorf("ToInt64 need numeric not `%T`", value)
+ }
+ return
+}