diff --git a/models/action.go b/models/action.go
index 9050be22a6..cde0fb080e 100644
--- a/models/action.go
+++ b/models/action.go
@@ -194,6 +194,10 @@ func (a *Action) GetRepoLink() string {
 
 // GetCommentLink returns link to action comment.
 func (a *Action) GetCommentLink() string {
+	return a.getCommentLink(x)
+}
+
+func (a *Action) getCommentLink(e Engine) string {
 	if a == nil {
 		return "#"
 	}
@@ -213,11 +217,15 @@ func (a *Action) GetCommentLink() string {
 		return "#"
 	}
 
-	issue, err := GetIssueByID(issueID)
+	issue, err := getIssueByID(e, issueID)
 	if err != nil {
 		return "#"
 	}
 
+	if err = issue.loadRepo(e); err != nil {
+		return "#"
+	}
+
 	return issue.HTMLURL()
 }
 
@@ -330,13 +338,15 @@ type PushCommits struct {
 	Commits    []*PushCommit
 	CompareURL string
 
-	avatars map[string]string
+	avatars    map[string]string
+	emailUsers map[string]*User
 }
 
 // NewPushCommits creates a new PushCommits object.
 func NewPushCommits() *PushCommits {
 	return &PushCommits{
-		avatars: make(map[string]string),
+		avatars:    make(map[string]string),
+		emailUsers: make(map[string]*User),
 	}
 }
 
@@ -344,16 +354,34 @@ func NewPushCommits() *PushCommits {
 // api.PayloadCommit format.
 func (pc *PushCommits) ToAPIPayloadCommits(repoLink string) []*api.PayloadCommit {
 	commits := make([]*api.PayloadCommit, len(pc.Commits))
+
+	if pc.emailUsers == nil {
+		pc.emailUsers = make(map[string]*User)
+	}
+	var err error
 	for i, commit := range pc.Commits {
 		authorUsername := ""
-		author, err := GetUserByEmail(commit.AuthorEmail)
-		if err == nil {
+		author, ok := pc.emailUsers[commit.AuthorEmail]
+		if !ok {
+			author, err = GetUserByEmail(commit.AuthorEmail)
+			if err == nil {
+				authorUsername = author.Name
+				pc.emailUsers[commit.AuthorEmail] = author
+			}
+		} else {
 			authorUsername = author.Name
 		}
+
 		committerUsername := ""
-		committer, err := GetUserByEmail(commit.CommitterEmail)
-		if err == nil {
-			// TODO: check errors other than email not found.
+		committer, ok := pc.emailUsers[commit.CommitterEmail]
+		if !ok {
+			committer, err = GetUserByEmail(commit.CommitterEmail)
+			if err == nil {
+				// TODO: check errors other than email not found.
+				committerUsername = committer.Name
+				pc.emailUsers[commit.CommitterEmail] = committer
+			}
+		} else {
 			committerUsername = committer.Name
 		}
 		commits[i] = &api.PayloadCommit{
@@ -379,18 +407,28 @@ func (pc *PushCommits) ToAPIPayloadCommits(repoLink string) []*api.PayloadCommit
 // AvatarLink tries to match user in database with e-mail
 // in order to show custom avatar, and falls back to general avatar link.
 func (pc *PushCommits) AvatarLink(email string) string {
-	_, ok := pc.avatars[email]
+	avatar, ok := pc.avatars[email]
+	if ok {
+		return avatar
+	}
+
+	u, ok := pc.emailUsers[email]
 	if !ok {
-		u, err := GetUserByEmail(email)
+		var err error
+		u, err = GetUserByEmail(email)
 		if err != nil {
 			pc.avatars[email] = base.AvatarLink(email)
 			if !IsErrUserNotExist(err) {
 				log.Error(4, "GetUserByEmail: %v", err)
+				return ""
 			}
 		} else {
-			pc.avatars[email] = u.RelAvatarLink()
+			pc.emailUsers[email] = u
 		}
 	}
+	if u != nil {
+		pc.avatars[email] = u.RelAvatarLink()
+	}
 
 	return pc.avatars[email]
 }
@@ -479,7 +517,8 @@ func UpdateIssuesCommit(doer *User, repo *Repository, commits []*PushCommit) err
 				continue
 			}
 
-			if err = issue.ChangeStatus(doer, repo, true); err != nil {
+			issue.Repo = repo
+			if err = issue.ChangeStatus(doer, true); err != nil {
 				// Don't return an error when dependencies are open as this would let the push fail
 				if IsErrDependenciesLeft(err) {
 					return nil
@@ -504,7 +543,8 @@ func UpdateIssuesCommit(doer *User, repo *Repository, commits []*PushCommit) err
 				continue
 			}
 
-			if err = issue.ChangeStatus(doer, repo, false); err != nil {
+			issue.Repo = repo
+			if err = issue.ChangeStatus(doer, false); err != nil {
 				return err
 			}
 		}
diff --git a/models/issue.go b/models/issue.go
index 88e96e5706..cee9b0ca5c 100644
--- a/models/issue.go
+++ b/models/issue.go
@@ -86,6 +86,11 @@ func (issue *Issue) IsOverdue() bool {
 	return util.TimeStampNow() >= issue.DeadlineUnix
 }
 
+// LoadRepo loads issue's repository
+func (issue *Issue) LoadRepo() error {
+	return issue.loadRepo(x)
+}
+
 func (issue *Issue) loadRepo(e Engine) (err error) {
 	if issue.Repo == nil {
 		issue.Repo, err = getRepositoryByID(e, issue.RepoID)
@@ -129,6 +134,11 @@ func (issue *Issue) loadLabels(e Engine) (err error) {
 	return nil
 }
 
+// LoadPoster loads poster
+func (issue *Issue) LoadPoster() error {
+	return issue.loadPoster(x)
+}
+
 func (issue *Issue) loadPoster(e Engine) (err error) {
 	if issue.Poster == nil {
 		issue.Poster, err = getUserByID(e, issue.PosterID)
@@ -154,10 +164,16 @@ func (issue *Issue) loadPullRequest(e Engine) (err error) {
 			}
 			return fmt.Errorf("getPullRequestByIssueID [%d]: %v", issue.ID, err)
 		}
+		issue.PullRequest.Issue = issue
 	}
 	return nil
 }
 
+// LoadPullRequest loads pull request info
+func (issue *Issue) LoadPullRequest() error {
+	return issue.loadPullRequest(x)
+}
+
 func (issue *Issue) loadComments(e Engine) (err error) {
 	if issue.Comments != nil {
 		return nil
@@ -310,11 +326,18 @@ func (issue *Issue) State() api.StateType {
 // Required - Poster, Labels,
 // Optional - Milestone, Assignee, PullRequest
 func (issue *Issue) APIFormat() *api.Issue {
+	return issue.apiFormat(x)
+}
+
+func (issue *Issue) apiFormat(e Engine) *api.Issue {
+	issue.loadLabels(e)
 	apiLabels := make([]*api.Label, len(issue.Labels))
 	for i := range issue.Labels {
 		apiLabels[i] = issue.Labels[i].APIFormat()
 	}
 
+	issue.loadPoster(e)
+	issue.loadRepo(e)
 	apiIssue := &api.Issue{
 		ID:       issue.ID,
 		URL:      issue.APIURL(),
@@ -336,6 +359,8 @@ func (issue *Issue) APIFormat() *api.Issue {
 	if issue.Milestone != nil {
 		apiIssue.Milestone = issue.Milestone.APIFormat()
 	}
+	issue.loadAssignees(e)
+
 	if len(issue.Assignees) > 0 {
 		for _, assignee := range issue.Assignees {
 			apiIssue.Assignees = append(apiIssue.Assignees, assignee.APIFormat())
@@ -343,6 +368,7 @@ func (issue *Issue) APIFormat() *api.Issue {
 		apiIssue.Assignee = issue.Assignees[0].APIFormat() // For compatibility, we're keeping the first assignee as `apiIssue.Assignee`
 	}
 	if issue.IsPull {
+		issue.loadPullRequest(e)
 		apiIssue.PullRequest = &api.PullRequestMeta{
 			HasMerged: issue.PullRequest.HasMerged,
 		}
@@ -656,7 +682,7 @@ func UpdateIssueCols(issue *Issue, cols ...string) error {
 	return updateIssueCols(x, issue, cols...)
 }
 
-func (issue *Issue) changeStatus(e *xorm.Session, doer *User, repo *Repository, isClosed bool) (err error) {
+func (issue *Issue) changeStatus(e *xorm.Session, doer *User, isClosed bool) (err error) {
 	// Nothing should be performed if current status is same as target status
 	if issue.IsClosed == isClosed {
 		return nil
@@ -707,7 +733,7 @@ func (issue *Issue) changeStatus(e *xorm.Session, doer *User, repo *Repository,
 	}
 
 	// New action comment
-	if _, err = createStatusComment(e, doer, repo, issue); err != nil {
+	if _, err = createStatusComment(e, doer, issue); err != nil {
 		return err
 	}
 
@@ -715,14 +741,21 @@ func (issue *Issue) changeStatus(e *xorm.Session, doer *User, repo *Repository,
 }
 
 // ChangeStatus changes issue status to open or closed.
-func (issue *Issue) ChangeStatus(doer *User, repo *Repository, isClosed bool) (err error) {
+func (issue *Issue) ChangeStatus(doer *User, isClosed bool) (err error) {
 	sess := x.NewSession()
 	defer sess.Close()
 	if err = sess.Begin(); err != nil {
 		return err
 	}
 
-	if err = issue.changeStatus(sess, doer, repo, isClosed); err != nil {
+	if err = issue.loadRepo(sess); err != nil {
+		return err
+	}
+	if err = issue.loadPoster(sess); err != nil {
+		return err
+	}
+
+	if err = issue.changeStatus(sess, doer, isClosed); err != nil {
 		return err
 	}
 
@@ -733,12 +766,14 @@ func (issue *Issue) ChangeStatus(doer *User, repo *Repository, isClosed bool) (e
 
 	mode, _ := AccessLevel(issue.Poster, issue.Repo)
 	if issue.IsPull {
+		if err = issue.loadPullRequest(sess); err != nil {
+			return err
+		}
 		// Merge pull request calls issue.changeStatus so we need to handle separately.
-		issue.PullRequest.Issue = issue
 		apiPullRequest := &api.PullRequestPayload{
 			Index:       issue.Index,
 			PullRequest: issue.PullRequest.APIFormat(),
-			Repository:  repo.APIFormat(mode),
+			Repository:  issue.Repo.APIFormat(mode),
 			Sender:      doer.APIFormat(),
 		}
 		if isClosed {
@@ -746,12 +781,12 @@ func (issue *Issue) ChangeStatus(doer *User, repo *Repository, isClosed bool) (e
 		} else {
 			apiPullRequest.Action = api.HookIssueReOpened
 		}
-		err = PrepareWebhooks(repo, HookEventPullRequest, apiPullRequest)
+		err = PrepareWebhooks(issue.Repo, HookEventPullRequest, apiPullRequest)
 	} else {
 		apiIssue := &api.IssuePayload{
 			Index:      issue.Index,
 			Issue:      issue.APIFormat(),
-			Repository: repo.APIFormat(mode),
+			Repository: issue.Repo.APIFormat(mode),
 			Sender:     doer.APIFormat(),
 		}
 		if isClosed {
@@ -759,12 +794,12 @@ func (issue *Issue) ChangeStatus(doer *User, repo *Repository, isClosed bool) (e
 		} else {
 			apiIssue.Action = api.HookIssueReOpened
 		}
-		err = PrepareWebhooks(repo, HookEventIssues, apiIssue)
+		err = PrepareWebhooks(issue.Repo, HookEventIssues, apiIssue)
 	}
 	if err != nil {
 		log.Error(4, "PrepareWebhooks [is_pull: %v, is_closed: %v]: %v", issue.IsPull, isClosed, err)
 	} else {
-		go HookQueue.Add(repo.ID)
+		go HookQueue.Add(issue.Repo.ID)
 	}
 
 	return nil
@@ -785,6 +820,10 @@ func (issue *Issue) ChangeTitle(doer *User, title string) (err error) {
 		return fmt.Errorf("updateIssueCols: %v", err)
 	}
 
+	if err = issue.loadRepo(sess); err != nil {
+		return fmt.Errorf("loadRepo: %v", err)
+	}
+
 	if _, err = createChangeTitleComment(sess, doer, issue.Repo, issue, oldTitle, title); err != nil {
 		return fmt.Errorf("createChangeTitleComment: %v", err)
 	}
@@ -795,6 +834,9 @@ func (issue *Issue) ChangeTitle(doer *User, title string) (err error) {
 
 	mode, _ := AccessLevel(issue.Poster, issue.Repo)
 	if issue.IsPull {
+		if err = issue.loadPullRequest(sess); err != nil {
+			return fmt.Errorf("loadPullRequest: %v", err)
+		}
 		issue.PullRequest.Issue = issue
 		err = PrepareWebhooks(issue.Repo, HookEventPullRequest, &api.PullRequestPayload{
 			Action: api.HookIssueEdited,
@@ -1099,8 +1141,8 @@ func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, assigneeIDs []in
 	return nil
 }
 
-// GetRawIssueByIndex returns raw issue without loading attributes by index in a repository.
-func GetRawIssueByIndex(repoID, index int64) (*Issue, error) {
+// GetIssueByIndex returns raw issue without loading attributes by index in a repository.
+func GetIssueByIndex(repoID, index int64) (*Issue, error) {
 	issue := &Issue{
 		RepoID: repoID,
 		Index:  index,
@@ -1114,9 +1156,9 @@ func GetRawIssueByIndex(repoID, index int64) (*Issue, error) {
 	return issue, nil
 }
 
-// GetIssueByIndex returns issue by index in a repository.
-func GetIssueByIndex(repoID, index int64) (*Issue, error) {
-	issue, err := GetRawIssueByIndex(repoID, index)
+// GetIssueWithAttrsByIndex returns issue by index in a repository.
+func GetIssueWithAttrsByIndex(repoID, index int64) (*Issue, error) {
+	issue, err := GetIssueByIndex(repoID, index)
 	if err != nil {
 		return nil, err
 	}
@@ -1131,7 +1173,16 @@ func getIssueByID(e Engine, id int64) (*Issue, error) {
 	} else if !has {
 		return nil, ErrIssueNotExist{id, 0, 0}
 	}
-	return issue, issue.loadAttributes(e)
+	return issue, nil
+}
+
+// GetIssueWithAttrsByID returns an issue with attributes by given ID.
+func GetIssueWithAttrsByID(id int64) (*Issue, error) {
+	issue, err := getIssueByID(x, id)
+	if err != nil {
+		return nil, err
+	}
+	return issue, issue.loadAttributes(x)
 }
 
 // GetIssueByID returns an issue by given ID.
diff --git a/models/issue_assignees.go b/models/issue_assignees.go
index f330ade1c8..753396e39b 100644
--- a/models/issue_assignees.go
+++ b/models/issue_assignees.go
@@ -174,7 +174,7 @@ func (issue *Issue) changeAssignee(sess *xorm.Session, doer *User, assigneeID in
 		apiPullRequest := &api.PullRequestPayload{
 			Index:       issue.Index,
 			PullRequest: issue.PullRequest.APIFormat(),
-			Repository:  issue.Repo.APIFormat(mode),
+			Repository:  issue.Repo.innerAPIFormat(sess, mode, false),
 			Sender:      doer.APIFormat(),
 		}
 		if removed {
@@ -191,8 +191,8 @@ func (issue *Issue) changeAssignee(sess *xorm.Session, doer *User, assigneeID in
 
 		apiIssue := &api.IssuePayload{
 			Index:      issue.Index,
-			Issue:      issue.APIFormat(),
-			Repository: issue.Repo.APIFormat(mode),
+			Issue:      issue.apiFormat(sess),
+			Repository: issue.Repo.innerAPIFormat(sess, mode, false),
 			Sender:     doer.APIFormat(),
 		}
 		if removed {
diff --git a/models/issue_assignees_test.go b/models/issue_assignees_test.go
index 3247812198..029c211a4b 100644
--- a/models/issue_assignees_test.go
+++ b/models/issue_assignees_test.go
@@ -14,7 +14,7 @@ func TestUpdateAssignee(t *testing.T) {
 	assert.NoError(t, PrepareTestDatabase())
 
 	// Fake issue with assignees
-	issue, err := GetIssueByID(1)
+	issue, err := GetIssueWithAttrsByID(1)
 	assert.NoError(t, err)
 
 	// Assign multiple users
diff --git a/models/issue_comment.go b/models/issue_comment.go
index 96b162ca19..577de1d84d 100644
--- a/models/issue_comment.go
+++ b/models/issue_comment.go
@@ -150,25 +150,6 @@ func (c *Comment) LoadIssue() (err error) {
 	return
 }
 
-// AfterLoad is invoked from XORM after setting the values of all fields of this object.
-func (c *Comment) AfterLoad(session *xorm.Session) {
-	var err error
-	c.Attachments, err = getAttachmentsByCommentID(session, c.ID)
-	if err != nil {
-		log.Error(3, "getAttachmentsByCommentID[%d]: %v", c.ID, err)
-	}
-
-	c.Poster, err = getUserByID(session, c.PosterID)
-	if err != nil {
-		if IsErrUserNotExist(err) {
-			c.PosterID = -1
-			c.Poster = NewGhostUser()
-		} else {
-			log.Error(3, "getUserByID[%d]: %v", c.ID, err)
-		}
-	}
-}
-
 // AfterDelete is invoked from XORM after the object is deleted.
 func (c *Comment) AfterDelete() {
 	if c.ID <= 0 {
@@ -189,6 +170,11 @@ func (c *Comment) HTMLURL() string {
 		log.Error(4, "LoadIssue(%d): %v", c.IssueID, err)
 		return ""
 	}
+	err = c.Issue.loadRepo(x)
+	if err != nil { // Silently dropping errors :unamused:
+		log.Error(4, "loadRepo(%d): %v", c.Issue.RepoID, err)
+		return ""
+	}
 	if c.Type == CommentTypeCode {
 		if c.ReviewID == 0 {
 			return fmt.Sprintf("%s/files#%s", c.Issue.HTMLURL(), c.HashTag())
@@ -217,6 +203,12 @@ func (c *Comment) IssueURL() string {
 	if c.Issue.IsPull {
 		return ""
 	}
+
+	err = c.Issue.loadRepo(x)
+	if err != nil { // Silently dropping errors :unamused:
+		log.Error(4, "loadRepo(%d): %v", c.Issue.RepoID, err)
+		return ""
+	}
 	return c.Issue.HTMLURL()
 }
 
@@ -228,6 +220,12 @@ func (c *Comment) PRURL() string {
 		return ""
 	}
 
+	err = c.Issue.loadRepo(x)
+	if err != nil { // Silently dropping errors :unamused:
+		log.Error(4, "loadRepo(%d): %v", c.Issue.RepoID, err)
+		return ""
+	}
+
 	if !c.Issue.IsPull {
 		return ""
 	}
@@ -303,6 +301,39 @@ func (c *Comment) LoadMilestone() error {
 	return nil
 }
 
+// LoadPoster loads comment poster
+func (c *Comment) LoadPoster() error {
+	if c.PosterID <= 0 || c.Poster != nil {
+		return nil
+	}
+
+	var err error
+	c.Poster, err = getUserByID(x, c.PosterID)
+	if err != nil {
+		if IsErrUserNotExist(err) {
+			c.PosterID = -1
+			c.Poster = NewGhostUser()
+		} else {
+			log.Error(3, "getUserByID[%d]: %v", c.ID, err)
+		}
+	}
+	return nil
+}
+
+// LoadAttachments loads attachments
+func (c *Comment) LoadAttachments() error {
+	if len(c.Attachments) > 0 {
+		return nil
+	}
+
+	var err error
+	c.Attachments, err = getAttachmentsByCommentID(x, c.ID)
+	if err != nil {
+		log.Error(3, "getAttachmentsByCommentID[%d]: %v", c.ID, err)
+	}
+	return nil
+}
+
 // LoadAssigneeUser if comment.Type is CommentTypeAssignees, then load assignees
 func (c *Comment) LoadAssigneeUser() error {
 	var err error
@@ -375,8 +406,10 @@ func (c *Comment) LoadReactions() error {
 }
 
 func (c *Comment) loadReview(e Engine) (err error) {
-	if c.Review, err = getReviewByID(e, c.ReviewID); err != nil {
-		return err
+	if c.Review == nil {
+		if c.Review, err = getReviewByID(e, c.ReviewID); err != nil {
+			return err
+		}
 	}
 	return nil
 }
@@ -454,6 +487,11 @@ func (c *Comment) CodeCommentURL() string {
 		log.Error(4, "LoadIssue(%d): %v", c.IssueID, err)
 		return ""
 	}
+	err = c.Issue.loadRepo(x)
+	if err != nil { // Silently dropping errors :unamused:
+		log.Error(4, "loadRepo(%d): %v", c.Issue.RepoID, err)
+		return ""
+	}
 	return fmt.Sprintf("%s/files#%s", c.Issue.HTMLURL(), c.HashTag())
 }
 
@@ -601,7 +639,7 @@ func sendCreateCommentAction(e *xorm.Session, opts *CreateCommentOptions, commen
 	return nil
 }
 
-func createStatusComment(e *xorm.Session, doer *User, repo *Repository, issue *Issue) (*Comment, error) {
+func createStatusComment(e *xorm.Session, doer *User, issue *Issue) (*Comment, error) {
 	cmtType := CommentTypeClose
 	if !issue.IsClosed {
 		cmtType = CommentTypeReopen
@@ -609,7 +647,7 @@ func createStatusComment(e *xorm.Session, doer *User, repo *Repository, issue *I
 	return createComment(e, &CreateCommentOptions{
 		Type:  cmtType,
 		Doer:  doer,
-		Repo:  repo,
+		Repo:  issue.Repo,
 		Issue: issue,
 	})
 }
@@ -983,6 +1021,9 @@ func UpdateComment(doer *User, c *Comment, oldContent string) error {
 		UpdateIssueIndexer(c.IssueID)
 	}
 
+	if err := c.LoadPoster(); err != nil {
+		return err
+	}
 	if err := c.LoadIssue(); err != nil {
 		return err
 	}
@@ -1040,6 +1081,9 @@ func DeleteComment(doer *User, comment *Comment) error {
 		UpdateIssueIndexer(comment.IssueID)
 	}
 
+	if err := comment.LoadPoster(); err != nil {
+		return err
+	}
 	if err := comment.LoadIssue(); err != nil {
 		return err
 	}
@@ -1095,6 +1139,10 @@ func fetchCodeCommentsByReview(e Engine, issue *Issue, currentUser *User, review
 		return nil, err
 	}
 
+	if err := CommentList(comments).loadPosters(e); err != nil {
+		return nil, err
+	}
+
 	if err := issue.loadRepo(e); err != nil {
 		return nil, err
 	}
diff --git a/models/issue_comment_list.go b/models/issue_comment_list.go
new file mode 100644
index 0000000000..35c1253f6b
--- /dev/null
+++ b/models/issue_comment_list.go
@@ -0,0 +1,58 @@
+// Copyright 2018 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package models
+
+// CommentList defines a list of comments
+type CommentList []*Comment
+
+func (comments CommentList) getPosterIDs() []int64 {
+	commentIDs := make(map[int64]struct{}, len(comments))
+	for _, comment := range comments {
+		if _, ok := commentIDs[comment.PosterID]; !ok {
+			commentIDs[comment.PosterID] = struct{}{}
+		}
+	}
+	return keysInt64(commentIDs)
+}
+
+// LoadPosters loads posters from database
+func (comments CommentList) LoadPosters() error {
+	return comments.loadPosters(x)
+}
+
+func (comments CommentList) loadPosters(e Engine) error {
+	if len(comments) == 0 {
+		return nil
+	}
+
+	posterIDs := comments.getPosterIDs()
+	posterMaps := make(map[int64]*User, len(posterIDs))
+	var left = len(posterIDs)
+	for left > 0 {
+		var limit = defaultMaxInSize
+		if left < limit {
+			limit = left
+		}
+		err := e.
+			In("id", posterIDs[:limit]).
+			Find(&posterMaps)
+		if err != nil {
+			return err
+		}
+		left = left - limit
+		posterIDs = posterIDs[limit:]
+	}
+
+	for _, comment := range comments {
+		if comment.PosterID <= 0 {
+			continue
+		}
+		var ok bool
+		if comment.Poster, ok = posterMaps[comment.PosterID]; !ok {
+			comment.Poster = NewGhostUser()
+		}
+	}
+	return nil
+}
diff --git a/models/issue_dependency_test.go b/models/issue_dependency_test.go
index 571bce3184..deb5dbcad7 100644
--- a/models/issue_dependency_test.go
+++ b/models/issue_dependency_test.go
@@ -19,8 +19,11 @@ func TestCreateIssueDependency(t *testing.T) {
 
 	issue1, err := GetIssueByID(1)
 	assert.NoError(t, err)
+	issue1.LoadAttributes()
+
 	issue2, err := GetIssueByID(2)
 	assert.NoError(t, err)
+	issue2.LoadAttributes()
 
 	// Create a dependency and check if it was successful
 	err = CreateIssueDependency(user1, issue1, issue2)
@@ -44,7 +47,7 @@ func TestCreateIssueDependency(t *testing.T) {
 	assert.False(t, left)
 
 	// Close #2 and check again
-	err = issue2.ChangeStatus(user1, issue2.Repo, true)
+	err = issue2.ChangeStatus(user1, true)
 	assert.NoError(t, err)
 
 	left, err = IssueNoDependenciesLeft(issue1)
diff --git a/models/issue_mail.go b/models/issue_mail.go
index b78da6d79a..7f780e667e 100644
--- a/models/issue_mail.go
+++ b/models/issue_mail.go
@@ -39,7 +39,7 @@ func mailIssueCommentToParticipants(e Engine, issue *Issue, doer *User, content
 
 	// In case the issue poster is not watching the repository and is active,
 	// even if we have duplicated in watchers, can be safely filtered out.
-	poster, err := GetUserByID(issue.PosterID)
+	poster, err := getUserByID(e, issue.PosterID)
 	if err != nil {
 		return fmt.Errorf("GetUserByID [%d]: %v", issue.PosterID, err)
 	}
diff --git a/models/issue_stopwatch.go b/models/issue_stopwatch.go
index 178b76c5dd..d754e7e19e 100644
--- a/models/issue_stopwatch.go
+++ b/models/issue_stopwatch.go
@@ -49,6 +49,10 @@ func CreateOrStopIssueStopwatch(user *User, issue *Issue) error {
 	if err != nil {
 		return err
 	}
+	if err := issue.loadRepo(x); err != nil {
+		return err
+	}
+
 	if exists {
 		// Create tracked time out of the time difference between start date and actual date
 		timediff := time.Now().Unix() - int64(sw.CreatedUnix)
@@ -112,6 +116,10 @@ func CancelStopwatch(user *User, issue *Issue) error {
 			return err
 		}
 
+		if err := issue.loadRepo(x); err != nil {
+			return err
+		}
+
 		if _, err := CreateComment(&CreateCommentOptions{
 			Doer:  user,
 			Issue: issue,
diff --git a/models/issue_tracked_time.go b/models/issue_tracked_time.go
index 6592f06d73..bb3e767127 100644
--- a/models/issue_tracked_time.go
+++ b/models/issue_tracked_time.go
@@ -90,6 +90,9 @@ func AddTime(user *User, issue *Issue, time int64) (*TrackedTime, error) {
 	if _, err := x.Insert(tt); err != nil {
 		return nil, err
 	}
+	if err := issue.loadRepo(x); err != nil {
+		return nil, err
+	}
 	if _, err := CreateComment(&CreateCommentOptions{
 		Issue:   issue,
 		Repo:    issue.Repo,
diff --git a/models/mail.go b/models/mail.go
index 6b69e7b2ad..7e6d4e0265 100644
--- a/models/mail.go
+++ b/models/mail.go
@@ -151,6 +151,7 @@ func composeTplData(subject, body, link string) map[string]interface{} {
 
 func composeIssueCommentMessage(issue *Issue, doer *User, content string, comment *Comment, tplName base.TplName, tos []string, info string) *mailer.Message {
 	subject := issue.mailSubject()
+	issue.LoadRepo()
 	body := string(markup.RenderByType(markdown.MarkupName, []byte(content), issue.Repo.HTMLURL(), issue.Repo.ComposeMetas()))
 
 	data := make(map[string]interface{}, 10)
diff --git a/models/pull.go b/models/pull.go
index 0041f83dc8..0d8886186e 100644
--- a/models/pull.go
+++ b/models/pull.go
@@ -148,6 +148,10 @@ func (pr *PullRequest) GetGitRefName() string {
 // Required - Issue
 // Optional - Merger
 func (pr *PullRequest) APIFormat() *api.PullRequest {
+	return pr.apiFormat(x)
+}
+
+func (pr *PullRequest) apiFormat(e Engine) *api.PullRequest {
 	var (
 		baseBranch *Branch
 		headBranch *Branch
@@ -155,16 +159,20 @@ func (pr *PullRequest) APIFormat() *api.PullRequest {
 		headCommit *git.Commit
 		err        error
 	)
-	apiIssue := pr.Issue.APIFormat()
+	if err = pr.Issue.loadRepo(e); err != nil {
+		log.Error(log.ERROR, "loadRepo[%d]: %v", pr.ID, err)
+		return nil
+	}
+	apiIssue := pr.Issue.apiFormat(e)
 	if pr.BaseRepo == nil {
-		pr.BaseRepo, err = GetRepositoryByID(pr.BaseRepoID)
+		pr.BaseRepo, err = getRepositoryByID(e, pr.BaseRepoID)
 		if err != nil {
 			log.Error(log.ERROR, "GetRepositoryById[%d]: %v", pr.ID, err)
 			return nil
 		}
 	}
 	if pr.HeadRepo == nil {
-		pr.HeadRepo, err = GetRepositoryByID(pr.HeadRepoID)
+		pr.HeadRepo, err = getRepositoryByID(e, pr.HeadRepoID)
 		if err != nil {
 			log.Error(log.ERROR, "GetRepositoryById[%d]: %v", pr.ID, err)
 			return nil
@@ -187,15 +195,18 @@ func (pr *PullRequest) APIFormat() *api.PullRequest {
 		Ref:        pr.BaseBranch,
 		Sha:        baseCommit.ID.String(),
 		RepoID:     pr.BaseRepoID,
-		Repository: pr.BaseRepo.APIFormat(AccessModeNone),
+		Repository: pr.BaseRepo.innerAPIFormat(e, AccessModeNone, false),
 	}
 	apiHeadBranchInfo := &api.PRBranchInfo{
 		Name:       pr.HeadBranch,
 		Ref:        pr.HeadBranch,
 		Sha:        headCommit.ID.String(),
 		RepoID:     pr.HeadRepoID,
-		Repository: pr.HeadRepo.APIFormat(AccessModeNone),
+		Repository: pr.HeadRepo.innerAPIFormat(e, AccessModeNone, false),
 	}
+
+	pr.Issue.loadRepo(e)
+
 	apiPullRequest := &api.PullRequest{
 		ID:        pr.ID,
 		Index:     pr.Index,
@@ -542,7 +553,7 @@ func (pr *PullRequest) setMerged() (err error) {
 		return err
 	}
 
-	if err = pr.Issue.changeStatus(sess, pr.Merger, pr.Issue.Repo, true); err != nil {
+	if err = pr.Issue.changeStatus(sess, pr.Merger, true); err != nil {
 		return fmt.Errorf("Issue.changeStatus: %v", err)
 	}
 	if _, err = sess.ID(pr.ID).Cols("has_merged, status, merged_commit_id, merger_id, merged_unix").Update(pr); err != nil {
diff --git a/models/update.go b/models/update.go
index 0f71cd1e70..9cd4d0d977 100644
--- a/models/update.go
+++ b/models/update.go
@@ -51,7 +51,7 @@ func ListToPushCommits(l *list.List) *PushCommits {
 		}
 		commits = append(commits, CommitToPushCommit(commit))
 	}
-	return &PushCommits{l.Len(), commits, "", nil}
+	return &PushCommits{l.Len(), commits, "", make(map[string]string), make(map[string]*User)}
 }
 
 // PushUpdateOptions defines the push update options
diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go
index 7a8ed09b48..65c97888f5 100644
--- a/routers/api/v1/repo/issue.go
+++ b/routers/api/v1/repo/issue.go
@@ -175,6 +175,7 @@ func CreateIssue(ctx *context.APIContext, form api.CreateIssueOption) {
 
 	issue := &models.Issue{
 		RepoID:       ctx.Repo.Repository.ID,
+		Repo:         ctx.Repo.Repository,
 		Title:        form.Title,
 		PosterID:     ctx.User.ID,
 		Poster:       ctx.User,
@@ -212,7 +213,7 @@ func CreateIssue(ctx *context.APIContext, form api.CreateIssueOption) {
 	notification.NotifyNewIssue(issue)
 
 	if form.Closed {
-		if err := issue.ChangeStatus(ctx.User, ctx.Repo.Repository, true); err != nil {
+		if err := issue.ChangeStatus(ctx.User, true); err != nil {
 			if models.IsErrDependenciesLeft(err) {
 				ctx.Error(http.StatusPreconditionFailed, "DependenciesLeft", "cannot close this issue because it still has open dependencies")
 				return
@@ -273,6 +274,7 @@ func EditIssue(ctx *context.APIContext, form api.EditIssueOption) {
 		}
 		return
 	}
+	issue.Repo = ctx.Repo.Repository
 
 	if !issue.IsPoster(ctx.User.ID) && !ctx.Repo.CanWrite(models.UnitTypeIssues) {
 		ctx.Status(403)
@@ -333,7 +335,7 @@ func EditIssue(ctx *context.APIContext, form api.EditIssueOption) {
 		return
 	}
 	if form.State != nil {
-		if err = issue.ChangeStatus(ctx.User, ctx.Repo.Repository, api.StateClosed == api.StateType(*form.State)); err != nil {
+		if err = issue.ChangeStatus(ctx.User, api.StateClosed == api.StateType(*form.State)); err != nil {
 			if models.IsErrDependenciesLeft(err) {
 				ctx.Error(http.StatusPreconditionFailed, "DependenciesLeft", "cannot close this issue because it still has open dependencies")
 				return
diff --git a/routers/api/v1/repo/issue_comment.go b/routers/api/v1/repo/issue_comment.go
index 3af0290585..a3fc6f41f3 100644
--- a/routers/api/v1/repo/issue_comment.go
+++ b/routers/api/v1/repo/issue_comment.go
@@ -51,7 +51,7 @@ func ListIssueComments(ctx *context.APIContext) {
 	}
 
 	// comments,err:=models.GetCommentsByIssueIDSince(, since)
-	issue, err := models.GetRawIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
+	issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
 	if err != nil {
 		ctx.Error(500, "GetRawIssueByIndex", err)
 		return
@@ -68,6 +68,10 @@ func ListIssueComments(ctx *context.APIContext) {
 	}
 
 	apiComments := make([]*api.Comment, len(comments))
+	if err = models.CommentList(comments).LoadPosters(); err != nil {
+		ctx.Error(500, "LoadPosters", err)
+		return
+	}
 	for i := range comments {
 		apiComments[i] = comments[i].APIFormat()
 	}
@@ -114,6 +118,11 @@ func ListRepoIssueComments(ctx *context.APIContext) {
 		return
 	}
 
+	if err = models.CommentList(comments).LoadPosters(); err != nil {
+		ctx.Error(500, "LoadPosters", err)
+		return
+	}
+
 	apiComments := make([]*api.Comment, len(comments))
 	for i := range comments {
 		apiComments[i] = comments[i].APIFormat()
diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go
index 9fbadcd076..2ad321ea38 100644
--- a/routers/api/v1/repo/pull.go
+++ b/routers/api/v1/repo/pull.go
@@ -350,6 +350,7 @@ func EditPullRequest(ctx *context.APIContext, form api.EditPullRequestOption) {
 
 	pr.LoadIssue()
 	issue := pr.Issue
+	issue.Repo = ctx.Repo.Repository
 
 	if !issue.IsPoster(ctx.User.ID) && !ctx.Repo.CanWrite(models.UnitTypePullRequests) {
 		ctx.Status(403)
@@ -383,7 +384,6 @@ func EditPullRequest(ctx *context.APIContext, form api.EditPullRequestOption) {
 	// Send an empty array ([]) to clear all assignees from the Issue.
 
 	if ctx.Repo.CanWrite(models.UnitTypePullRequests) && (form.Assignees != nil || len(form.Assignee) > 0) {
-
 		err = models.UpdateAPIAssignee(issue, form.Assignee, form.Assignees, ctx.User)
 		if err != nil {
 			if models.IsErrUserNotExist(err) {
@@ -422,7 +422,7 @@ func EditPullRequest(ctx *context.APIContext, form api.EditPullRequestOption) {
 		return
 	}
 	if form.State != nil {
-		if err = issue.ChangeStatus(ctx.User, ctx.Repo.Repository, api.StateClosed == api.StateType(*form.State)); err != nil {
+		if err = issue.ChangeStatus(ctx.User, api.StateClosed == api.StateType(*form.State)); err != nil {
 			if models.IsErrDependenciesLeft(err) {
 				ctx.Error(http.StatusPreconditionFailed, "DependenciesLeft", "cannot close this pull request because it still has open dependencies")
 				return
diff --git a/routers/repo/issue.go b/routers/repo/issue.go
index e0fb4ac52f..3600120fb5 100644
--- a/routers/repo/issue.go
+++ b/routers/repo/issue.go
@@ -576,6 +576,12 @@ func ViewIssue(ctx *context.Context) {
 	ctx.Data["RequireTribute"] = true
 	renderAttachmentSettings(ctx)
 
+	err = issue.LoadAttributes()
+	if err != nil {
+		ctx.ServerError("GetIssueByIndex", err)
+		return
+	}
+
 	ctx.Data["Title"] = fmt.Sprintf("#%d - %s", issue.Index, issue.Title)
 
 	var iw *models.IssueWatch
@@ -677,6 +683,10 @@ func ViewIssue(ctx *context.Context) {
 						ctx.ServerError("GetIssueByID", err)
 						return
 					}
+					if err = otherIssue.LoadRepo(); err != nil {
+						ctx.ServerError("LoadRepo", err)
+						return
+					}
 					// Add link to the issue of the already running stopwatch
 					ctx.Data["OtherStopwatchURL"] = otherIssue.HTMLURL()
 				}
@@ -697,7 +707,17 @@ func ViewIssue(ctx *context.Context) {
 	// Render comments and and fetch participants.
 	participants[0] = issue.Poster
 	for _, comment = range issue.Comments {
+		if err := comment.LoadPoster(); err != nil {
+			ctx.ServerError("LoadPoster", err)
+			return
+		}
+
 		if comment.Type == models.CommentTypeComment {
+			if err := comment.LoadAttachments(); err != nil {
+				ctx.ServerError("LoadAttachments", err)
+				return
+			}
+
 			comment.RenderedContent = string(markdown.Render([]byte(comment.Content), ctx.Repo.RepoLink,
 				ctx.Repo.Repository.ComposeMetas()))
 
@@ -868,6 +888,7 @@ func GetActionIssue(ctx *context.Context) *models.Issue {
 		ctx.NotFoundOrServerError("GetIssueByIndex", models.IsErrIssueNotExist, err)
 		return nil
 	}
+	issue.Repo = ctx.Repo.Repository
 	checkIssueRights(ctx, issue)
 	if ctx.Written() {
 		return nil
@@ -1049,7 +1070,7 @@ func UpdateIssueStatus(ctx *context.Context) {
 	}
 	for _, issue := range issues {
 		if issue.IsClosed != isClosed {
-			if err := issue.ChangeStatus(ctx.User, issue.Repo, isClosed); err != nil {
+			if err := issue.ChangeStatus(ctx.User, isClosed); err != nil {
 				if models.IsErrDependenciesLeft(err) {
 					ctx.JSON(http.StatusPreconditionFailed, map[string]interface{}{
 						"error": "cannot close this issue because it still has open dependencies",
@@ -1126,7 +1147,7 @@ func NewComment(ctx *context.Context, form auth.CreateCommentForm) {
 				ctx.Flash.Info(ctx.Tr("repo.pulls.open_unmerged_pull_exists", pr.Index))
 			} else {
 				isClosed := form.Status == "close"
-				if err := issue.ChangeStatus(ctx.User, ctx.Repo.Repository, isClosed); err != nil {
+				if err := issue.ChangeStatus(ctx.User, isClosed); err != nil {
 					log.Error(4, "ChangeStatus: %v", err)
 
 					if models.IsErrDependenciesLeft(err) {
diff --git a/routers/repo/pull.go b/routers/repo/pull.go
index 4adfb96e74..0d5cec802c 100644
--- a/routers/repo/pull.go
+++ b/routers/repo/pull.go
@@ -223,6 +223,10 @@ func checkPullInfo(ctx *context.Context) *models.Issue {
 		}
 		return nil
 	}
+	if err = issue.LoadPoster(); err != nil {
+		ctx.ServerError("LoadPoster", err)
+		return nil
+	}
 	ctx.Data["Title"] = fmt.Sprintf("#%d - %s", issue.Index, issue.Title)
 	ctx.Data["Issue"] = issue
 
@@ -231,6 +235,11 @@ func checkPullInfo(ctx *context.Context) *models.Issue {
 		return nil
 	}
 
+	if err = issue.LoadPullRequest(); err != nil {
+		ctx.ServerError("LoadPullRequest", err)
+		return nil
+	}
+
 	if err = issue.PullRequest.GetHeadRepo(); err != nil {
 		ctx.ServerError("GetHeadRepo", err)
 		return nil
@@ -519,16 +528,7 @@ func MergePullRequest(ctx *context.Context, form auth.MergePullRequestForm) {
 		return
 	}
 
-	pr, err := models.GetPullRequestByIssueID(issue.ID)
-	if err != nil {
-		if models.IsErrPullRequestNotExist(err) {
-			ctx.NotFound("GetPullRequestByIssueID", nil)
-		} else {
-			ctx.ServerError("GetPullRequestByIssueID", err)
-		}
-		return
-	}
-	pr.Issue = issue
+	pr := issue.PullRequest
 
 	if !pr.CanAutoMerge() || pr.HasMerged {
 		ctx.NotFound("MergePullRequest", nil)
@@ -949,15 +949,7 @@ func CleanUpPullRequest(ctx *context.Context) {
 		return
 	}
 
-	pr, err := models.GetPullRequestByIssueID(issue.ID)
-	if err != nil {
-		if models.IsErrPullRequestNotExist(err) {
-			ctx.NotFound("GetPullRequestByIssueID", nil)
-		} else {
-			ctx.ServerError("GetPullRequestByIssueID", err)
-		}
-		return
-	}
+	pr := issue.PullRequest
 
 	// Allow cleanup only for merged PR
 	if !pr.HasMerged {
@@ -965,7 +957,7 @@ func CleanUpPullRequest(ctx *context.Context) {
 		return
 	}
 
-	if err = pr.GetHeadRepo(); err != nil {
+	if err := pr.GetHeadRepo(); err != nil {
 		ctx.ServerError("GetHeadRepo", err)
 		return
 	} else if pr.HeadRepo == nil {
@@ -1077,8 +1069,12 @@ func DownloadPullDiff(ctx *context.Context) {
 		return
 	}
 
-	pr := issue.PullRequest
+	if err = issue.LoadPullRequest(); err != nil {
+		ctx.ServerError("LoadPullRequest", err)
+		return
+	}
 
+	pr := issue.PullRequest
 	if err = pr.GetBaseRepo(); err != nil {
 		ctx.ServerError("GetBaseRepo", err)
 		return
@@ -1111,8 +1107,12 @@ func DownloadPullPatch(ctx *context.Context) {
 		return
 	}
 
-	pr := issue.PullRequest
+	if err = issue.LoadPullRequest(); err != nil {
+		ctx.ServerError("LoadPullRequest", err)
+		return
+	}
 
+	pr := issue.PullRequest
 	if err = pr.GetHeadRepo(); err != nil {
 		ctx.ServerError("GetHeadRepo", err)
 		return
diff --git a/routers/user/home.go b/routers/user/home.go
index 4c6a9f6cd0..883adf4e6c 100644
--- a/routers/user/home.go
+++ b/routers/user/home.go
@@ -138,6 +138,7 @@ func Dashboard(ctx *context.Context) {
 		OnlyPerformedBy: false,
 		IncludeDeleted:  false,
 	})
+
 	if ctx.Written() {
 		return
 	}