最近寫一個(gè)博客練手,文章功能需要增加一個(gè)標(biāo)簽的功能,一篇文章可以有多個(gè)標(biāo)簽,一個(gè)標(biāo)簽可以被多個(gè)文章使用,于是就想用m2m模型實(shí)現(xiàn),過程如下
文章模型簡(jiǎn)化如下:
type Article struct {
Id int `form:"-"`
//這個(gè)是標(biāo)簽
Label []*Label `orm:"rel(m2m);rel_through(blog/models.Articlelabel)"`
}
這里說一下這個(gè)rel_through, 官方文檔的說法是pkg.models.struct 用點(diǎn)兒連接,但是實(shí)際情況不是路徑還是要用/ 不知道是不是我對(duì)官方文檔理解有問題,還是官方的說法有瑕疵
下面是標(biāo)簽?zāi)P停?/p>
type Label struct {
Id int `form:"-"`
Title string `form:"title"`
//這個(gè)是文章關(guān)聯(lián)
Article []*Article `orm:"reverse(many)"`
}
下面是關(guān)聯(lián)模型
type Articlelabel struct {
Id int
Article *Article `orm:"rel(fk)"`
Label *Label `orm:"rel(fk)"`
}
注意關(guān)聯(lián)模型中的 Article和Label 都不能加id 查詢會(huì)自動(dòng)加上
我的列表查詢?nèi)缦?/p>
func ArtList() ([]Article, error) {
var list []Article
o := orm.NewOrm()
orm.Debug = true
_, err := o.QueryTable("article").RelatedSel().Limit(10).All(&list)
if err != nil {
return []Article{}, err
}
//這個(gè)是正確的寫法
/*for k,_ := range list {
o.LoadRelated(&list[k], "Label")
}*/
//這個(gè)是錯(cuò)誤的寫法
for _, v := range list {
o.LoadRelated(v, "Label")
}
return list, nil
}
然后就報(bào)錯(cuò)了
2020/03/01 18:54:29.795 [C] [panic.go:679] the request url is /admin/article
2020/03/01 18:54:29.795 [C] [panic.go:679] Handler crashed with error <Ormer> cannot use non-ptr model struct `blog/models.Article`
...
Article 結(jié)構(gòu)體空指針,于是我查閱了文檔,發(fā)現(xiàn) LoadRelated參數(shù)都是指針, 下面是文檔給的例子
// 載入相應(yīng)的 Tags
post := Post{Id: 1}
err := o.Read(&post)
num, err := o.LoadRelated(&post, "Tags")
于是我把我的代碼也換成了指針o.LoadRelated(&v, "Label"),發(fā)現(xiàn)不報(bào)錯(cuò)了,但是也沒有查詢到。這就奇怪了。于是我想到是不是&v 并不是真的指向了原來的結(jié)構(gòu)體,經(jīng)過谷歌之后發(fā)現(xiàn)還真是這樣,for循環(huán)的時(shí)候 &v指向的其實(shí)是 v的地址,而不像PHP一樣就是原來的參數(shù)引用。那就只能用 list[k]來更改了
于是
for k,_ := range list {
o.LoadRelated(&list[k], "Label")
}
這樣就成了,對(duì)于查詢一條記錄同理,只不過不需要循環(huán)我的list, 而是直接像官方文檔給的例子那樣寫就可以了
事后我測(cè)試
a := [] int {1}
for k,v := range a {
fmt.Println(&v)
fmt.Println(&a[k])
}
//兩個(gè)不同的地址
//0x40e024
//0x40e020
看來我還是基礎(chǔ)不過關(guān)啊,共勉