GForms

A flexible forms validation and rendering library for golang web development. Inspired by django-forms and wtforms.

wercker status

Overview

  • Validate HTTP request
  • Rendering form-html
  • Support parsing content-type "form-urlencoded", "json"
  • Support many widgets for form field.

Getting Started

Install

go get github.com/bluele/gforms

Examples

See examples.

Usage

Define Form

userForm := gforms.DefineForm(gforms.NewFields(
  gforms.NewTextField(
    "name",
    gforms.Validators{
      gforms.Required(),
      gforms.MaxLengthValidator(32),
    },
  ),
  gforms.NewFloatField(
    "weight",
    gforms.Validators{},
  ),
))

Validate HTTP request

Server (code):

type User struct {
  Name   string  `gforms:"name"`
  Weight float32 `gforms:"weight"`
}

func main() {
  tplText := `<form method="post">
{{range $i, $field := .Fields}}
  <label>{{$field.GetName}}: </label>{{$field.Html}}
  {{range $ei, $err := $field.Errors}}<label class="error">{{$err}}</label>{{end}}<br />
{{end}}<input type="submit">
</form>
  `
  tpl := template.Must(template.New("tpl").Parse(tplText))

  userForm := gforms.DefineForm(gforms.NewFields(
    gforms.NewTextField(
      "name",
      gforms.Validators{
        gforms.Required(),
        gforms.MaxLengthValidator(32),
      },
    ),
    gforms.NewFloatField(
      "weight",
      gforms.Validators{},
    ),
  ))

  http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "text/html")
    form := userForm(r)
    if r.Method != "POST" {
      tpl.Execute(w, form)
      return
    }
    if !form.IsValid() {
      tpl.Execute(w, form)
      return
    }
    user := User{}
    form.MapTo(&user)
    fmt.Fprintf(w, "ok: %v", user)
  })
  http.ListenAndServe(":9000", nil)
}

Client:

# show html form
$ curl -X GET localhost:9000/users
<form method="post">
  <label>name: </label><input type="text" name="name" value=""></input>
  <br />

  <label>weight: </label><input type="text" name="weight" value=""></input>
  <br />
<input type="submit">
</form>

# valid request
$ curl -X POST localhost:9000/users -d 'name=bluele&weight=71.9'
ok: {bluele 71.9}

# "name" field is required.
$ curl -X POST localhost:9000/users -d 'weight=71.9'
<form method="post">
  <label>name: </label><input type="text" name="name" value=""></input>
  <label class="error">This field is required.</label><br />

  <label>weight: </label><input type="text" name="weight" value="71.9"></input>
  <br />
<input type="submit">
</form>

Define Form by Struct Model

type User struct {
  Name   string  `gforms:"name"`
  Weight float32 `gforms:"weight"`
}

func initForm() {
  userForm := gforms.DefineModelForm(User{}, gforms.NewFields(
    // override User.name field
    gforms.NewTextField(
      "name",
      gforms.Validators{
        gforms.Required(),
        gforms.MaxLengthValidator(32),
      },
    ),
  ))
  /* equal an above defined form.
  userForm := gforms.DefineForm(gforms.NewFields(
    gforms.NewTextField(
      "name",
      gforms.Validators{
        gforms.Required(),
        gforms.MaxLengthValidator(32),
      },
    ),
    gforms.NewFloatField(
      "weight",
      gforms.Validators{},
    ),
  ))
  */
}

Render HTML

FormInstance#Html

form := userForm(r)
fmt.Println(form.Html())
/* 
# Output
<input type="text" name="name"></input>
<input type="text" name="weight"></input>
*/

FieldInstance#Html

form := userForm(r)
fmt.Println(form.GetField("name").Html())
/* 
# Output
<input type="text" name="name"></input>
*/

Parse request data

(Default) Parse *http.Request to create a new FormInstance.

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  form := userForm(r)  
  ...
}

Parse net/url.Values to create a new FormInstance.

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  // parse querystring values.
  form := userForm.FromUrlValues(r.URL.Query())
  ...
}

Customize Formfield attributes

customForm := gforms.DefineForm(gforms.NewFields(
  gforms.NewTextField(
    "name",
    gforms.Validators{
      gforms.Required(),
    },
    gforms.TextInputWidget(
      map[string]string{
        "class": "custom",
      },
    )),
))

form := customForm(r)
fmt.Println(form.Html())
/* 
# Output
<input type="text" name="name" value="" class="custom"></input>
*/

Custom Validation error message

userForm := gforms.DefineForm(gforms.NewFields(
  gforms.NewTextField(
    "name",
    gforms.Validators{
      gforms.Required("Custom error required message."),
      gforms.MaxLengthValidator(32, "Custom error maxlength message."),
    },
  ),
))

Support Fields

TextField

It maps value to FormInstance.CleanedData as type string.

gforms.NewTextField(
  "text",
  gforms.Validators{},
)

BooleanField

It maps value to FormInstance.CleanedData as type bool.

gforms.NewBooleanField(
  "checked",
  gforms.Validators{},
)

IntegerField

It maps value to FormInstance.CleanedData as type int.

gforms.NewIntegerField(
  "number",
  gforms.Validators{},
)

FloatField

It maps value to FormInstance.CleanedData as type float32 or float64.

gforms.NewFloatField(
  "floatNumber",
  gforms.Validators{},
)

MultipleTextField

It maps value to FormInstance.CleanedData as type []string.

gforms.NewMultipleTextField(
  "texts",
  gforms.Validators{},
)

DateTimeField

It maps value to FormInstance.CleanedData as type time.Time.

gforms.NewDateTimeField(
  "date", 
  DefaultDateTimeFormat, 
  gforms.Validators{},  
)

Support Validators

Required validator

Added an error msg to FormInstance.Errors() if the field is not provided.

gforms.Validators{
  gforms.Required(),
},

Regexp validator

Added an error msg to FormInstance.Errors() if the regexp doesn't matched a value.

gforms.Validators{
  gforms.RegexpValidator(`number-\d+`),
},

Email validator

Added an error msg to FormInstance.Errors() if a value doesn't looks like an email address.

gforms.Validators{
  gforms.EmailValidator(),
},

URL Validator

Added an error msg to FormInstance.Errors() if a value doesn't looks like an url.

gforms.Validators{
  gforms.URLValidator(),
},

MinLength Validator

Added an error msg to FormInstance.Errors() if the length of value is less than specified first argument.

gforms.Validators{
  gforms.MinLengthValidator(16),
},

MaxLength Validator

Added an error msg to FormInstance.Errors() if the length of value is greater than specified first argument.

gforms.Validators{
  gforms.MaxLengthValidator(256),
},

MinValueValidator

Added an error msg to FormInstance.Errors() if value is less than specified first argument.

gforms.Validators{
  gforms.MinValueValidator(16),
},

MaxValueValidator

Added an error msg to FormInstance.Errors() if value is greater than specified first argument.

gforms.Validators{
  gforms.MaxValueValidator(256),
},

Support Widgets

SelectWidget

Form := gforms.DefineForm(gforms.NewFields(
  gforms.NewTextField(
    "gender",
    gforms.Validators{
      gforms.Required(),
    },
    gforms.SelectWidget(
      map[string]string{
        "class": "custom",
      },
      func() gforms.SelectOptions {
        return gforms.StringSelectOptions([][]string{
          {"Men", "0"},
          {"Women", "1"},
        })
      },
    ),
  ),
))

form = Form()
fmt.Println(form.Html())
/*
# output
<select class="custom">
<option value="0">Men</option>
<option value="1">Women</option>
</select>
*/

RadioSelectWidget

Form := gforms.DefineForm(gforms.NewFields(
    gforms.NewTextField(
      "lang",
      gforms.Validators{
        gforms.Required(),
      },
      gforms.RadioSelectWidget(
        map[string]string{
          "class": "custom",
        },
        func() gforms.RadioOptions {
          return gforms.StringRadioOptions([][]string{
            {"Golang", "0", "false", "false"},
            {"Python", "1", "false", "true"},
          })
        },
      ),
    ),  
))

form = Form()
fmt.Println(form.Html())
/*
# output
<input type="radio" name="lang" value="0">Golang
<input type="radio" name="lang" value="1" disabled>Python
*/

CheckboxMultipleWidget

Form := gforms.DefineForm(gforms.NewFields(
    gforms.NewMultipleTextField(
      "lang",
      gforms.Validators{
        gforms.Required(),
      },
      gforms.CheckboxMultipleWidget(
        map[string]string{
          "class": "custom",
        },
        func() gforms.CheckboxOptions {
          return gforms.StringCheckboxOptions([][]string{
            {"Golang", "0", "false", "false"},
            {"Python", "1", "false", "true"},
          })
        },
      ),
    ),
))

form := Form()
fmt.Println(form.Html())
/*
# output
<input type="checkbox" name="lang" value="0">Golang
<input type="checkbox" name="lang" value="1" disabled>Python
*/

TODO

  • Support FileField, DateField, DateTimeField
  • Writing more godoc and unit tests.
  • Improve performance.

Author

Jun Kimura



GForms

golang Web开发的灵活的表单验证和渲染库。 灵感来源于 django-forms

wercker状态

概述

  • 验证HTTP请求
  • 呈现form-html
  • 支持解析内容类型form-urlencoded,json
  • 支持表单字段的许多小部件。

Getting Started

安装

go get github.com/bluele/gforms

示例

请参见示例

用法

定义表单

userForm := gforms.DefineForm(gforms.NewFields(
  gforms.NewTextField(
    "name",
    gforms.Validators{
      gforms.Required(),
      gforms.MaxLengthValidator(32),
    },
  ),
  gforms.NewFloatField(
    "weight",
    gforms.Validators{},
  ),
))

验证HTTP请求

服务器(代码):

type User struct {
  Name   string  </span>gforms:&#34;name&#34;<span class="pl-pds">
  Weight float32 </span>gforms:&#34;weight&#34;<span class="pl-pds">
}

func main() { tplText := </span>&lt;form method=&#34;post&#34;&gt;</span> <span class="pl-s">{{range $i, $field := .Fields}}</span> <span class="pl-s"> &lt;label&gt;{{$field.GetName}}: &lt;/label&gt;{{$field.Html}}</span> <span class="pl-s"> {{range $ei, $err := $field.Errors}}&lt;label class=&#34;error&#34;&gt;{{$err}}&lt;/label&gt;{{end}}&lt;br /&gt;</span> <span class="pl-s">{{end}}&lt;input type=&#34;submit&#34;&gt;</span> <span class="pl-s">&lt;/form&gt;</span> <span class="pl-s"> <span class="pl-pds"> tpl := template.Must(template.New("tpl").Parse(tplText))

userForm := gforms.DefineForm(gforms.NewFields( gforms.NewTextField( "name", gforms.Validators{ gforms.Required(), gforms.MaxLengthValidator(32), }, ), gforms.NewFloatField( "weight", gforms.Validators{}, ), ))

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html") form := userForm® if r.Method != "POST" { tpl.Execute(w, form) return } if !form.IsValid() { tpl.Execute(w, form) return } user := User{} form.MapTo(&user) fmt.Fprintf(w, "ok: %v", user) }) http.ListenAndServe(":9000", nil) }

客户端:

# show html form
$ curl -X GET localhost:9000/users
<form method="post">
  <label>name: </label><input type="text" name="name" value=""></input>
  <br />

<label>weight: </label><input type="text" name="weight" value=""></input> <br /> <input type="submit"> </form>

valid request

$ curl -X POST localhost:9000/users -d 'name=bluele&weight=71.9' ok: {bluele 71.9}

"name" field is required.

$ curl -X POST localhost:9000/users -d 'weight=71.9' <form method="post"> <label>name: </label><input type="text" name="name" value=""></input> <label class="error">This field is required.</label><br />

<label>weight: </label><input type="text" name="weight" value="71.9"></input> <br /> <input type="submit"> </form>

通过Struct Model定义表单

type User struct {
  Name   string  </span>gforms:&#34;name&#34;<span class="pl-pds">
  Weight float32 </span>gforms:&#34;weight&#34;<span class="pl-pds">
}

func initForm() { userForm := gforms.DefineModelForm(User{}, gforms.NewFields( // override User.name field gforms.NewTextField( "name", gforms.Validators{ gforms.Required(), gforms.MaxLengthValidator(32), }, ), )) / equal an above defined form. userForm := gforms.DefineForm(gforms.NewFields( gforms.NewTextField( "name", gforms.Validators{ gforms.Required(), gforms.MaxLengthValidator(32), }, ), gforms.NewFloatField( "weight", gforms.Validators{}, ), )) / }

渲染HTML

FormInstance#Html

form := userForm®
fmt.Println(form.Html())
/ 
# Output
<input type="text" name="name"></input>
<input type="text" name="weight"></input>
/

FieldInstance#Html

form := userForm®
fmt.Println(form.GetField("name").Html())
/*

Output

<input type="text" name="name"></input> */

解析请求数据

(默认)解析 * http.Request 来创建一个新的 FormInstance

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  form := userForm®
… }

解析 net / url.Values 来创建一个新的 FormInstance

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  // parse querystring values.
  form := userForm.FromUrlValues(r.URL.Query())
  …
}

自定义Formfield属性

customForm := gforms.DefineForm(gforms.NewFields(
  gforms.NewTextField(
    "name",
    gforms.Validators{
      gforms.Required(),
    },
    gforms.TextInputWidget(
      map[string]string{
        "class": "custom",
      },
    )),
))

form := customForm® fmt.Println(form.Html()) / # Output <input type="text" name="name" value="" class="custom"></input> /

自定义验证错误消息

userForm := gforms.DefineForm(gforms.NewFields(
  gforms.NewTextField(
    "name",
    gforms.Validators{
      gforms.Required("Custom error required message."),
      gforms.MaxLengthValidator(32, "Custom error maxlength message."),
    },
  ),
))

支持字段

TextField

它将值映射到FormInstance.CleanedData作为类型 string

gforms.NewTextField(
  "text",
  gforms.Validators{},
)

BooleanField

它将值映射到FormInstance.CleanedData作为类型 bool

gforms.NewBooleanField(
  "checked",
  gforms.Validators{},
)

整数字段

它将值映射到FormInstance.CleanedData作为类型 int

gforms.NewIntegerField(
  "number",
  gforms.Validators{},
)

FloatField

它将值映射到FormInstance.CleanedData作为类型 float32 float64

gforms.NewFloatField(
  "floatNumber",
  gforms.Validators{},
)

MultipleTextField

它将值映射为FormInstance.CleanedData作为类型 [] string

gforms.NewMultipleTextField(
  "texts",
  gforms.Validators{},
)

DateTimeField

它将值映射到FormInstance.CleanedData作为类型 time.Time

gforms.NewDateTimeField(
  "date",
  DefaultDateTimeFormat,
  gforms.Validators{},
)

支持验证器

必需的验证器

如果未提供该字段,则向FormInstance.Errors()添加错误消息。

gforms.Validators{
  gforms.Required(),
},

正则表达式验证器

如果正则表达式不匹配值,则向FormInstance.Errors()添加错误消息。

gforms.Validators{
  gforms.RegexpValidator(</span>number-\d+<span class="pl-pds">),
},

电子邮件验证器

如果值不像电子邮件地址,则向FormInstance.Errors()添加错误消息。

gforms.Validators{
  gforms.EmailValidator(),
},

URL验证器

如果值不像网址,则向FormInstance.Errors()添加错误消息。

gforms.Validators{
  gforms.URLValidator(),
},

MinLength Validator

如果值的长度小于指定的第一个参数,则会向FormInstance.Errors()添加错误消息。

gforms.Validators{
  gforms.MinLengthValidator(16),
},

MaxLength Validator

如果值的长度大于指定的第一个参数,则向FormInstance.Errors()添加错误消息。

gforms.Validators{
  gforms.MaxLengthValidator(256),
},

MinValueValidator

如果值小于指定的第一个参数,则向FormInstance.Errors()添加错误消息。

gforms.Validators{
  gforms.MinValueValidator(16),
},

MaxValueValidator

如果值大于指定的第一个参数,则向FormInstance.Errors()添加错误消息。

gforms.Validators{
  gforms.MaxValueValidator(256),
},

支持小部件

SelectWidget

Form := gforms.DefineForm(gforms.NewFields(
  gforms.NewTextField(
    "gender",
    gforms.Validators{
      gforms.Required(),
    },
    gforms.SelectWidget(
      map[string]string{
        "class": "custom",
      },
      func() gforms.SelectOptions {
        return gforms.StringSelectOptions([][]string{
          {"Men", "0"},
          {"Women", "1"},
        })
      },
    ),
  ),
))

form = Form() fmt.Println(form.Html()) / # output <select class="custom"> <option value="0">Men</option> <option value="1">Women</option> </select> /

RadioSelectWidget

Form := gforms.DefineForm(gforms.NewFields(
    gforms.NewTextField(
      "lang",
      gforms.Validators{
        gforms.Required(),
      },
      gforms.RadioSelectWidget(
        map[string]string{
          "class": "custom",
        },
        func() gforms.RadioOptions {
          return gforms.StringRadioOptions([][]string{
            {"Golang", "0", "false", "false"},
            {"Python", "1", "false", "true"},
          })
        },
      ),
    ),
))

form = Form() fmt.Println(form.Html()) / # output <input type="radio" name="lang" value="0">Golang <input type="radio" name="lang" value="1" disabled>Python /

CheckboxMultipleWidget

Form := gforms.DefineForm(gforms.NewFields(
    gforms.NewMultipleTextField(
      "lang",
      gforms.Validators{
        gforms.Required(),
      },
      gforms.CheckboxMultipleWidget(
        map[string]string{
          "class": "custom",
        },
        func() gforms.CheckboxOptions {
          return gforms.StringCheckboxOptions([][]string{
            {"Golang", "0", "false", "false"},
            {"Python", "1", "false", "true"},
          })
        },
      ),
    ),
))

form := Form() fmt.Println(form.Html()) / # output <input type="checkbox" name="lang" value="0">Golang <input type="checkbox" name="lang" value="1" disabled>Python /

TODO

  • 支持FileField,DateField,DateTimeField
  • 编写更多的godoc和单元测试。
  • 提高成效。

Author

木村俊俊




相关问题推荐