Golang GAE - intID in struct for mustache

2019-03-28 04:52发布

Here is an Example of the app. The essential code is in: golang-code/handler/handler.go (After the subject should appear an ID!)

Im trying to build a little blog system in Golang on Google Appengine and use Mustache as template engine.

So, i have a struct:

type Blogposts struct {
    PostTitle   string
    PostPreview string
    Content     string
    Creator     string
    Date        time.Time
}

The data is passed to GAE via

    datastore.Put(c, datastore.NewIncompleteKey(c, "Blogposts", nil), &blogposts)

So, GAE assigns automatically a intID (int64). Now I tried to get the latest blogposts

// Get the latest blogposts
c := appengine.NewContext(r)
q := datastore.NewQuery("Blogposts").Order("-Date").Limit(10)

var blogposts []Blogposts
_, err := q.GetAll(c, &blogposts)

Until there all things works fine, but when I try to access intID (or stringID, whatever) I dont have access to this :-(

<h3><a href="/blog/read/{{{intID}}}">{{{PostTitle}}}</a></h3>

(PostTitle works, intID not, i've tried thousand of things, nothing worked :-( )

Anyone an idea? This would be great!

Edit: I use mustache.

http://mustache.github.com/

In the code I use:

x["Blogposts"] = blogposts
data := mustache.RenderFile("templates/about.mustache", x)
sendData(w, data) // Equivalent to fmt.Fprintf

And then the data can be accessed in the .mustache template with {{{Content}}} or {{{PostTitle}}} etc.

4条回答
▲ chillily
2楼-- · 2019-03-28 05:03

AFAICS, the Blogposts struct has no field intID, but it has a field PostTitle. I guess that could be the reason why the former doesn't and the later does get rendered, though I've never used Mustache...

查看更多
老娘就宠你
3楼-- · 2019-03-28 05:04

I know this question is a couple years old, but the following article was very helpful to me in this regard: Golang basics with Google Datastore.

In the article, the author provides a nice example of how you can run a query that gets an entity by its ID...

func GetCategory(c appengine.Context, id int64) (*Category, error) {
  var category Category
  category.Id = id

  k := category.key(c)
  err := datastore.Get(c, k, &category)
  if err != nil {
    return nil, err
  }

  category.Id = k.IntID()

  return &category, nil
}

...as well as getting a list/collection of entities with their associated ID:

func GetCategories(c appengine.Context) ([]Category, error) {
  q := datastore.NewQuery("Category").Order("Name")

  var categories []Category
  keys, err := q.GetAll(c, &categories)
  if err != nil {
    return nil, err
  }

  // you'll see this a lot because instances
  // do not have this by default
  for i := 0; i < len(categories); i++ {
    categories[i].Id = keys[i].IntID()
  }

  return categories, nil
}

The snippet above is very close to the helpful answer by @koz.

查看更多
神经病院院长
4楼-- · 2019-03-28 05:10

intID is an internal property of a Key not the struct, and is accessible through a getter:

id := key.IntID()

GetAll returns []*Key, which you're not using:

_, err := q.GetAll(c, &blogposts)

One way to get around this is to create a viewmodel struct that has both your post and key info (untested, but this is the gist of it):

  //... handler code ...

  keys, err := q.GetAll(c, &blogposts)
  if err != nil {
    http.Error(w, "Problem fetching posts.", http.StatusInternalServerError)
    return
  }

  models := make([]BlogPostVM, len(blogposts))
  for i := 0; i < len(blogposts); i++ {
    models[i].Id = keys[i].IntID()
    models[i].Title = blogposts[i].Title
    models[i].Content = blogposts[i].Content
  }

  //... render with mustache ...
}

type BlogPostVM struct {
  Id int
  Title string
  Content string
}
查看更多
Summer. ? 凉城
5楼-- · 2019-03-28 05:10

As hyperslug pointed out, the id field of an entity is on the key, not the struct it gets read into.

Another way around this is to add an id field to your struct and tell datastore to ignore it, eg:

type Blogposts struct {
    PostTitle   string
    PostPreview string
    Content     string
    Creator     string
    Date        time.Time
    Id          int64 `datastore:"-"`
}

You can then populate the Id field manually after a call to GetAll() like so

keys, err := q.GetAll(c, &blogposts)
if err != nil {
    // handle the error
    return
}
for i, key := range keys {
    blogposts[i].Id = key.IntID()
}

This has the benefit of not introducing an extra type.

查看更多
登录 后发表回答