Creating a News Application using Flask
Tags: webdev, flask, python
Published: 2021-10-26 04:30:57

---
title: Creating a News Application using Flask
published: true
date: 2021-10-14 05:56:26 UTC
series: Flask Mini Tutorial
tags: WebDevelopment, Flask, Python
canonical_url: http://iread.ga/posts/55/creating-a-news-application-using-flask
---

In the [last part](https://iread.ga/posts/54/getting-started-with-flask), we had seen a simple Hello World application using Flask. In this part, we'll continue with the same codebase and create a News Application. We'll make use of Templates and Static files to make the application look attractive. For the news, we'll be using [News API](https://newsapi.org/). So, let's dive in!  

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t5fwj3maou86hf53yep1.png)
 

# **Templates**

Templates are the HTML files that we'll use to serve HTML pages on the application. As we have already discussed in the [previous blog](https://iread.ga/posts/54/getting-started-with-flask), these files will exist in a `templates` directory inside the `core` package. So, let's create a `templates` directory inside the `core` package. Also, let's create an `index.html` file inside the `templates` directory.

```bash
$ mkdir core/templates
$ touch core/templates/index.html
```

Now that, we'll be using HTML files for our application, why don't we use **Bootstrap** for this? [Bootstrap](https://getbootstrap.com/) helps us quickly design and customize responsive mobile-first sites. With that being said, head over to the [starter template](https://getbootstrap.com/docs/5.1/getting-started/introduction/#starter-template) given by Bootstrap and copy and paste it inside the `index.html` file:

```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 -->
    <link
      href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"
      rel="stylesheet"
      integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3"
      crossorigin="anonymous"
    />

    <title>Hello, {{ user.name }}!</title>
  </head>
  <body>
    <h1>Hello, {{ user.name }}!</h1>

    <!-- Bootstrap Bundle with Popper -->
    <script
      src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
      integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
      crossorigin="anonymous"
    ></script>
  </body>
</html>

```

This is a simple _starter template_ provided by Bootstrap. It includes CSS and Javascript given by Bootstrap. If you open this, it will just render a message. Instead of the _Hello World_ message, we want to make it customized. So, we have used `Hello, {{ user.name }}` which makes use of the **Jinja2** templating engine. Now, let's see how we can serve this page using Flask.

```py
from core import app
from flask import render_template # Add this line

@app.route('/')
def say_hello():
    user = {"name": "Ashutosh"}
    return render_template("index.html", user=user) # Modify this line

```

To render an HTML page from our flask application, we make use of the `render_template()` method provided by flask itself. This method takes a **template filename** and a **variable list of template arguments** and returns the same template, but with all the placeholders in it replaced with actual values. The `render_template()` method invokes the [Jinja2](http://jinja.pocoo.org/) template engine that comes bundled with the Flask framework. Jinja2 substitutes `{{ ... }}` blocks with the corresponding values, given by the arguments provided in the `render_template()` call.

Now, let's run the server and see what the output looks like:

![](https://res.cloudinary.com/dlomjljb6/image/upload/v1/media/blog/uploads/2021/10/14/screenshot-2021-10-14-100833_syx43x)

Did you see, whatever name we passed in the `user` dictionary, we have the same name in the output. This is how it works.   
 

# **Static Files**

Now, let us see how we can serve static files in the HTML templates. Static files include CSS, Javascript, Images, Fonts, etc. Since we already have CSS and Javascript served by Bootstrap, let us serve an image. For that create a `static` directory inside the `core` package, inside that directory, create an `images` folder.

```bash
$ mkdir core/static
$ mkdir core/static/images
```

You can put any image inside the images folder. I am using a `demo.jpg` image, for example. This is how we can use static files in our HTML templates:

```html
<img src="{{ url_for('static', filename='images/demo.jpg') }}" alt="">
```

Flask provides a `url_for` function that generates URLs dynamically. We are referencing the `images/demo.jpg` file inside the `static` folder. Let's put this line below the _Hello_ message. Here's what our output will look like:

![](https://res.cloudinary.com/dlomjljb6/image/upload/v1/media/blog/uploads/2021/10/14/screenshot-2021-10-14-102509_zhimer)  
 

# **News API**

Now, let us jump to the main part of the application - how we will get the news headlines. For this purpose, we are going to use [News API](https://newsapi.org). Signup for a free account and get an **API Key** from News API. Once you get the API Key, create a `.env` file at the top-level directory and store your API Key there as:

```
NEWS_API_KEY=YOUR-API-KEY-HERE
```

You can learn more about environment variables [here](https://iread.ga/posts/49/do-you-really-need-environment-variables-in-python). To use environment variables, we are using an external library called `python-decouple`. You can install it as:

```bash
$ pip install python-decouple
```

Once installed, create a `utils.py` file inside the `core` package. Inside this file, we're going to fetch the latest news headlines. News API has a Python library called [newsapi-python](https://pypi.org/project/newsapi-python/). But instead of using that, we will be using the `requests` library. You need to install it as:

```bash
$ pip install requests
```

You can learn how to work with APIs using Python in [this blog](https://iread.ga/posts/26/python-api-tutorial).

Now, that we have everything ready, let us fetch the latest news headlines in the `utils.py` file. Open the `utils.py` file and add the following code there:

```py
import requests
from decouple import config

NEWS_API_KEY = config('NEWS_API_KEY')
COUNTRY = 'in'

def get_latest_news():
    news_data = requests.get(f'https://newsapi.org/v2/top-headlines?country={COUNTRY}&apiKey={NEWS_API_KEY}').json()
    return news_data['articles']

```

In the above script, we are having two imports - `requests` to get the news and `config` to get values of environment variables stored in `.env` file. We are then storing the value of **API Key** inside a variable `NEWS_API_KEY`. We are also setting the `COUNTRY` to **in** , i.e., India. You can find the country code of various countries in the News API documentation. The next thing we are doing is creating a `get_latest_news()` function. Inside that, we are making a **GET** request to the URL provided by News API [here](https://newsapi.org/docs/endpoints/top-headlines) with the country and API Key parameters. We are converting the response into JSON. It will look something like this:

```json
{
  "status": "ok",
  "totalResults": 38,
  "articles": [
    {
      "source": {
        "id": null,
        "name": "Sportskeeda"
      },
      "author": "Aniket Thakkar",
      "title": "Latest Free Fire redeem code to get Weapon loot crate today (14 October 2021) - Sportskeeda",
      "description": "Gun crates are one of the ways that players in Free Fire can obtain impressive and appealing gun skins.",
      "url": "https://www.sportskeeda.com/free-fire/latest-free-fire-redeem-code-get-weapon-loot-crate-today-14-october-2021",
      "urlToImage": "https://staticg.sportskeeda.com/editor/2021/10/d0b83-16341799119781-1920.jpg",
      "publishedAt": "2021-10-14T03:51:50Z",
      "content": null
    },
    {
      "source": {
        "id": null,
        "name": "NDTV News"
      },
      "author": null,
      "title": "BSF Gets Increased Powers In 3 Border States: What It Means - NDTV",
      "description": "Border Security Force (BSF) officers will now have the power toarrest, search, and of seizure to the extent of 50 km inside three newstates sharing international boundaries with Pakistan and Bangladesh.",
      "url": "https://www.ndtv.com/india-news/bsf-gets-increased-powers-in-3-border-states-what-it-means-2574644",
      "urlToImage": "https://c.ndtvimg.com/2021-08/eglno7qk_-bsf-recruitment-2021_625x300_10_August_21.jpg",
      "publishedAt": "2021-10-14T03:44:00Z",
      "content": "This move is quickly snowballing into a debate on state autonomy. New Delhi: Border Security Force (BSF) officers will now have the power to arrest, search, and of seizure to the extent of 50 km ins… [+4143 chars]"
    },
    {
      "source": {
        "id": "the-times-of-india",
        "name": "The Times of India"
      },
      "author": "TIMESOFINDIA.COM",
      "title": "5 health conditions that can make your joints hurt - Times of India",
      "description": "Joint pain caused by these everyday issues generally goes away on its own when you stretch yourself a little and flex your muscles.",
      "url": "https://timesofindia.indiatimes.com/life-style/health-fitness/health-news/5-health-conditions-that-can-make-your-joints-hurt/photostory/86994969.cms",
      "urlToImage": "https://static.toiimg.com/photo/86995017.cms",
      "publishedAt": "2021-10-14T03:30:00Z",
      "content": "Depression is a mental health condition, but the symptoms may manifest even on your physical health. Unexpected aches and pain in the joints that you may experience when suffering from chronic depres… [+373 chars]"
    },
    {
      "source": {
        "id": null,
        "name": "The Indian Express"
      },
      "author": "Devendra Pandey",
      "title": "Rahul Dravid likely to be interim coach for New Zealand series - The Indian Express",
      "description": "It’s learnt that a few Australian coaches expressed interest in the job, but the BCCI isn’t keen as they are focussing on an Indian for the role, before they look elsewhere.",
      "url": "https://indianexpress.com/article/sports/cricket/rahul-dravid-likely-to-be-interim-coach-for-new-zealand-series-7570990/",
      "urlToImage": "https://images.indianexpress.com/2021/05/rahul-dravid.jpg",
      "publishedAt": "2021-10-14T03:26:09Z",
      "content": "Rahul Dravid is likely to be approached by the Indian cricket board to be the interim coach for Indias home series against New Zealand. Head coach Ravi Shastri and the core of the support staff will … [+1972 chars]"
    },
    {
      "source": {
        "id": null,
        "name": "CNBCTV18"
      },
      "author": null,
      "title": "Thursday's top brokerage calls: Infosys, Wipro and more - CNBCTV18",
      "description": "Goldman Sachs has maintained its 'sell' rating on Mindtree largely due to expensive valuations, while UBS expects a muted reaction from Wipro's stock. Here are the top brokerage calls for the day:",
      "url": "https://www.cnbctv18.com/market/stocks/thursdays-top-brokerage-calls-infosys-wipro-and-more-11101072.htm",
      "urlToImage": "https://images.cnbctv18.com/wp-content/uploads/2019/03/buy-sell.jpg",
      "publishedAt": "2021-10-14T03:26:03Z",
      "content": "MiniGoldman Sachs has maintained its 'sell' rating on Mindtree largely due to expensive valuations, while UBS expects a muted reaction from Wipro's stock. Here are the top brokerage calls for the day:"
    }
  ]
}

```

Since the news is contained in a list called `articles`, we are returning `news_data['articles']` from the function. Now we are ready to use this function in our routes.  
 

# **Designing News Page**

We're going to design the news page using Bootstrap only. So, create a `news.html` file inside the `templates` directory and add the following code there:

```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 -->
    <link
      href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"
      rel="stylesheet"
      integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3"
      crossorigin="anonymous"
    />

    <title>Latest News Headlines</title>
  </head>
  <body>
    <h1 class="text-center mt-4 mb-5">Latest News Headlines</h1>
    <div class="row mt-5">
      <div class="col-md-2"></div>
      <div class="col-md-8">
        <div class="row">
          {% for news in news_articles %}
          <div class="col-md-4 mb-5">
            <div class="card" style="width: 18rem">
              <img src="{{ news.urlToImage }}" class="card-img-top" alt="..." />
              <div class="card-body">
                <h5 class="card-title">{{ news.title }}</h5>
                <p class="card-text">{{ news.description }}</p>
                <a href="{{ news.url }}" class="btn btn-primary">Read More</a>
              </div>
            </div>
          </div>
          {% endfor %}
        </div>
      </div>
      <div class="col-md-2"></div>
    </div>

    <!-- Bootstrap Bundle with Popper -->
    <script
      src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
      integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
      crossorigin="anonymous"
    ></script>
  </body>
</html>

```

The code would look familiar to you now. In the body of the template, we have added a heading. Below that we have used [Jinja2 for loop](https://jinja2docs.readthedocs.io/en/stable/templates.html?highlight=loop#for) to iterate over the `news_articles` list passed by our routes. We have used [Bootstrap cards](https://getbootstrap.com/docs/5.1/components/card/#example) for each news. It contains an **image** , the **news title** , its **description** and a **button** to read the complete news. If you take a look at the sample response given above, you will find `title`, `description`, `URL` and `urlToImage` in the response.  
 

# **Creating Route for News page**

Now, open the `routes.py` file and create a route `"/news"` for the news page. 

```py
from core import app
from flask import render_template
from .utils import get_latest_news # Add this line

@app.route('/')
def say_hello():
    user = {"name": "Ashutosh"}
    return render_template("index.html", user=user)

# Add this part
@app.route('/news')
def news_headlines():
    news_articles = get_latest_news()
    return render_template("news.html", news_articles=news_articles)

```

In the above script, we have imported `get_latest_news()` function from `utils.py` file. We have then created a view function `news_headlines()` mapped with the URL `"/news"` using the `@app.route` decorator. Inside the function, we have got the data from `get_latest_news()` function in a `news_articles` variable which is nothing but a _list_. We have then rendered our `news.html` file and passed the `news_articles` list.

Now we are ready to run the server and see the output:

![](https://res.cloudinary.com/dlomjljb6/image/upload/v1/media/blog/uploads/2021/10/14/screenshot-2021-10-14-111855_dgudhx)

Doesn't that look amazing? We just created our first news application using Flask.  
 

# **Conclusion**

In this blog, we have created a News application. Go through the [News API Documentation](https://newsapi.org/docs) and explore some more API endpoints. You can make the page look more attractive by using custom CSS. Hope you liked the tutorial. You can find the entire application code here: [https://github.com/ashutoshkrris/Flask-News-Application](https://github.com/ashutoshkrris/Flask-News-Application)