Open In App

Build Blog website using Flask

In this article, we’ll explore how to build a dynamic blog website using Flask, a lightweight and versatile Python web framework. Flask provides developers with the tools needed to create robust web applications, and its simplicity makes it an excellent choice for beginners and experienced developers alike.

Requirements



Packages Required

pip install flask
pip install Flask-SQLAlchemy

File Structure



Steps to Build Blog website using Flask

Step 1: Make a folder name as project2.

Step 2: We need to create 2 folders: “templates”, and “statics”.

Step 3: In templates create a file named an index.html.




<!doctype html>
<html lang="en">
  
<head>
  <!-- Required meta tags -->
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  
  <!-- Bootstrap CSS -->
    integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
  
  <title>Home</title>
</head>
  
<body>
  
  <div id="part1">
    <nav class="navbar navbar-expand-lg navbar-light bg-light">
      <div class="container-fluid">
        <a class="navbar-brand" href="#">Home</a>
        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarScroll"
          aria-controls="navbarScroll" aria-expanded="false" aria-label="Toggle navigation">
          <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarScroll">
          <ul class="navbar-nav me-auto my-2 my-lg-0 navbar-nav-scroll" style="--bs-scroll-height: 100px;">
            <li class="nav-item">
              <a class="nav-link active" aria-current="page" href="/">Home</a>
            </li>
            <li class="nav-item">
              <a class="nav-link active" href="{{ url_for('about') }}">About</a>
            </li>
              
            <li class="nav-item">
              <a class="nav-link active" href="{{ url_for('addpost') }}" tabindex="-1">Add</a>
            </li>
          {% if name != "guest" %}
            <li class="nav-item">
              <a class="nav-link active" href="{{ url_for('signin') }}" tabindex="-1">Signin</a>
            </li>
          {% endif %}
  
          </ul>
          <div class="mx-3">
            {% if name == "guest" %}
              <a class="btn btn-danger" href="{{ url_for('login') }}">Login</a>
                
            {% else %}
              <a class="btn btn-danger" href="#">{{name}}</a>
              <a class="btn btn-danger" href="{{ url_for('logout') }}">Logout</a>
            
            {% endif %}
            
          </div>
        </div>
      </div>
    </nav>
  </div>
  
  <div id="part2">
    <div id="carouselExampleCaptions" class="carousel slide" data-bs-ride="carousel">
      <div class="carousel-indicators">
        <button type="button" data-bs-target="#carouselExampleCaptions" data-bs-slide-to="0" class="active"
          aria-current="true" aria-label="Slide 1"></button>
        <button type="button" data-bs-target="#carouselExampleCaptions" data-bs-slide-to="1"
          aria-label="Slide 2"></button>
      </div>
      <div class="carousel-inner">
        <div class="carousel-item active">
          <img src="../static/home-bg.jpg" class="d-block w-100" alt="...">
          <div class="carousel-caption d-none d-md-block">
            <h5>First slide label</h5>
            <p>Some representative placeholder content for the first slide.</p>
          </div>
        </div>
        <div class="carousel-item">
          <img src="../static/home-bg.jpg" class="d-block w-100" alt="...">
          <div class="carousel-caption d-none d-md-block">
            <h5>Second slide label</h5>
            <p>Some representative placeholder content for the second slide.</p>
          </div>
        </div>
  
      </div>
  
    </div>
  </div>
   
    <div id="part3">
      <div class="album py-5 bg-light">
        <div class="container">
  
          <div class="row row-cols-1 row-cols-sm-2 row-cols-md-3 g-3">
  
  
            <!-- <div class="col">
              <div class="card shadow-sm">
                <svg class="bd-placeholder-img card-img-top" width="100%" height="225"
                  xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Placeholder: Thumbnail"
                  preserveAspectRatio="xMidYMid slice" focusable="false">
                  <title>Placeholder</title>
                  <rect width="100%" height="100%" fill="#55595c"></rect><text x="50%" y="50%" fill="#eceeef"
                    dy=".3em">Thumbnail</text>
                </svg>
  
                <div class="card-body">
                  <h2 class="post-title">
                    GFG Blog
                  </h2>
                  <p class="card-text">This is a wider card with supporting text below as a natural lead-in to
                    additional content. This content is a little bit longer.</p>
                  <div class="d-flex justify-content-between align-items-center">
                    <div class="btn-group">
                      <button type="button" class="btn btn-sm btn-outline-secondary">Edit</button>
                      <button type="button" class="btn btn-sm btn-outline-secondary">Delete</button>
                    </div>
                    <small class="text-muted">9 mins</small>
                  </div>
                </div>
              </div>
            </div> -->
         <!-- loop to show all blogs that are present in the database -->
            {% for articles in article %}
            <div class="col">
              <div class="card shadow-sm">
                <svg class="bd-placeholder-img card-img-top" width="100%" height="225"
                  xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Placeholder: Thumbnail"
                  preserveAspectRatio="xMidYMid slice" focusable="false">
                  <title>Placeholder</title>
                  <rect width="100%" height="100%" fill="#55595c"></rect><text x="50%" y="50%" fill="#eceeef"
                    dy=".3em">Thumbnail</text>
                </svg>
  
                <div class="card-body">
                  <h2 class="post-title">
                    {{ articles.title }}
                  </h2>
                  <p class="card-text">{{articles.content}}</p>
                  <p class="post-meta">Posted by {{ articles.author }} </p>
                  <div class="d-flex justify-content-between align-items-center">
                    <div class="btn-group">
                    <!-- Check if the user is not guest, if guest "edit and delete button will be hidden" -->
                    {% if name != "guest" %}  
                      <a href="/update/{{articles.id}}" type="button" class="btn btn-sm btn-outline-secondary">Edit</a>
                      <a href="/delete/{{articles.id}}" type="button" class="btn btn-sm btn-outline-secondary">Delete</a>
                    {% endif %}
                    </div>
                    <small class="text-muted">{{ articles.post_date.strftime('%B %d, %Y') }}</small>
                  </div>
                </div>
              </div>
            </div>
            {% endfor %}
  
          </div>
        </div>
      </div>
    </div>
    
  
  <div>
  
  </div>
  
  <!-- Optional JavaScript; choose one of the two! -->
  
  <!-- Option 1: Bootstrap Bundle with Popper -->
    integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
    crossorigin="anonymous"></script>
  
</body>
  
</html>

Step 4: Create an about.html page.




<!doctype html>
<html lang="en">
  
<head>
  <!-- Required meta tags -->
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  
  <!-- Bootstrap CSS -->
    integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
  
  <title>About</title>
</head>
  
<body>
  
  <div id="part1">
    <nav class="navbar navbar-expand-lg navbar-light bg-light">
      <div class="container-fluid">
        <a class="navbar-brand" href="#">GFG Blog</a>
        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarScroll"
          aria-controls="navbarScroll" aria-expanded="false" aria-label="Toggle navigation">
          <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarScroll">
          <ul class="navbar-nav me-auto my-2 my-lg-0 navbar-nav-scroll" style="--bs-scroll-height: 100px;">
            <li class="nav-item">
              <a class="nav-link active" aria-current="page" href="/">Home</a>
            </li>
            <li class="nav-item">
              <a class="nav-link" href="./about.html">About</a>
            </li>
  
            <li class="nav-item">
              <a class="nav-link" href="./add.html" tabindex="-1">Add</a>
            </li>
          </ul>
          <form class="d-flex">
            <input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
            <button class="btn btn-outline-success" type="submit">Search</button>
          </form>
        </div>
      </div>
    </nav>
  </div>
  
  <div id="part2">
    <div id="carouselExampleCaptions" class="carousel slide" data-bs-ride="carousel">
      <div class="carousel-indicators">
        <button type="button" data-bs-target="#carouselExampleCaptions" data-bs-slide-to="0" class="active"
          aria-current="true" aria-label="Slide 1"></button>
      </div>
      <div class="carousel-inner">
        <div class="carousel-item active">
          <img src="../static/about-bg.jpg" class="d-block w-100" alt="...">
          <div class="carousel-caption d-none d-md-block">
            <h5>About Me</h5>
            <p>Some representative placeholder content for the first slide.</p>
          </div>
        </div>
  
      </div>
  
    </div>
  </div>
  
  <div class="container">
    <p class="lead ">Lorem ipsum, dolor sit amet consectetur adipisicing elit.
      Ipsam ea, quam tempora quibusdam, ullam ex consequuntur illum
      dolor cum, aperiam illo obcaecati facere voluptatibus? Voluptas
      deserunt accusamus eius! Quo velit culpa obcaecati.</p>
  </div>
  
  <div>
  
  </div>
  
  <!-- Optional JavaScript; choose one of the two! -->
  
  <!-- Option 1: Bootstrap Bundle with Popper -->
    integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
    crossorigin="anonymous"></script>
  
  <!-- Option 2: Separate Popper and Bootstrap JS -->
  <!--
    <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.2/dist/umd/popper.min.js" integrity="sha384-IQsoLXl5PILFhosVNubq5LC7Qb9DXgDA9i+tQ8Zj3iwWAwPtgFTxbJ8NT4GN1R8p" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.min.js" integrity="sha384-cVKIPhGWiC2Al4u+LWgxfKTRIcfu0JTxR+EQDz/bgldoEyl4H0zUF0QKbrJ0EcQF" crossorigin="anonymous"></script>
    -->
</body>
  
</html>

Step 5: Create an add.html page.




<!doctype html>
<html lang="en">
  
<head>
  <!-- Required meta tags -->
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  
  <!-- Bootstrap CSS -->
    integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
  
  <title>Add Post</title>
</head>
  
<body>
  
  <div id="part1">
    <nav class="navbar navbar-expand-lg navbar-light bg-light">
      <div class="container-fluid">
        <a class="navbar-brand" href="#">GFG Blog</a>
        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarScroll"
          aria-controls="navbarScroll" aria-expanded="false" aria-label="Toggle navigation">
          <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarScroll">
          <ul class="navbar-nav me-auto my-2 my-lg-0 navbar-nav-scroll" style="--bs-scroll-height: 100px;">
            <li class="nav-item">
              <a class="nav-link active" aria-current="page" href="/">Home</a>
            </li>
            <li class="nav-item">
              <a class="nav-link" href="./about.html">About</a>
            </li>
  
            <li class="nav-item">
              <a class="nav-link" href="./add.html" tabindex="-1">Add</a>
            </li>
          </ul>
          <form class="d-flex">
            <input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
            <button class="btn btn-outline-success" type="submit">Search</button>
          </form>
        </div>
      </div>
    </nav>
  </div>
  
  <div id="part3">
    <div class="container">
      <div class="row">
        <div class="col-lg-8 col-md-10 mx-auto">
          <form name="addForm" id="addForm" method="POST" action="{{ url_for('addpost') }}" novalidate>
            <div class="control-group">
              <div class="form-group floating-label-form-group controls">
                <label>Title</label>
                <input type="text" class="form-control" placeholder="Title" name="title" id="title" required
                  data-validation-required-message="Please enter a title.">
                <p class="help-block text-danger"></p>
              </div>
            </div>
  
            <div class="control-group">
              <div class="form-group col-xs-12 floating-label-form-group controls">
                <label>Author</label>
                <input type="text" class="form-control" placeholder="Author" name="author" id="author" required
                  data-validation-required-message="Please enter your phone number.">
                <p class="help-block text-danger"></p>
              </div>
            </div>
            <div class="control-group">
              <div class="form-group floating-label-form-group controls">
                <label>Blog Content</label>
                <textarea rows="5" class="form-control" placeholder="Blog content" name="content" id="content" required
                  data-validation-required-message="Please enter a message."></textarea>
                <p class="help-block text-danger"></p>
              </div>
            </div>
            <div class="mb-3">
              <label for="formFileSm" class="form-label">Small file input example</label>
              <input class="form-control form-control-sm" id="formFileSm" type="file">
            </div>
            <br>
            <div id="success"></div>
            <div class="form-group">
              <button type="submit" class="btn btn-secondary" id="sendMessageButton">Send</button>
            </div>
          </form>
        </div>
      </div>
    </div>
  </div>
  
  <div>
  
  </div>
  
  <!-- Optional JavaScript; choose one of the two! -->
  
  <!-- Option 1: Bootstrap Bundle with Popper -->
    integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
    crossorigin="anonymous"></script>
  
  <!-- Option 2: Separate Popper and Bootstrap JS -->
  <!--
    <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.2/dist/umd/popper.min.js" integrity="sha384-IQsoLXl5PILFhosVNubq5LC7Qb9DXgDA9i+tQ8Zj3iwWAwPtgFTxbJ8NT4GN1R8p" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.min.js" integrity="sha384-cVKIPhGWiC2Al4u+LWgxfKTRIcfu0JTxR+EQDz/bgldoEyl4H0zUF0QKbrJ0EcQF" crossorigin="anonymous"></script>
    -->
</body>
  
</html>

Step 6: Create a update.html page.




<!doctype html>
<html lang="en">
  
<head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
  
    <!-- Bootstrap CSS -->
        integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
  
    <title>Update Post</title>
</head>
  
<body>
  
    <div id="part1">
        <nav class="navbar navbar-expand-lg navbar-light bg-light">
            <div class="container-fluid">
                <a class="navbar-brand" href="#">GFG Blog</a>
                <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarScroll"
                    aria-controls="navbarScroll" aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="collapse navbar-collapse" id="navbarScroll">
                    <ul class="navbar-nav me-auto my-2 my-lg-0 navbar-nav-scroll" style="--bs-scroll-height: 100px;">
                        <li class="nav-item">
                            <a class="nav-link active" aria-current="page" href="/">Home</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link" href="./about.html">About</a>
                        </li>
  
                        <li class="nav-item">
                            <a class="nav-link" href="./add.html" tabindex="-1">Add</a>
                        </li>
                    </ul>
                    <form class="d-flex">
                        <input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
                        <button class="btn btn-outline-success" type="submit">Search</button>
                    </form>
                </div>
            </div>
        </nav>
    </div>
  
    <div id="part2">
        <div id="carouselExampleCaptions" class="carousel slide" data-bs-ride="carousel">
            <div class="carousel-indicators">
                <button type="button" data-bs-target="#carouselExampleCaptions" data-bs-slide-to="0" class="active"
                    aria-current="true" aria-label="Slide 1"></button>
            </div>
            <div class="carousel-inner">
                <div class="carousel-item active">
                    <img src="../static/about-bg.jpg" class="d-block w-100" alt="...">
                    <div class="carousel-caption d-none d-md-block">
                        <h5>About Me</h5>
                        <p>Some representative placeholder content for the first slide.</p>
                    </div>
                </div>
  
            </div>
  
        </div>
    </div>
  
    <div id="part3">
        <div class="container">
            <div class="row">
                <div class="col-lg-8 col-md-10 mx-auto">
                    <form name="addForm" id="addForm" method="POST" action="/update/{{edit.id}}" novalidate>
                        <div class="control-group">
                            <div class="form-group floating-label-form-group controls">
                                <label>Update Title</label>
                                <input type="text" class="form-control" value="{{edit.title}}" name="title" id="title"
                                    required data-validation-required-message="Please enter a title.">
                                <p class="help-block text-danger"></p>
                            </div>
                        </div>
  
                        <div class="control-group">
                            <div class="form-group col-xs-12 floating-label-form-group controls">
                                <label>Author</label>
                                <input type="text" class="form-control" value="{{edit.author}}" name="author"
                                    id="author" required
                                    data-validation-required-message="Please enter your phone number.">
                                <p class="help-block text-danger"></p>
                            </div>
                        </div>
                        <div class="control-group">
                            <div class="form-group floating-label-form-group controls">
                                <label>Blog Content</label>
  
  
                                <!-- <textarea rows="5" class="form-control"
                                    placeholder="{{edit.content}}" name="content" id="content" required
                                    data-validation-required-message="Please enter a message.">
                                    Geeksforgeeks
                               </textarea> -->
  
                                <input type="text" value="{{edit.content}}" name="content" id="content"
                                    class="form-control">
                                <p class="help-block text-danger"></p>
                            </div>
                        </div>
                        <br>
                        <div id="success"></div>
                        <div class="form-group">
                            <button type="submit" class="btn btn-secondary" id="sendMessageButton">Send</button>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
  
    <div>
  
    </div>
  
    <!-- Optional JavaScript; choose one of the two! -->
  
    <!-- Option 1: Bootstrap Bundle with Popper -->
        integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
        crossorigin="anonymous"></script>
  
    <!-- Option 2: Separate Popper and Bootstrap JS -->
    <!--
    <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.2/dist/umd/popper.min.js" integrity="sha384-IQsoLXl5PILFhosVNubq5LC7Qb9DXgDA9i+tQ8Zj3iwWAwPtgFTxbJ8NT4GN1R8p" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.min.js" integrity="sha384-cVKIPhGWiC2Al4u+LWgxfKTRIcfu0JTxR+EQDz/bgldoEyl4H0zUF0QKbrJ0EcQF" crossorigin="anonymous"></script>
    -->
</body>
  
</html>

Step 7: Create a login.html page.




<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Login</title>
<style>
body {font-family: Arial, Helvetica, sans-serif;}
  
/* Full-width input fields */
input[type=text], input[type=password] {
  width: 100%;
  padding: 12px 20px;
  margin: 8px 0;
  display: inline-block;
  border: 1px solid #ccc;
  box-sizing: border-box;
}
  
/* Set a style for all buttons */
button {
  background-color: #04AA6D;
  color: white;
  padding: 14px 20px;
  margin: 8px 0;
  border: none;
  cursor: pointer;
  width: 100%;
}
  
button:hover {
  opacity: 0.8;
}
  
/* Extra styles for the cancel button */
.cancelbtn {
  width: auto;
  padding: 10px 18px;
  background-color: #f44336;
}
  
/* Center the image and position the close button */
.imgcontainer {
  text-align: center;
  margin: 24px 0 12px 0;
  position: relative;
}
  
img.avatar {
  width: 40%;
  border-radius: 50%;
}
  
.container {
  padding: 16px;
}
  
span.psw {
  float: right;
  padding-top: 16px;
}
  
/* The Modal (background) */
.modal {
  display: none; /* Hidden by default */
  position: fixed; /* Stay in place */
  z-index: 1; /* Sit on top */
  left: 0;
  top: 0;
  width: 100%; /* Full width */
  height: 100%; /* Full height */
  overflow: auto; /* Enable scroll if needed */
  background-color: rgb(0,0,0); /* Fallback color */
  background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
  padding-top: 60px;
}
  
/* Modal Content/Box */
.modal-content {
  background-color: #fefefe;
  margin: 5% auto 15% auto; /* 5% from the top, 15% from 
  the bottom and centered */
  border: 1px solid #888;
  width: 80%; /* Could be more or less, depending on screen size */
}
  
/* The Close Button (x) */
.close {
  position: absolute;
  right: 25px;
  top: 0;
  color: #000;
  font-size: 35px;
  font-weight: bold;
}
  
.close:hover,
.close:focus {
  color: red;
  cursor: pointer;
}
  
/* Add Zoom Animation */
.animate {
  -webkit-animation: animatezoom 0.6s;
  animation: animatezoom 0.6s
}
  
@-webkit-keyframes animatezoom {
  from {-webkit-transform: scale(0)} 
  to {-webkit-transform: scale(1)}
}
    
@keyframes animatezoom {
  from {transform: scale(0)} 
  to {transform: scale(1)}
}
  
/* Change styles for span and cancel button on extra small screens */
@media screen and (max-width: 300px) {
  span.psw {
     display: block;
     float: none;
  }
  .cancelbtn {
     width: 100%;
  }
}
</style>
</head>
<body>
  
    
  <form class="modal-content animate" action="{{ url_for('login') }}" 
        method="POST">
      
    <div class="container">
      <label for="uname"><b>Username</b></label>
      <input type="text" placeholder="Enter Username"
             name="username" id="username" required>
  
      <label for="psw"><b>Password</b></label>
      <input type="password" placeholder="Enter Password" 
             name="password" id="password" required>
          
      <button type="submit">Login</button>
      <label>
        <input type="checkbox" checked="checked" 
               name="remember"> Remember me
      </label>
    </div>
  
    <div class="container" style="background-color:#f1f1f1">
      <button type="button" 
              onclick="document.getElementById('id01').style.display='none'" 
              class="cancelbtn">Cancel</button>
      <span class="psw">Forgot <a href="#">password?</a></span>
    </div>
  </form>
  
  
  
</body>
</html>

Step 8: Create a signin.html page.




<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Signup</title>
  
<style>
body {font-family: Arial, Helvetica, sans-serif;}
  
/* Full-width input fields */
input[type=text], input[type=password] {
  width: 100%;
  padding: 12px 20px;
  margin: 8px 0;
  display: inline-block;
  border: 1px solid #ccc;
  box-sizing: border-box;
}
  
/* Set a style for all buttons */
button {
  background-color: #04AA6D;
  color: white;
  padding: 14px 20px;
  margin: 8px 0;
  border: none;
  cursor: pointer;
  width: 100%;
}
  
button:hover {
  opacity: 0.8;
}
  
/* Extra styles for the cancel button */
.cancelbtn {
  width: auto;
  padding: 10px 18px;
  background-color: #f44336;
}
  
/* Center the image and position the close button */
.imgcontainer {
  text-align: center;
  margin: 24px 0 12px 0;
  position: relative;
}
  
img.avatar {
  width: 40%;
  border-radius: 50%;
}
  
.container {
  padding: 16px;
}
  
span.psw {
  float: right;
  padding-top: 16px;
}
  
/* The Modal (background) */
.modal {
  display: none; /* Hidden by default */
  position: fixed; /* Stay in place */
  z-index: 1; /* Sit on top */
  left: 0;
  top: 0;
  width: 100%; /* Full width */
  height: 100%; /* Full height */
  overflow: auto; /* Enable scroll if needed */
  background-color: rgb(0,0,0); /* Fallback color */
  background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
  padding-top: 60px;
}
  
/* Modal Content/Box */
.modal-content {
  background-color: #fefefe;
  margin: 5% auto 15% auto; /* 5% from the top, 15% 
  from the bottom and centered */
  border: 1px solid #888;
  width: 80%; /* Could be more or less, depending on screen size */
}
  
/* The Close Button (x) */
.close {
  position: absolute;
  right: 25px;
  top: 0;
  color: #000;
  font-size: 35px;
  font-weight: bold;
}
  
.close:hover,
.close:focus {
  color: red;
  cursor: pointer;
}
  
/* Add Zoom Animation */
.animate {
  -webkit-animation: animatezoom 0.6s;
  animation: animatezoom 0.6s
}
  
@-webkit-keyframes animatezoom {
  from {-webkit-transform: scale(0)} 
  to {-webkit-transform: scale(1)}
}
    
@keyframes animatezoom {
  from {transform: scale(0)} 
  to {transform: scale(1)}
}
  
/* Change styles for span and cancel button on extra small screens */
@media screen and (max-width: 300px) {
  span.psw {
     display: block;
     float: none;
  }
  .cancelbtn {
     width: 100%;
  }
}
</style>
</head>
<body>
  
    
  <form class="modal-content animate"
        action="{{ url_for('signin') }}" method="POST">
      
    <div class="container">
      <label for="uname"><b>Username</b></label>
      <input type="text" placeholder="Enter Username" 
             name="username" id="username" required>
  
      <label for="psw"><b>Password</b></label>
      <input type="password" placeholder="Enter Password"
             name="password" id="password" required>
          
      <button type="submit">Sign In</button>
        
    </div>
  
    <div class="container" style="background-color:#f1f1f1">
      <button type="button" 
              onclick="document.getElementById('id01').style.display='none'" 
              class="cancelbtn">Cancel</button>
      <span class="psw">Forgot <a href="#">password?</a></span>
    </div>
  </form>
  
</body>
</html>

Step 9: Create an app.py

from distutils.log import debug

from flask import Flask, render_template, request, redirect, url_for

from flask_login import UserMixin, login_user, login_required, logout_user, current_user

from flask_sqlalchemy import SQLAlchemy

from flask_login import login_user, logout_user, login_required, LoginManager

from werkzeug.security import generate_password_hash, check_password_hash

from datetime import datetime

from flask import flash

app = Flask(__name__)
db = SQLAlchemy(app)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///blogs.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SECRET_KEY'] = 'thisisasecretkey'
class GFGBLOG(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(50))
author = db.Column(db.String(20))
post_date = db.Column(db.DateTime)
content = db.Column(db.Text)
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), nullable=False, unique=True)
password = db.Column(db.String(80), nullable=False)
@app.route("/")
def hello_world():
article = GFGBLOG.query.order_by(GFGBLOG.post_date.desc()).all()
print(current_user.is_anonymous)
if current_user.is_anonymous:
name = "guest"
else:
name = current_user.username
print("bye")
return render_template('index.html', article=article, name=name)
@app.route('/about')
def about():
return render_template('about.html')
@app.route('/addpost', methods=['POST', 'GET'])
def addpost():
if request.method == 'POST':
title = request.form['title']
author = request.form['author']
content = request.form['content']
post = GFGBLOG(title=title, author=author, content=content,
post_date=datetime.now())
db.session.add(post)
db.session.commit()
print("Done")
return redirect(url_for('hello_world'))
return render_template('add.html')
@app.route('/update/<int:id>', methods=['POST', 'GET'])
@login_required
def update(id):
if request.method == 'POST':
title = request.form['title']
author = request.form['author']
content = request.form['content']
print(content)
post = GFGBLOG.query.filter_by(id=id).first()
post.title = title
post.author = author
post.content = content
db.session.add(post)
db.session.commit()
return redirect("/")
edit = GFGBLOG.query.filter_by(id=id).first()
return render_template('update.html', edit=edit)
@app.route('/delete/<int:id>')
@login_required
def delete(id):
d = GFGBLOG.query.filter_by(id=id).first()
db.session.delete(d)
db.session.commit()
return redirect(url_for('hello_world'))
@app.route('/login', methods=['POST', 'GET'])
def login():
if request.method == 'POST':
# print("hello")
username = request.form['username']
password = request.form['password']
user = User.query.filter_by(username=username).first()
if not user and not check_password_hash(user.password, password):
flash('Please check your login details and try again.')
# return redirect(url_for('auth.login'))
return render_template('not.html')
else:
login_user(user)
print("yes")
return redirect(url_for('hello_world'))
return render_template('login.html')
@app.route('/signin', methods=['POST', 'GET'])
def signin():
if request.method == 'POST':
print("hello")
username = request.form['username']
password = request.form['password']
user = User(username=username, password=password)
db.session.add(user)
db.session.commit()
return redirect(url_for('hello_world'))
return render_template('signin.html')

@app.route('/logout', methods=['GET', 'POST'])
@login_required
def logout():
logout_user()
return redirect(url_for('hello_world'))

Code Implementation:




from distutils.log import debug
from flask import Flask, render_template, request, redirect, url_for
from flask_login import UserMixin, login_user, 
              login_required, logout_user, current_user
from flask_sqlalchemy import SQLAlchemy 
from flask_login import login_user, logout_user, login_required, LoginManager
from werkzeug.security import generate_password_hash, check_password_hash
from datetime import datetime
from flask import flash
  
  
app = Flask(__name__)
db = SQLAlchemy(app)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///blogs.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SECRET_KEY'] = 'thisisasecretkey'
  
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'
  
  
@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))
  
class GFGBLOG(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(50))
    author = db.Column(db.String(20))
    post_date = db.Column(db.DateTime)
    content = db.Column(db.Text)
  
class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(20), nullable=False, unique=True)
    password = db.Column(db.String(80), nullable=False)
  
  
  
@app.route("/")
def hello_world():
    article = GFGBLOG.query.order_by(GFGBLOG.post_date.desc()).all()
    print(current_user.is_anonymous)
    if current_user.is_anonymous:
        name = "guest"
    else:
        name = current_user.username
        print("bye")
  
    return render_template('index.html', article=article, name=name)
  
  
@app.route('/about')
def about():
    return render_template('about.html')
  
  
@app.route('/addpost', methods=['POST', 'GET'])
def addpost():
    if request.method == 'POST':
        title = request.form['title']
        author = request.form['author']
        content = request.form['content']
  
        post = GFGBLOG(title=title, author=author, 
                       content=content, post_date=datetime.now())
  
        db.session.add(post)
        db.session.commit()
        print("Done")
        return redirect(url_for('hello_world'))
    return render_template('add.html')
  
@app.route('/update/<int:id>', methods=['POST', 'GET'])
@login_required
def update(id):
    if request.method == 'POST':
        title = request.form['title']
        author = request.form['author']
        content = request.form['content']
        print(content)
  
        post = GFGBLOG.query.filter_by(id=id).first()
  
        post.title = title
        post.author = author
        post.content = content
  
        db.session.add(post)
        db.session.commit()
        return redirect("/")
  
    edit = GFGBLOG.query.filter_by(id=id).first()
    return render_template('update.html', edit=edit)
  
@app.route('/delete/<int:id>')
@login_required
def delete(id):
    d = GFGBLOG.query.filter_by(id=id).first()
    db.session.delete(d)
    db.session.commit()
    return redirect(url_for('hello_world'))
  
@app.route('/login', methods=['POST', 'GET'])
def login():
    if request.method == 'POST':
        # print("hello")
        username = request.form['username']
        password = request.form['password']
        user = User.query.filter_by(username=username).first()
  
        if not user and not check_password_hash(user.password, password):
            flash('Please check your login details and try again.')
            # return redirect(url_for('auth.login'))
            return render_template('not.html')
        else:
            login_user(user)
            print("yes")
            return redirect(url_for('hello_world'))
  
    return render_template('login.html')
  
@app.route('/signin', methods=['POST', 'GET'])
def signin():
    if request.method == 'POST':
        print("hello")
        username = request.form['username']
        password = request.form['password']
  
        user = User(username=username, password=password)
        db.session.add(user)
        db.session.commit()
        return redirect(url_for('hello_world'))
  
    return render_template('signin.html')
  
  
@app.route('/logout', methods=['GET', 'POST'])
@login_required
def logout():
    logout_user()
    return redirect(url_for('hello_world'))  
  
# main driver function
if __name__ == '__main__':
    
    # run() method of Flask class runs the application 
    # on the local development server.
    app.run(debug=True)

Step 10: Create your database 

Output:

Note: For a first-time user you can register yourself by going directly to the link “http://127.0.0.1:5000/signin” which will show you to the sign-in page to register yourself in the database.


Article Tags :