package main
import (
"fmt"
"github.com/gin-contrib/multitemplate"
"github.com/gin-gonic/gin"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"html/template"
"log"
"os"
"reflect"
"strconv"
"time"
)
/*
go在调用gorm将结构体对象转换成mysql对应的数据进行插入的时候,里面的动作实际是一下几点:
1. gorm插件调用create(&t)函数 从go的结构体变量t里面获取到对应的内存的值,并将t结构体指针对应的值进行转换成mysql的insert语句将结构体对象的值插入到mysql数据库对应的t结构体名字一致的表名里面;
2. mysql根据gorm插件转换之后的sql语句对表进行数据插入操作;
3. gorm插件将mysql生成的字段值返回值结构体变量t指针对应的内存地址的值;
4. 此刻就能保证结构体t指针指向的内存地址的值与mysql对应生成的字段的值保持一致,且一一映射;
*/
/*Gorm框架在执行插入操作以后,会将数据库返回的生成值(如自增主键)更新到传入结构体的相应字段中。这个过程发生在应用层,而非数据库层,确保了go程序中的对象状态与数据库的一致性。
例如,如果你有一个结构体定义如下:
go
type User struct {
ID uint `gorm:"primary_key"`
Name string
}
然后你创建一个新的User:
user := User{Name: "John"}
db.json.Create(&user)
在执行 db.json.Create(&user) 后,假设数据库生成的新纪录id为5,则Gorm会更新 user.ID 的值为5。这样,你就可以从你的Go程序中的 user 对象直接获取新插入记录的ID。
注意这个操作是【Gorm框架提供的功能】,它在【插入完成后】,【再次查询了数据库中的新纪录】,然后【把新纪录的值指定回 user 对象】。这样你可以确保 user 对象中的值与数据库中的记录是同步的。*/
type BaseModel struct {
Id int `gorm:"primarykey"`
CreateTime *time.Time `gorm:"autoCreateTime"`
UpdateTime *time.Time `gorm:"autoCreateTime"`
Name string `gorm:"type:varchar(30);unique;not null"`
}
type Teachers struct {
BaseModel
Ton int `gorm:"unique"`
//Pwd string `gorm:"type:varchar(100);not null"`
Tel string `gorm:"type:char(11);"`
Birth *time.Time
Remark string `gorm:"type:varchar(255);"`
//一对一
AccountID int `gorm:"unique"`
Account Account
}
type Account struct {
BaseModel
Pwd string
}
type Students struct {
BaseModel
Sno int `gorm:"unique"`
//Pwd string `gorm:"type:varchar(100);not null"`
Tel string `gorm:"type:char(11);"`
Gender int
Brith *time.Time
Remark string `gorm:"type:varchar(255);"`
//多对一
ClassID int
Class Class `gorm:"foreignkey:ClassID;constraint:OnDelete:CASCADE;"`
//多对多
Course []Course `gorm:"many2many:student2course;constraint:OnDelete:CASCADE;"`
//一对一
AccountID int `gorm:"unique"`
Account Account `gorm:"constraint:OnDelete:CASCADE;"`
}
/*
在 gorm 使用 Go 语言定义数据模型的结构体时,多对一 (Many-to-One) 和一对一 (One-to-One) 关系的主要区别确实在于外键的唯一性:
一对一 (One-to-One)
一对一关系是指一个实体 A 的记录只能与另一个实体 B 的唯一记录相关联,反之亦然。在 gorm 中,这通常通过在实体 A 的结构体中添加一个具有 unique 约束的外键字段来实现,这样每个实体 B 的记录只能关联一个实体 A 的记录。
type Students struct {
// ...
AccountID int `gorm:"unique"` // 表示一对一关系,AccountID 是外键且是唯一的
Account Account
}
这里的 unique 标签是确保一对一关系的关键。它会告诉数据库在 AccountID 字段上创建唯一约束,这样就不可能有两个 Students 记录具有相同的 AccountID。
多对一 (Many-to-One)
多对一关系指的是多个实体 A(如学生)的记录可以关联到单个实体 B(如班级)的记录。在 gorm 中,这通过在实体 A 的结构体中加入一个外键来实现,这个外键指向实体 B 的记录的主键。
type Students struct {
// ...
ClassID int // 外键,指向 Class 实体,表示多对一关系
Class Class `gorm:"foreignKey:ClassID"`
}
在这个例子中,ClassID 是外键,但并没有 unique 约束。这意味着多个 Students 的记录可以有相同的 ClassID,即多个学生可以属于同一个班级。
总结
所以,从 Go 语言的角度来看:
一对一:外键具有 unique 约束。
多对一:外键没有 unique 约束。
在数据库设计中,这两种关系在逻辑上有明显的不同,且对应了不同的完整性约束。在数据模型或结构体的定义中,unique 标签是区分一对一和多对一关系的关键因素。
*/
type Course struct {
BaseModel
Credit int
Period int
TeacherID int
Teacher Teachers `gorm:"foreignkey:TeacherID"`
}
type Class struct {
BaseModel
Num int
TutorID int
Tutor Teachers `gorm:"foreignkey:TutorID"`
}
//构建函数体
// 数据库初始化
func DbInit() *gorm.DB {
newLogger := logger.New(
log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
logger.Config{
//SlowThreshold: time.Second, // 慢 SQL 阈值
LogLevel: logger.Info, // Log level
},
)
fmt.Println(reflect.TypeOf(newLogger))
dsn := "xxx:xxxx@tcp(124.221.77.206:xxxx)/css3?charset=utf8mb4&parseTime=True&loc=Local"
db, _ = gorm.Open(mysql.Open(dsn), &gorm.Config{
Logger: newLogger,
})
//调用gorm根据go语言的结构体去创建mysql一一对应的表
/*db.AutoMigrate(&Teachers{})
db.AutoMigrate(&Class{})
db.AutoMigrate(&Course{})
db.AutoMigrate(&Students{})
db.AutoMigrate(&Account{})*/
//先删除表
//db.Migrator().DropTable(&Teachers{}, &Class{}, &Course{}, &Students{}, &Account{})
//再重建表
//db.AutoMigrate(&Teachers{}, &Class{}, &Course{}, &Students{})
return db
}
// 定义全局变量,用于给下面的db引用
var db *gorm.DB
func Stu(ctx *gin.Context) {
//插入数据
var Student []Students
//get请求里面获取头部[查询]信息
Cx := ctx.Query("cx")
fmt.Println("====", Cx, "====")
//判断Cx的值,如果为空则显示所有,如果有值则根据值进行过滤后再进行渲染返回响应
if Cx == "" {
//关联预加载
db.Preload("Class.Tutor").Preload("Account").Find(&Student)
} else {
//关联预加载过滤查询
db.Where("Name like ?", "%"+Cx+"%").Preload("Class.Tutor").Find(&Student)
}
//服务器响应客户端
ctx.HTML(200, "student.html", gin.H{
"student": Student,
})
//fmt.Println(Student)
}
func studentAdd(ctx *gin.Context) {
//获取class表所有数据
var Cla []Class
//db.json.Where("Name like ?", "软件%").Find(&Cla)
db.Find(&Cla)
fmt.Println(Cla)
ctx.HTML(200, "stuAdd.html", gin.H{
"class": Cla,
})
}
func submit(ctx *gin.Context) {
//从post请求头里面抓起head内容
Name := ctx.PostForm("xm")
Sno := ctx.PostForm("xh")
Tel := ctx.PostForm("tel")
Pwd := ctx.PostForm("pw")
Gender := ctx.PostForm("gender")
SON, _ := strconv.Atoi(Sno)
ClassID := ctx.PostForm("class")
ClaID, _ := strconv.Atoi(ClassID)
Gend, _ := strconv.Atoi(Gender) //字符转换成int数据类型
fmt.Println(Name, Sno, Tel, Pwd, SON, ClassID, ClaID, "----")
//Student := Students{BaseModel: BaseModel{Name: Name}, Pwd: Pwd, Sno: SON, Tel: Tel, ClassID: ClaID, Gender: Gend}
Student := Students{BaseModel: BaseModel{Name: Name}, Sno: SON, Tel: Tel, ClassID: ClaID, Gender: Gend, Account: Account{Pwd: Pwd, BaseModel: BaseModel{
Name: Name,
}}}
//插入数据
db.Create(&Student)
//每当插入数据之后就会相应的在class的Num里面进行增+1的操作
db.Model(Class{}).Where(" Id = ?", ClassID).Update("num", gorm.Expr("num+1"))
//重定向
ctx.Redirect(301, "/student")
}
func delete(ctx *gin.Context) {
var Student Students
//获取url参数
DelID := ctx.Param("DelID")
fmt.Println("---WEQW----", DelID, "---EWEQ===")
//删除DelID对应数据库里面sno字段参数对应的数据
db.Where("sno = ?", DelID).Delete(&Student)
//重定向
ctx.Redirect(301, "/student")
}
func edit(ctx *gin.Context) {
var (
Cla Class
Student Students
C []Class
)
//获取到页面URL参数
EdiID := ctx.Param("EdiID")
fmt.Println("====", EdiID, "==========")
db.Preload("Account").Where("sno = ?", EdiID).Find(&Student)
//定义获取到的class
db.Where("Id = ?", Student.ClassID).Find(&Cla)
//获取所有class班级信息
db.Find(&C)
fmt.Println(Student.ClassID)
ctx.HTML(200, "studentEdit.html", gin.H{
"student": Student,
"class": Cla,
"claAll": C,
})
}
func upEdit(ctx *gin.Context) {
//从post请求头里面抓起head内容
Name := ctx.PostForm("xm")
Sno := ctx.PostForm("xh")
Tel := ctx.PostForm("tel")
Pwd := ctx.PostForm("pw")
Gender := ctx.PostForm("gender")
SON, _ := strconv.Atoi(Sno)
ClassID := ctx.PostForm("class")
ClaID, _ := strconv.Atoi(ClassID)
Gend, _ := strconv.Atoi(Gender) //字符转换成int数据类型
fmt.Println(Name, Sno, Tel, Pwd, SON, ClassID, ClaID, Gender, "----")
//修改账户密码,在go语言里面不支持修改嵌套在结构体内的值,不会更新级联嵌套结构体里面的字段。
var (
Student Students
Ac Account
)
account := db.Where("sno = ?", SON).Preload("Account").Find(&Student)
fmt.Println(reflect.TypeOf(account), account)
if account.Error != nil {
fmt.Println(account.Error)
}
fmt.Println("ppppppppppppppppppppppppp->", Student.AccountID, Student)
result := db.Model(Ac).Where("id = ? ", Student.AccountID).Update("Pwd", Pwd)
//Student := Students{BaseModel: BaseModel{Name: Name}, Pwd: Pwd, Sno: SON, Tel: Tel, ClassID: ClaID, Gender: Gend}
student := Students{BaseModel: BaseModel{Name: Name}, Sno: SON, Tel: Tel, ClassID: ClaID, Gender: Gend}
fmt.Println(Student)
result2 := db.Model(Students{}).Where("sno = ?", SON).Updates(student)
if result.Error != nil {
fmt.Printf("Error updating student: %v\n", result2.Error)
}
/*重定向:客户端访问/student/submit表单页面进行数据提交;服务器响应客户端【空值】;客户端第二次向服务端发出/student页面请求;服务端再次根据请求将/student页面响应客户端;
一次请求两个响应,一次空响应,第二次为跳转之后的响应页面数据*/
ctx.Redirect(301, "/student")
}
func index(ctx *gin.Context) {
ctx.HTML(200, "xcxc", gin.H{})
}
// 创建累加函数
func addOne(i int) int {
return i + 1
}
func StuSelect(ctx *gin.Context) {
var (
Student Students
Col []Course
)
//获取页面的ID
stuID := ctx.Param("stuID")
fmt.Println("p-------", stuID, "----------p")
db.Where("sno = ? ", stuID).Preload("Class.Tutor").Preload("Account").Find(&Student)
fmt.Println(Student)
//获取到学生对应的课程信息
db.Model(&Student).Preload("Teacher").Preload("Account").Association("Course").Find(&Col)
ctx.HTML(200, "StuSelect.html", gin.H{
"student": Student,
"course": Col,
})
}
func course(ctx *gin.Context) {
var (
Cou []Course
Stu Students
)
//获取页面的ID
stuID := ctx.Param("stuID")
db.Where("sno = ?", stuID).Take(&Stu)
fmt.Println("p-------", stuID, "----------p")
db.Preload("Teacher").Find(&Cou)
fmt.Println(Cou)
ctx.HTML(200, "course.html", gin.H{
"course": Cou,
"stuID": stuID,
"student": Stu,
})
}
func class(ctx *gin.Context) {
}
func courseSubmit(ctx *gin.Context) {
//tuID := ctx.Param("stuID")
//fmt.Println(tuID)
courseName := ctx.PostForm("kc")
xf := ctx.PostForm("xf")
zq := ctx.PostForm("zq")
teacher := ctx.PostForm("teacher")
//cla:=ctx.PostForm("class")
Xf, _ := strconv.Atoi(xf)
Zq, _ := strconv.Atoi(zq)
Te, _ := strconv.Atoi(teacher)
fmt.Println(courseName, xf, zq, teacher)
var (
Cou []Course
Tea Teachers
)
db.Where("id = ?", Te).Take(&Tea)
db.Find(&Cou)
c := Course{
BaseModel: BaseModel{Name: courseName},
Credit: Xf,
Period: Zq,
TeacherID: Te,
Teacher: Tea,
}
db.Create(&c)
fmt.Println(Cou, "-----", Tea)
//重定向
ctx.Redirect(301, "/course")
}
func courseSelect(ctx *gin.Context) {
var co []Course
db.Preload("Teacher").Find(&co)
ctx.HTML(200, "CourseSelect.html", gin.H{
"course": co,
})
}
func courseADD(ctx *gin.Context) {
var (
Tea []Teachers
)
db.Find(&Tea)
//db.Find(&Cou)
ctx.HTML(200, "courseADD.html", gin.H{
"Tea": Tea,
//"class": Cou,
})
}
func PostCourse(ctx *gin.Context) {
var (
Stud Students
Col []Course
)
//获取url参数
stuID := ctx.Param("stuID")
//获取到url的的post请求的from表单的course多值postformArray进行参数获取
CouID := ctx.PostFormArray("courseSelect")
//根据参数过滤到指定的学生
fmt.Println(stuID, CouID)
//根据sno的ID值查询到学生信息
db.Where("sno = ?", stuID).Preload("Class.Tutor").Preload("Students").Find(&Stud)
//根据post请求的值获取到对应的课程信息
db.Where("id in ?", CouID).Preload("Teacher").Find(&Col)
//将学生与课程进行绑定
db.Model(&Stud).Preload("Students").Association("Course").Append(&Col)
//查询有关学生的所有课程绑定信息
db.Model(&Stud).Preload("Teacher").Association("Course").Find(&Col)
//服务器响应客户端,并对模板进行渲染
ctx.HTML(200, "StuSelect.html", gin.H{
"course": Col,
"student": Stud,
})
}
func Login(ctx *gin.Context) {
ctx.HTML(200, "login.html", nil)
}
func LoginPOST(ctx *gin.Context) {
var AC Account
Name := ctx.PostForm("name")
Pwd := ctx.PostForm("pwd")
db.Where("name = ? AND pwd = ?", Name, Pwd).Take(&AC)
if AC.Id == 0 {
ctx.String(200, "登入失败")
} else {
ctx.JSON(200, gin.H{
"name": Name,
"PWD": Pwd,
})
}
}
func createMyRender() multitemplate.Renderer {
// 创建功能映射
funcMap := template.FuncMap{
"addOne": addOne,
}
templates, err := template.New("StuSelect.html").Funcs(funcMap).ParseFiles("template/publi.html", "template/StuSelect.html")
if err != nil {
log.Fatalf("Failed to create template 'xcxc': %v", err)
}
r := multitemplate.NewRenderer()
r.AddFromFiles("xcxc", "template/publi.html", "template/index.html") //xcxc 为组合后的模板名称,与函数内的名字保持一致即可
r.AddFromFiles("student.html", "template/publi.html", "template/student.html")
r.AddFromFiles("stuAdd.html", "template/publi.html", "template/studentAdd.html")
r.AddFromFiles("course.html", "template/publi.html", "template/course.html")
r.AddFromFiles("clss.html", "template/publi.html", "template/class.html")
r.AddFromFiles("studentADD.html", "template/publi.html", "template/jixuADD.html")
r.AddFromFiles("studentEdit.html", "template/publi.html", "template/studentEdit.html")
//r.AddFromFiles("StuSelect.html", "template/publi.html", "template/StuSelect.html")
r.Add("StuSelect.html", templates)
r.AddFromFiles("courseADD.html", "template/publi.html", "template/courseADD.html")
r.AddFromFiles("CourseSelect.html", "template/publi.html", "template/CourseSelect.html")
r.AddFromFiles("login.html", "template/LoginStu.html")
return r
/*
在Gin框架中注册自定义函数addOne,并在名为StuSelect.html的模板中使用它。错误panic: template: StuSelect.html:46: function "addOne" not defined表明在解析模板的过程中
模板引擎尝试查找并执行addOne函数,但是没有找到这个函数的定义。
要解决这个问题,你需要确保以下几点:
自定义函数addOne确实已经在你的代码中定义了。
这个函数通过适当的FuncMap注册到了Gin框架的模板中。
这个注册的函数在模板中使用的时候要匹配函数映射中的键(即函数名)。
你的代码中的错误是因为你在Gin的默认模板渲染器HTMLRender中并没有正确地注册自定义的函数映射。你使用了multitemplate.NewRenderer()来创建新的多模板渲染器,但在创建这个渲染器的过程中,并没有将自定义函数addOne加入到FuncMap中。
你在main函数中尝试注册addOne到"StuSelect.html"模板,并设置它为Gin的HTML渲染器。这个操作并不能应用到multitemplate.Renderer上。由于multitemplate.Renderer处理多模板的方式不同,你的自定义函数需要通过不同的方式注册。
为了将自定义函数addOne注册到你所有使用multitemplate.Renderer的模板中,你需要在每个AddFromFiles调用中创建一个新的template.Template,将FuncMap添加到这个模板,并且使用它们来创建各自的页面模板。
修改createMyRender函数,像这样注册你的自定义函数:
go
func createMyRender() multitemplate.Renderer {
funcMap := template.FuncMap{
"addOne": addOne,
}
r := multitemplate.NewRenderer()
// 这里以"xcxc"为例,其他模板类似地处理
templates, err := template.New("publi.html").Funcs(funcMap).ParseFiles("template/publi.html", "template/index.html")
if err != nil {
log.Fatalf("Failed to create template 'xcxc': %v", err)
}
r.Add("xcxc", templates)
// ...其他模板注册代码
return r
}
请确保使用Funcs和ParseFiles的顺序是正确的,并且处理了所有可能发生的错误。
这样做能够确保所有使用multitemplate.Renderer的模板都注册了addOne函数。
最后,记得删除main函数中重新注册StuSelect.html模板和设置HTML渲染器的代码,因为这个操作应该在createMyRender函数内完成。所有模板都应该通过multitemplate.Renderer来创建和注册。
在您提供的代码中,“xcxc”是一个在multitemplate.NewRenderer()中注册的模板的名称。在Gin框架中,multitemplate是一个用来支持多模板渲染的扩展包。使用这个扩展包的NewRenderer()方法可以创建一个新的渲染器,它能允许您为不同的路由定义不同的模板布局。
在创建这些模板时,您可以为这些组合好的模板指定任意的名字,名称是自定义的,对系统没有具体的意义,但是应该反映出模板的内容或用途,让人一看就能理解这个模板的作用。在这里,xcxc可能是开发者随意给出的一个示例名称,或者特定于应用程序上下文的内部命名。
举例来说,以下代码创建了一个名为xcxc的组合模板,该模板由"template/publi.html"和"template/index.html"这两个文件组合而成:
go
r.AddFromFiles("xcxc", "template/publi.html", "template/index.html")
在这段代码中,"xcxc"是您可以在Gin的路由处理函数中使用的模板名。例如:
go
func index(ctx *gin.Context) {
ctx.HTML(http.StatusOK, "xcxc", gin.H{
// 模板数据...
})
}
在这个index函数中,调用ctx.HTML方法时使用了"xcxc"作为模板名称,这告诉Gin渲染器要使用我们定义的包含名为"xcxc"的组合模板来生成响应的HTML。
总结来说,"xcxc"在您提供的代码示例中只是一个随意的模板名称,它在Gin的路由处理中用来引用特定的模板组合。您完全可以根据自己的需要将它改为更具描述性的名称。
*/
}
func main() {
//数据库初始化
DbInit()
//构gin引擎
r := gin.Default()
//加载静态文件
r.Static("/static", "./static")
//多模块加载,渲染
r.HTMLRender = createMyRender()
//动态路由
r.GET("/", index)
r.GET("/student", Stu)
r.GET("/student/:stuID/course", course)
r.GET("/class", class)
r.GET("/student/add", studentAdd)
r.GET("/student/delete/:DelID", delete)
r.GET("/student/edit/:EdiID", edit)
r.POST("/student", upEdit)
r.POST("/student/submit", submit)
r.GET("/student/:stuID/StuSelect", StuSelect)
r.POST("/student/:stuID/StuSelect", PostCourse)
r.GET("/login", Login)
r.POST("/login", LoginPOST)
r.GET("/course", courseSelect)
r.GET("/course/add", courseADD)
r.POST("/course/submit", courseSubmit)
//运行go引擎
r.Run(":8888")
}
class.html
{{template "publi.html" .}}
{{define "content" }}
班级管理系统
{{end}}
{{define "title" }}
班级管理系统
{{end}}
course.html
{{template "publi.html" .}}
{{define "content" }}
选课信息
{{end}}
{{define "title" }}
学生管理系统
{{end}}
{{define "jumu"}}
{{$student := .student}}
{{end}}
{{define "xuanxiang"}}
{{end}}
courseADD.html
{{template "publi.html" .}}
{{define "content" }}
添加课程
{{end}}
{{define "title" }}
班级管理系统
{{end}}
CourseSelect.html
{{template "publi.html" .}}
{{define "content" }}
{{$course := .course}}
学生管理
序号
课程名称
学分
周期
导师
{{range $course:=.course}}
{{$course.Id}}
{{$course.Name}}
{{$course.Credit}}
{{$course.Period}}
{{$course.Teacher.Name}}
{{end}}
{{end}}
{{define "title" }}
学生管理系统
{{end}}
{{define "jumu"}}
{{$student := .student}}
{{end}}
{{define "xuanxiang"}}
{{$student := .student}}
{{end}}
delete.html
{{template "publi.html" .}}
{{define "content" }}
学生管理
序号
学号
姓名
密码
电话号码
性别
班级
删除
{{ range $student:=.student}}
{{$student.Id}}
{{$student.Sno}}
{{$student.Name}}
{{$student.Pwd}}
{{$student.Tel}}
{{$student.Gender}}
{{$student.ClassID}}
{{end}}
{{end}}
{{define "title" }}
学生管理系统
{{end}}
index.html
{{template "publi.html" .}}
{{ define "content"}}
首页页面
{{end}}
{{define "title" }}
首页页面
{{end}}
jixuADD.html
{{template "publi.html" .}}
{{define "content" }}
添加学生
{{end}}
{{define "title" }}
学生管理系统
{{end}}
login.html
HTML5响应式用户登录界面模板
登录
用户名
密码
LoginStu.html
Document
login
publi.html
{{block "title" .}}
学生管理系统
{{end}}
{{block "xuanxiang" .}}
{{end}}
student.html
{{template "publi.html" .}}
{{define "content" }}
学生管理
序号
学号
姓名
密码
电话号码
性别
班级
班级人数
导师
删除
编辑
{{ range $student:=.student}}
{{$student.Id}}
{{$student.Sno}}
{{$student.Name}}
{{$student.Account.Pwd}}
{{$student.Tel}}
{{$student.Gender}}
{{$student.Class.Name}}
{{$student.Class.Num}}
{{$student.Class.Tutor.Name}}
{{end}}
{{end}}
{{define "title" }}
学生管理系统
{{end}}
studentAdd.html
{{template "publi.html" .}}
{{define "content" }}
添加学生
{{end}}
{{define "title" }}
学生管理系统
{{end}}
studentEdit.html
{{template "publi.html" .}}
{{define "content" }}
添加学生
{{end}}
{{define "title" }}
学生管理系统
{{end}}
StuSelect.html
{{template "publi.html" .}}
{{define "content" }}
{{$student := .student}}
{{$student.Name}}同学个人信息
序号
学号
姓名
密码
电话号码
性别
班级
导师
{{$student.Id}}
{{$student.Sno}}
{{$student.Name}}
{{$student.Account.Pwd}}
{{$student.Tel}}
{{$student.Gender}}
{{$student.Class.Name}}
{{$student.Class.Tutor.Name}}
选课信息
{{$student.Name}}同学已选课程
课程序号
课程名称
学分
周期
导师
{{range $id,$course:=.course}}
{{addOne $id}}
{{$course.Name}}
{{$course.Credit}}
{{$course.Period}}
{{$course.Teacher.Name}}
{{end}}
{{end}}
{{define "title" }}
学生管理系统
{{end}}
{{define "jumu"}}
{{$student := .student}}
{{end}}
{{define "xuanxiang"}}
{{$student := .student}}
{{end}}
teachers.html
{{template "publi.html" .}}
{{define "content" }}
学生管理
序号
姓名
ID
电话号码
{{ range $Teacher:=.name}}
{{$Teacher.Id}}
{{$Teacher.Name}}
{{$Teacher.Ton}}
{{$Teacher.Tel}}
{{end}}
{{end}}
{{define "title" }}
学生管理系统
{{end}}