dongshui9690
dongshui9690
2014-07-10 09:19

转到调用t.Execute中的许多参数

Im trying to render a template with values that I got from a table of a db. The problem is that when I run the program I got errors. I dont know what Im doing wrong.

I started creating an estructure:

type App struct{
    Title string
    Author string
    Description string
}

I created a function to render the templates:

   func render(w http.ResponseWriter, tmpl string, data map[string]interface{}){
    tmpl = fmt.Sprintf("templates/%s", tmpl)
    t, err := template.ParseFiles(tmpl)
    if err != nil{
        log.Print("template parsing error: ", err)
    }
    err = t.Execute(w, data)
    if err != nil{
        log.Print("template executing error: ", err)
    }
}

Then, here I got the apps from the database and try to render them to the html.

func myappsHandler(w http.ResponseWriter, r *http.Request){
    db, err := sql.Open("postgres"," user=postgres dbname=lesson4 host=localhost password=1234 sslmode=disable")
    if err != nil{
        log.Fatal(err)
    }
        rows, err := db.Query(`SELECT title, author, description FROM apps
                                 WHERE title ILIKE $1
                                 OR author ILIKE $1
                                 OR description ILIKE $1`)
            defer rows.Close()

            apps := []App{}
            for rows.Next(){
                b := App{}
                err := rows.Scan(&b.Title, &b.Author, &b.Description)

                if err != nil{
                log.Fatal(err)
            }
                apps = append(apps, b)
            }

            render(w, "myapps.html", map[string]interface{}{"apps" : apps})

        db.Close()
}

My main function:

func main() {

    http.HandleFunc("/myapps", myappsHandler)
    http.ListenAndServe(":8080", nil)
}

And this is myapps.html

<html>
<body>
<table class="table">
  <tr>
    <th>Título</th>
    <th>Imagen</th>
    <th>Descripción</th>
  </tr>
{{ range .}}
  <tr>
    <td>{{ .Title }}</td>
    <td>{{ .Author }}</td>
    <td>{{ .Description }}</td>
    <td> <form action="/delete">
          <p class="navbar-form navbar-right"><button type="submit" class="btn btn-danger">Borrar</button> </p>
       </form></td>
  </tr>
{{ end  }}
</table>
    </body>
</html>
  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答

1条回答

  • dongren1011 dongren1011 7年前

    Your render function accepts a http.ResponseWriter and a string. You are trying to pass it a http.ResponseWriter, a string and a []App.

    The short answer is that you should change your function to accept a map[string]interface that you can pass to ExecuteTemplate. This is useful when you want to pass more than one thing to a template later.

    func render(w http.ResponseWriter, tmpl string, data map[string]interface{}){
            tmpl = fmt.Sprintf("templates/%s", tmpl)
            t, err := template.ParseFiles(tmpl)
            if err != nil{
                log.Print("template parsing error: ", err)
            }
            // We pass our data map to the template
            err = t.Execute(w, data)
            if err != nil{
                log.Print("template executing error: ", err)
            }
        }
    

    ... and call it like so:

        render(w, "myapps.html", map[string]interface{}{
            "apps": apps
        })
    

    The long answer is that:

    • You are establishing a new database pool on every request. Not good! Create either a global pool (okay; sql.DB has locks) or by passing a *sql.DB to your handlers.

    • You are re-parsing your templates on every request. This is slow and inefficient. Parse them once on start-up as per http://golang.org/doc/articles/wiki/#tmp_6

    • You can write a shortcut for map[string]interface{} by writing out type M map[string]interface{}, which will allow you to instead write render(w, "myapps.html", M{"apps": apps})

    • You should split your DB query out into its own function so you can re-use it elsewhere.

    • sqlx can help you from having to rows.Scan() things yourself - it's a nice convenience wrapper around database/sql.

    Updated

    I've managed to compile your code (for the most part) on my machine, and don't have any panics. I suggest you read the whole stack trace, including the bit above the nil pointer deference/memory address, which may be something along the lines of "template parsing error" (is your filename correct?).

    http://play.golang.org/p/QZ65eP-Aln (I've commented out the database stuff)

    You will need to fix your templates to have {{ range .apps }}, however that won't be the source of the panic.

    <html>
    <body>
    <table class="table">
      <tr>
        <th>Título</th>
        <th>Imagen</th>
        <th>Descripción</th>
      </tr>
    {{ range .apps }}
      <tr>
        <td>{{ .Title }}</td>
        <td>{{ .Author }}</td>
        <td>{{ .Description }}</td>
        <td> <form action="/delete">
              <p class="navbar-form navbar-right"><button type="submit" class="btn btn-danger">Borrar</button> </p>
           </form></td>
      </tr>
    {{ end  }}
    </table>
        </body>
    </html>
    
    点赞 评论 复制链接分享

为你推荐