13.5. 总结和任务 之 『任务一』

主要内容:文章的分类设置; 用户创建编辑文章的时候可以选择分类、文章列表页以及详情页可以显示文章分类

【课程地址】

【主要步骤】

  • 如何让文章详情页显示文章分类?

    • 文章与分类的关联;在Article的模型里面,增加Category字段,类似用户,都是一个文章对应一个用户和一个分类

    • 文章详情页是读取的Article模型里面的Get()方法,同时我们要采用GORMPreload()进行关联,这样在读取某篇文章信息的时候,也会带上分类;

    • 文章详情页;找到 _article_meta.gohtml 视图,增加分类,直接读取.Category.Name

  • 如何让用户个人文章列表页,每个文章都显示分类?

    • 用户的文章列表页是 User控制器的Show 方法,定位到这个方法里面,找到 article模型的GetByUserID()调用

    • GetByUserID()方法里面也是需要采用GORMPreload()进行关联,这样在读取多篇文章信息的时候,也会带上分类;

  • 如何让创建文章的时候可以选择分类?

    • 控制器:获取变量; articles控制器中的Create()方法,需要增加全部分类列表的获取,并且变量categories追加到视图中

    • 视图:渲染变量;_form_field.gohtml视图中,增加分类的下拉选择框select,利用range循环渲染categories

    • 控制器:保存数据;articles控制器中的Store()方法,接收字段category_id, 一并存入进去即可

  • 如何让编辑文章的时候可以选择分类?

    • 控制器:获取变量;articles控制器中的Edit()方法,需要增加全部分类列表的获取,并且变量categories追加到视图中

    • 视图:渲染变量;_form_field.gohtml视图中,采用if eq进行判断当前分类id等于文章id的时候,增加selected,这样在编辑的时候就是选中状态了

    • 控制器;更新数据;articles控制器中的Update方法

1. Article模型 【app/models/article/article.go


// Article 文章模型

type Article struct {

   // 加载基类
   models.BaseModel
   Title string `gorm:"type:varchar(255);not null;" valid:"title"`
   Body  string `gorm:"type:longtext;not null;" valid:"body"`
   // 关联用户
   UserID uint64 `gorm:"not null;index"`
   User   user.User
   // 关联分类
   CategoryID uint64 `gorm:"not null;default:3;index"`
   // 新增下面这一行
   Category   category.Category

}

2、Article模型的CRUD操作【app/models/article/crud.go

  • 采用GORMPreload()进行关联

// Get 通过ID获取文章

func Get(idstr string) (Article, error) {
   var article Article
   id := types.StringToUint64(idstr)
    // 增加 Preload("Category")
   if err := model.DB.Debug().Preload("User").Preload("Category").First(&article, id).Error; err != nil {
      return article, err
   }
   return article, nil

}

3、视图 【resources/views/articles/_article_meta.gohtml

  • 增加分类一行
{{define "article-meta"}}
  <p class="blog-post-meta text-secondary">
    发布于 <a href="{{ .Link }}" class="font-weight-bold">{{ .CreatedAtDate }}</a>
    by <a href="{{ .User.Link }}" class="font-weight-bold">{{ .User.Name }}</a>
    分类 <a href="{{ .Category.Link }}" class="font-weight-bold">{{ .Category.Name }}</a>
  </p>
{{ end }}

4、视图 【resources/views/articles/_form_field.gohtml

  • 文章新增和编辑的时候分类的选择

 ...


  <div class="form-group mt-3">
    <label for="category">分类 </label>
{{ if .Categories }}
  <select class="form-control" name="category_id">
      {{ range $key, $category := .Categories }}
          <option value="{{ $category.ID }}"  {{if  eq $category.ID $.Article.CategoryID }} selected {{end}} >{{ $category.Name }} </option>
      {{ end }}
  </select>
{{ end }}
  </div>


...

5、控制器 【app/http/controllers/articles_controller.go

  • Create() 方法渲染视图的时候追加 categories

...
// 读取分类 
categories , _:= category.All()

view.Render(w, view.D{
   "Categories" : categories,
}, "articles.create", "articles._form_field")
...
  • Store() 方法保存数据

...
_article := article.Article{
   Title: r.PostFormValue("title"),
   Body:  r.PostFormValue("body"),
   UserID: currentUser.ID,
   // 获取分类ID
   CategoryID:  types.StringToUint64(r.PostFormValue("category_id")),
}

...
  • Edit() 方法编辑文章

// 读取分类 select
categories , _:= category.All()
// 4. 读取成功,显示编辑文章表单
view.Render(w, view.D{
   "Article": _article,
   "Categories": categories,
   "Errors":  view.D{},
}, "articles.edit", "articles._form_field")
  • Update() 方法更新文章

// 接收更换的分类ID
cid := r.PostFormValue("category_id")
_category , err := category.Get(cid)
if err != nil {
   ac.ResponseForSQLError(w, err)
}
_article.CategoryID  = types.StringToUint64(cid)
// 这个地方有一些疑惑 ???
_article.Category    = _category

【我的疑惑】

  • 文章的创建和更新中有个地方关于 article.CategoryID 的变更,为什么在新增的时候只需要把 CategoryID 分类id 赋值到 article里面,但是更新的时候,必须加上 _article.Category = _category 才能更新分类成功

GORM 还是挺好用的,关联模型的时候,感觉join都不用写了

go
明天我们吃什么 悲哀藏在现实中 Tacks
讨论数量: 6

Go

_article.CategoryID  = types.StringToUint64(cid) //<-其实这步可以省略(注释掉也不影响数据库更新),也不做展示(eg:上图),所以没啥卵用
_article.Category    = _category    //<-这个才是最关键的

可以跟进一下这个方法

Go

Go

Go

{
    BaseModel:
    {
        ID:5 CreatedAt:2022-09-05 08:32:35.973 +0800 CST 
        UpdatedAt:2022-09-05 22:46:52.121 +0800 CST
    } 
    Title:这是一个神话 
    Body:这是一个神话这是一个神话这是一个神话这是一个神话 
    UserID:1 
    User:
    {
        BaseModel:
        {
            ID:1 
            CreatedAt:2022-09-03 19:37:54.786 +0800 CST 
            UpdatedAt:2022-09-03 19:37:54.786 +0800 CST
        } 
        Name:admin 
        Email:wdsj002@126.com 
        Password:$2a$14$Y4fcbERWttvilMHqBpBzg.V8aZqMgPxyfHjZeagbq1v73WOu4tCkq 
        PasswordConfirm:
    }
    CategoryID:2 
    Category:
    {
        BaseModel:
        {
            ID:3 
            CreatedAt:2022-09-04 21:46:07.485 +0800 CST 
            UpdatedAt:2022-09-04 21:46:07.485 +0800 CST
        } 
        Name:神话
    }
}
1年前 评论
Tacks (楼主) 1年前
"Categories": categories,

在view.go 文件中全局,可以不用再次查询

1年前 评论

有个疑问,我希望修改表单验证(article_form.go),来确保表单提交时category_id的值有效。 但我不知道如何在规则中写这个字段名称,无论把该字段写作“category_id”还是“CategoryID”,都会报错。

1年前 评论

楼上,直接参考not_exists规则

// 1. 表单规则
    rules := govalidator.MapData{
        "name":             []string{"required", "alpha_num", "between:3,20", "not_exists:users,name"},
        "email":            []string{"required", "min:4", "max:30", "email", "not_exists:users,email"},
    }
1年前 评论

遇到了同样的问题, 谢谢各位楼主和大佬@wz8081633

1年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!