Creating Static Page Database
#models/categorydb.py
import os
import psycopg2

def createTable(): 
  if 'DYNO' in os.environ:
    DATABASE_URL = os.environ['DATABASE_URL']
    conn = psycopg2.connect(DATABASE_URL, sslmode='require')
    cursor = conn.cursor()
  else: 
    conn = psycopg2.connect(
      database="postgres", 
      user="postgres", 
      password="sokhavuth", 
      host="localhost", 
      port="5432"
    )

    cursor = conn.cursor()

  SQL = '''CREATE TABLE IF NOT EXISTS PAGE(
  ID TEXT,
  TITLE TEXT,
  AUTHOR TEXT,
  POSTDATE DATE,
  POSTTIME TIME,
  CONTENT TEXT
  )'''

  cursor.execute(SQL)
  
  conn.commit()
  conn.close()

def insert(*post):
  createTable()
  if 'DYNO' in os.environ:
    DATABASE_URL = os.environ['DATABASE_URL']
    conn = psycopg2.connect(DATABASE_URL, sslmode='require')
    cursor = conn.cursor()
  else: 
    conn = psycopg2.connect(
      database="postgres", 
      user="postgres", 
      password="sokhavuth", 
      host="localhost", 
      port="5432"
    )

    cursor = conn.cursor()

  cursor.execute("INSERT INTO PAGE (ID, TITLE, AUTHOR, POSTDATE, POSTTIME, CONTENT) VALUES %s ", (post,))
  
  conn.commit()
  conn.close()

def select(amount, id=None, page=0):
  createTable()

  if 'DYNO' in os.environ:
    DATABASE_URL = os.environ['DATABASE_URL']
    conn = psycopg2.connect(DATABASE_URL, sslmode='require')
    cursor = conn.cursor()
  else: 
    conn = psycopg2.connect(
      database="postgres", 
      user="postgres", 
      password="sokhavuth", 
      host="localhost", 
      port="5432"
    )

    cursor = conn.cursor()
  if id and (amount == 1):
    cursor.execute("SELECT * FROM PAGE WHERE ID = '" + str(id) +"'")
  elif page:
    SQL = "SELECT * FROM PAGE ORDER BY POSTDATE DESC, POSTTIME DESC OFFSET %s ROWS FETCH NEXT %s ROWS ONLY"
    cursor.execute(SQL, (amount*page, amount))
  elif amount == 'all':
    cursor.execute("SELECT * FROM PAGE ORDER BY POSTDATE DESC, POSTTIME DESC")
  else:
    cursor.execute("SELECT * FROM PAGE ORDER BY POSTDATE DESC, POSTTIME DESC LIMIT " + str(amount))
    
  result = cursor.fetchall()
  return result

def check(username):
  if 'DYNO' in os.environ:
    DATABASE_URL = os.environ['DATABASE_URL']
    conn = psycopg2.connect(DATABASE_URL, sslmode='require')
    cursor = conn.cursor()
  else: 
    conn = psycopg2.connect(
      database="postgres", 
      user="postgres", 
      password="sokhavuth", 
      host="localhost", 
      port="5432"
    )

    cursor = conn.cursor()

  cursor.execute("SELECT USERNAME FROM USERS WHERE USERNAME = '"+ username + "' LIMIT 1")
  result = cursor.fetchone()
  if result:
    return True
  else:
    return False

def delete(id):
  if 'DYNO' in os.environ:
    DATABASE_URL = os.environ['DATABASE_URL']
    conn = psycopg2.connect(DATABASE_URL, sslmode='require')
    cursor = conn.cursor()
  else: 
    conn = psycopg2.connect(
      database="postgres", 
      user="postgres", 
      password="sokhavuth", 
      host="localhost", 
      port="5432"
    )

    cursor = conn.cursor()

  cursor.execute("DELETE FROM PAGE WHERE ID = '" + str(id) + "'")

  conn.commit()
  conn.close()

def update(*args):
  if 'DYNO' in os.environ:
    DATABASE_URL = os.environ['DATABASE_URL']
    conn = psycopg2.connect(DATABASE_URL, sslmode='require')
    cursor = conn.cursor()
  else: 
    conn = psycopg2.connect(
      database="postgres", 
      user="postgres", 
      password="sokhavuth", 
      host="localhost", 
      port="5432"
    )

    cursor = conn.cursor()

  sql = "UPDATE PAGE SET TITLE = %s, POSTDATE = %s, POSTTIME = %s, CONTENT = %s WHERE ID = '%s' "
  
  cursor.execute(sql, args)
  
  conn.commit()
  conn.close()
#controllers/category.py
import config, lib, datetime, uuid
from pytz import timezone
from bottle import route, template, request, redirect, response
from models import pagedb

def getTimeZone():
  khtz = timezone('Asia/Phnom_Penh')
  date = datetime.datetime.now().astimezone(tz=khtz).strftime('%d-%m-%Y')
  time = datetime.datetime.now().astimezone(tz=khtz).strftime('%H:%M:%S')
  return (date, time)

@route('/page')
def post():
  config.kargs['blogTitle'] = "ទំព័រ​ស្តាទិក"
  config.kargs['posts'] = pagedb.select(config.kargs['dashboardPostLimit'])
  config.kargs['thumbs'] = lib.getPostThumbs(config.kargs['posts'])
  config.kargs['datetime'] = getTimeZone()
  config.kargs['page'] = 1
  author = request.get_cookie("logged-in", secret=config.kargs['secretKey'])
  if author:
    config.kargs['author'] = author
    config.kargs['showEdit'] = True

  return template('dashboard/page', data=config.kargs)

@route('/page/<id:int>')
def post(id):
  config.kargs['blogTitle'] = "ទំព័រ​ស្តាទិក"
  config.kargs['post'] = pagedb.select(1, id)
  config.kargs['posts'] = pagedb.select(config.kargs['frontPagePostLimit'])
  config.kargs['thumbs'] = lib.getPostThumbs(config.kargs['posts'])
  config.kargs['page'] = 1
  author = request.get_cookie("logged-in", secret=config.kargs['secretKey'])
  if author:
    config.kargs['showEdit'] = True

  return template('page', data=config.kargs)

@route('/paging', method="POST")
def posting():
  author = request.get_cookie("logged-in", secret=config.kargs['secretKey'])
  if ((author != "Guest") and pagedb.check(author)):
    title = request.forms.getunicode('fpost-title')
    if title == "":
      title = "untitled"

    postdate = request.forms.getunicode('fpost-date')
    posttime = request.forms.getunicode('fpost-time')
    content = request.forms.getunicode('fcontent')

    try:
      postdate = datetime.datetime.strptime(postdate, "%d-%m-%Y")
    except ValueError:
      config.kargs['message'] = 'ទំរង់​កាលបរិច្ឆេទ​មិន​ត្រឹមត្រូវ!'
      return template('dashboard/category', data=config.kargs)

    try:
      posttime = datetime.datetime.strptime(posttime, "%H:%M:%S")
    except ValueError:
      config.kargs['message'] = 'ទំរង់​ពេល​វេលា​មិន​ត្រឹមត្រូវ!'
      return template('dashboard/category', data=config.kargs)

    if 'postId' in config.kargs:
      id = config.kargs['postId']
      pagedb.update(title, postdate, posttime, content, id)
      del config.kargs['postId']
    else:
      pagedb.insert(str(uuid.uuid4().int), title, author, postdate, posttime, content)
  
  redirect('/page')

@route('/page/delete/<id:int>')
def delete(id):
  author = request.get_cookie("logged-in", secret=config.kargs['secretKey'])
  if ((author != "Guest") and pagedb.check(author)):
    pagedb.delete(id)

  redirect('/page')

@route('/page/edit/<id:int>')
def edit(id):
  author = request.get_cookie("logged-in", secret=config.kargs['secretKey'])
  if ((author != "Guest") and pagedb.check(author)):
    config.kargs['blogTitle'] = "ទំព័រ​កែ​តំរូវ"
    config.kargs['posts'] = pagedb.select(config.kargs['dashboardPostLimit'])
    config.kargs['thumbs'] = lib.getPostThumbs(config.kargs['posts'])
    config.kargs['post'] = pagedb.select(1, id)
    config.kargs['edit'] = True
    config.kargs['postId'] = id
    config.kargs['page'] = 1
    return template('dashboard/page', data=config.kargs)
  
  redirect('/page')

@route('/page/paginate')
def paginate():
  postLimit = config.kargs['dashboardPostLimit']
  posts = pagedb.select(postLimit, page=config.kargs['page'])
  
  def toString(post):
    post[3] = post[3].strftime('%d-%m-%Y')
    post[4] = post[4].strftime('%H:%M:%S')

  if posts:
    config.kargs['page'] += 1
    posts = [list(obj) for obj in posts ]

    [toString(obj) for obj in posts]
    thumbs = lib.getPostThumbs(posts)
    print(posts)
    return {'json':posts, 'thumbs':thumbs}
  else:
    return {'json':0}
<!--views/partials/footer.tpl-->
<style>
.footer{
  min-height: 150px;
  background:  lavender;
  padding: 0px;
  box-sizing: border-box;
  margin: 15px auto;
}
.post-panel{
  padding: 15px;
  font: 16px/1.5 Oswald, Limonf3;
  display: grid;
  grid-template-columns: calc(25% - 11.25px) calc(25% - 11.25px) calc(25% - 11.25px) calc(25% - 11.25px);
  grid-gap: 15px;
  margin-bottom: 15px;
}
.post-panel:last-child{
  margin-bottom: 0;
}
.post-panel .post-thumb{
  display: block;
  overflow: hidden;
}
.post-panel .post-thumb img{
  width: 100%;
  min-height: 100%;
  float: left;
  margin-bottom: 5px;
}
.post-panel .post-title{
  text-align: left;
  display: block;
}
.post-panel .post-author{
  text-align: right;
}
.post-panel .post-date{
  font: bold 14px/1.5 'Lucida Sans';
}
@media only screen and (max-width: 600px){
  .post-panel{
    grid-template-columns: 100%;
  }
}
#pagination{
  text-align: center;
  padding: 0 0 5px;
}
#pagination img:hover{
  opacity: .5;
  cursor: pointer;
}
</style>
      <footer class="footer region">
        <div class="post-panel">
        %if 'posts' in data:
          %for v in range(len(data['posts'])):
            <div class="post-outer">
              <a class="post-thumb" href="/page/{{data['posts'][v][0]}}"><img src="{{data['thumbs'][v]}}" /></a>
                <a class="post-title" href="/page/{{data['posts'][v][0]}}">{{data['posts'][v][1]}}</a>
                %postdate = data['posts'][v][3].strftime("%d-%m-%Y")
                <div class="post-date">{{postdate}}</div>
            </div>
          %end
        %end
        </div>
        <div id="pagination">
          <img onclick="paginate()" src="/static/images/load-more.png" />
        </div>
        <script>
          function paginate(){
            $('#pagination img').attr('src', '/static/images/loading.gif');
            $.get("/page/paginate", function(data, status){
              if((status=='success') && data.json){
                var posts = data.json;
                var thumbs = data.thumbs;
                var html = '';

                for(var index in posts){
                  html += '<div class="post-outer">';
                  html += `<a class="post-thumb" href="/page/${posts[index][0]}"><img src="${thumbs[index]}" /></a>`;
                  html += `<a class="post-title" href="/page/${posts[index][0]}">${posts[index][1]}</a>`;
                  html += `<div class="post-date">${posts[index][3]}</div>`;
                  html += '</div>';
                }

                $('.post-panel').append(html);

                var width = $('footer .post-thumb img').css('width');
                var height = parseInt(width) / 16 * 9;
                $('footer .post-thumb').css({'height':height});
              }

              $('#pagination img').attr('src', '/static/images/load-more.png');

            });
          }

          var width = $('footer .post-thumb img').css('width');
          var height = parseInt(width) / 16 * 9;
          $('footer .post-thumb').css({'height':height});

          $(window).resize(function(){
            var width = $('footer .post-thumb img').css('width');
            var height = parseInt(width) / 16 * 9;
            $('footer .post-thumb').css({'height':height});
          });
        </script>
      </footer>
    </div><!--site-->
  </body>
</html>

GitHub: https://github.com/Sokhavuth/kwblog
Heroku: https://khmerweb-kwblog.herokuapp.com/