17
Creating a News Application using Flask
In the last part, 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. So, let's dive in!
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, 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.
$ 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 helps us quickly design and customize responsive mobile-first sites. With that being said, head over to the starter template given by Bootstrap and copy and paste it inside the index.html
file:
<!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/[email protected]/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/[email protected]/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.
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 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:
Did you see, whatever name we passed in the user
dictionary, we have the same name in the output. This is how it works.
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.
$ 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:
<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:
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. 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. To use environment variables, we are using an external library called python-decouple
. You can install it as:
$ 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. But instead of using that, we will be using the requests
library. You need to install it as:
$ pip install requests
You can learn how to work with APIs using Python in this blog.
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:
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 with the country and API Key parameters. We are converting the response into JSON. It will look something like this:
{
"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.
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:
<!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/[email protected]/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/[email protected]/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 to iterate over the news_articles
list passed by our routes. We have used Bootstrap cards 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.
Now, open the routes.py
file and create a route "/news"
for the news page.
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:
Doesn't that look amazing? We just created our first news application using Flask.
In this blog, we have created a News application. Go through the News API Documentation 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
17