Instantly create a beautiful, cross platform, configurable Admin Interface and API for managing your data in minutes.
For security issues, please send us an email to security@getqor.com and give us time to respond BEFORE posting as an issue or reporting on public forums.
- Generate Admin Interface for managing data
- RESTFul JSON API
- Association handling
- Search and filtering
- Actions/Batch Actions
- Authentication and Authorization
- Extendability
package main
import (
"fmt""net/http""github.com/jinzhu/gorm"
_ "github.com/mattn/go-sqlite3""github.com/qor/admin"
)
// Create a GORM-backend modeltypeUserstruct {
gorm.ModelNamestring
}
// Create another GORM-backend modeltypeProductstruct {
gorm.ModelNamestringDescriptionstring
}
funcmain() {
DB, _:=gorm.Open("sqlite3", "demo.db")
DB.AutoMigrate(&User{}, &Product{})
// InitializeAdmin:=admin.New(&admin.AdminConfig{DB: DB})
// Allow to use Admin to manage User, ProductAdmin.AddResource(&User{})
Admin.AddResource(&Product{})
// initialize an HTTP request multiplexermux:=http.NewServeMux()
// Mount admin interface to muxAdmin.MountTo("/admin", mux)
fmt.Println("Listening on: 9000")
http.ListenAndServe(":9000", mux)
}go run main.go and visit localhost:9000/admin to see the result!
Suppose we have 2 models Factory and Item. Factory has many Items.
In the struct, you need add a field resource.CompositePrimaryKeyField to the "many" side, which is Item here.
typeFactorystruct {
gorm.ModelNamestring
publish2.VersionItems []Item`gorm:"many2many:factory_items;association_autoupdate:false"`ItemsSorter sorting.SortableCollection
}
typeItemstruct {
gorm.ModelNamestring
publish2.Version// github.com/qor/qor/resource
resource.CompositePrimaryKeyField// Required
}Then define a remote resource selector. You need configure the ID meta like below to make it support composite primary key, this is mandatory.
funcgenerateRemoteItemSelector(adm*admin.Admin) (res*admin.Resource) {
res=adm.AddResource(&Item{}, &admin.Config{Name: "ItemSelector"})
res.IndexAttrs("ID", "Name")
// Required. Convert single ID into composite primary keyres.Meta(&admin.Meta{
Name: "ID",
Valuer: func(valueinterface{}, ctx*qor.Context) interface{} {
ifr, ok:=value.(*Item); ok {
// github.com/qor/qor/resourcereturnresource.GenCompositePrimaryKey(r.ID, r.GetVersionName())
}
return""
},
})
returnres
}Last, use it in the Factory resource.
itemSelector:=generateRemoteItemSelector(adm)
factoryRes.Meta(&admin.Meta{
Name: "Items",
Config: &admin.SelectManyConfig{
RemoteDataResource: itemSelector,
},
})Suppose we have 2 models. Factory and Manager. Factory has one Manager.
First, In the struct, you need add a field resource.CompositePrimaryKeyField to the "one" side, which is Manager here.
typeFactorystruct {
gorm.ModelNamestring
publish2.VersionManagerIDuintManagerVersionNamestring// Required. in "xxxVersionName" format.ManagerManager
}
typeManagerstruct {
gorm.ModelNamestring
publish2.Version// github.com/qor/qor/resource
resource.CompositePrimaryKeyField// Required
}Then define a remote resource selector. You need configure the ID meta like below to make it support composite primary key, this is mandatory.
funcgenerateRemoteManagerSelector(adm*admin.Admin) (res*admin.Resource) {
res=adm.AddResource(&Manager{}, &admin.Config{Name: "ManagerSelector"})
res.IndexAttrs("ID", "Name")
// Required. Convert single ID into composite primary keyres.Meta(&admin.Meta{
Name: "ID",
Valuer: func(valueinterface{}, ctx*qor.Context) interface{} {
ifr, ok:=value.(*Manager); ok {
// github.com/qor/qor/resourcereturnresource.GenCompositePrimaryKey(r.ID, r.GetVersionName())
}
return""
},
})
returnres
}
Last, useitintheFactoryresource.
```gomanagerSelector:=generateRemoteManagerSelector(adm)
factoryRes.Meta(&admin.Meta{
Name: "Manager",
Config: &admin.SelectOneConfig{
RemoteDataResource: managerSelector,
},
})If you need to overwrite Collection. you have to pass composite primary key as the first element of the returning array instead of ID.
factoryRes.Meta(&admin.Meta{
Name: "Items",
Config: &admin.SelectManyConfig{
Collection: func(valueinterface{}, ctx*qor.Context) (results [][]string) {
ifc, ok:=value.(*Factory); ok {
varitems []Itemctx.GetDB().Model(c).Related(&items, "Items")
for_, p:=rangeitems {
// The first element must be the composite primary key instead of IDresults=append(results, []string{resource.GenCompositePrimaryKey(p.ID, p.GetVersionName()), p.Name})
}
}
return
},
RemoteDataResource: itemSelector,
},
})If you want to assign associations when creating a new version of object immediately. You need to define a function called AssignVersionName to the versioned struct with pointer receiver which should contains the generating new version name's logic and assign the new version name to the object.
e.g.
func (fac*Factory) AssignVersionName(db*gorm.DB) {
varcountintname:=time.Now().Format("2006-01-02")
iferr:=db.Model(&CollectionWithVersion{}).Where("id = ? AND version_name like ?", fac.ID, name+"%").Count(&count).Error; err!=nil {
panic(err)
}
fac.VersionName=fmt.Sprintf("%s-v%v", name, count+1)
}- Live Demo http://demo.getqor.com/admin
- Source Code of Live Demo https://github.com/qor/qor-example
To print all registered routes
// adm is a QOR admin instanceadm.GetRouter().PrintRoutes()QOR was developed before go mod was introduced. So it still support go path while finding its template files. The priority is
- check vendor, if not found
- check $GOPATH/pkg/mod/github.com/qor/admin@v0.x/views. the version would be detected automatically by your go.mod file, if still not found
- load view path from $GOPATH/src/github.com/qor/admin/views
So if you want to use the template under the pkg/mod, make sure $GOPATH/src/github.com/qor/admin is absent.
Released under the MIT License.