最近写一个博客练手,文章功能需要增加一个标签的功能,一篇文章可以有多个标签,一个标签可以被多个文章使用,于是就想用m2m模型实现,过程如下
文章模型简化如下:
type Article struct {
Id int `form:"-"`
//这个是标签
Label []*Label `orm:"rel(m2m);rel_through(blog/models.Articlelabel)"`
}
这里说一下这个rel_through, 官方文档的说法是pkg.models.struct
用点儿连接,但是实际情况不是路径还是要用/
不知道是不是我对官方文档理解有问题,还是官方的说法有瑕疵
下面是标签模型:
type Label struct {
Id int `form:"-"`
Title string `form:"title"`
//这个是文章关联
Article []*Article `orm:"reverse(many)"`
}
下面是关联模型
type Articlelabel struct {
Id int
Article *Article `orm:"rel(fk)"`
Label *Label `orm:"rel(fk)"`
}
注意关联模型中的 Article
和Label
都不能加id
查询会自动加上
我的列表查询如下
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
}
//这个是正确的写法
/*for k,_ := range list {
o.LoadRelated(&list[k], "Label")
}*/
//这个是错误的写法
for _, v := range list {
o.LoadRelated(v, "Label")
}
return list, nil
}
然后就报错了
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 cannot use non-ptr model struct `blog/models.Article`
...
Article
结构体空指针,于是我查阅了文档,发现 LoadRelated
参数都是指针, 下面是文档给的例子
// 载入相应的 Tags
post := Post{Id: 1}
err := o.Read(&post)
num, err := o.LoadRelated(&post, "Tags")
于是我把我的代码也换成了指针o.LoadRelated(&v, "Label")
,发现不报错了,但是也没有查询到。这就奇怪了。于是我想到是不是&v 并不是真的指向了原来的结构体,经过谷歌之后发现还真是这样,for循环的时候 &v
指向的其实是 v
的地址,而不像PHP一样就是原来的参数引用。那就只能用 list[k]
来更改了
于是
for k,_ := range list {
o.LoadRelated(&list[k], "Label")
}
这样就成了,对于查询一条记录同理,只不过不需要循环我的list, 而是直接像官方文档给的例子那样写就可以了
事后我测试
a := [] int {1}
for k,v := range a {
fmt.Println(&v)
fmt.Println(&a[k])
}
//两个不同的地址
//0x40e024
//0x40e020
看来我还是基础不过关啊,共勉