Flask
User input in Flask

User input in Flask

Getting user input using HTTP GET

HTTP GET requests are the simplest way of retrieving input from the user.

http://127.0.0.1:5000/?publication=dta

The bit after the question mark represents a named GET argument. The name is ‘publication’ and the value, ‘dta’.

HTTP GET is designed to get limited, non-sensitive information from the user in order for the server to return a page as requested by the GET arguments. By convention, GET requests should never modify the server state in a way that produce side effects, that is, the user should be able to make exactly the same request multiple times and always be given exactly the same output.

import feedparser
from flask import Flask,render_template
from flask import request

app = Flask(__name__)
RSS_FEEDS = {'bbc':"http://feeds.bbci.co.uk/news/rss.xml",
'cnn':'http://rss.cnn.com/rss/edition.rss',
'fox':'http://feeds.foxnews.com/foxnews/latest',
'iol':'http://www.iol.co.za/cmlink/1.640',
'dw':"https://rss.dw.com/rdf/rss-en-all",
'dta':"https://www.dta.gov.au/news-blogs/feed/blog_post",
'france24':"https://www.france24.com/en/france/rss"}

@app.route("/")
def get_news():
    query = request.args.get("publication")
    if not query or query.lower() not in RSS_FEEDS:
        publicaton = "dta"
    else:
        publication = query.lower()

    feed = feedparser.parse(RSS_FEEDS[publication])
    return render_template("headline.html",articles = feed['entries'])



if __name__ == '__main__':
    app.run(port=5000,debug=True)

The code for ‘headline.html’

<!DOCTYPE html>
<html>
   
    <body>
        <h1>Headlines</h1>
        {% for article in articles %}
            <b><a href="{{article.link}}">{{ article.title }}</a></b><br/>
            <i>{{ article.published}}</i> </br>
            <p>{{ article.summary }} </p> </br>
            <hr/>
        {% endfor %}
     
    </body>
</html>

Output

We can test out the code by visiting our URL followed by the get argument, for example: localhost:5000/?publication=dw. Unfortunately, from our user’s experience, we’ve made the application less user-friendly, instead of more.

To make our webpage more user friendly, we add a submit form in our html file.

<!DOCTYPE html>
<html>
   
    <body>
        <form>
            <input type="text" name="publication" placeholder="search"/>
            <input type="submit" value="Submit"/>
        </form>
        <h1>Headlines</h1>
        {% for article in articles %}
            <b><a href="{{article.link}}">{{ article.title }}</a></b><br/>
            <i>{{ article.published}}</i> </br>
            <p>{{ article.summary }} </p> </br>
            <hr/>
        {% endfor %}
     
    </body>
</html>

Output

Adding POST routes in Flask

To use a POST request, we need to make some small changes to our Python and HTML code. In the headlines.py file, make the following changes:

Change request.args.get to request.form.get

The reason for the first change is that we are now grabbing the user data from a form, so Flask automatically makes this available to us in request.form. This works the same way as request.get except that it gathers data from POST requests instead of from GETs.

All route decorators can specify how the function can be accessed: either through GET requests, POST requests, or both. By default, only GET is permitted, but we now want our default page to be accessible by either GET (when we just visit the home main page and are given BBC as a default), or POST (for when we’ve requested the page through our form with the additional query data). The methods parameter accepts a list of HTTP methods which should be permitted to access that particular route of our application.

Making our HTML form use POST

<form action="/" method="POST">

Just as with Flask, HTML forms use GET by default, so we have to explicitly define that we want to use POST instead. The action attribute isn’t strictly necessary, but usually, when we use POST, we redirect users to a confirmation page or similar, and the URL for the following page would appear here. In this case, we’re explicitly saying that we want to be redirected to the same page after our form has been submitted.

Headline.py

import feedparser
from flask import Flask,render_template
from flask import request

app = Flask(__name__)
RSS_FEEDS = {'bbc':"http://feeds.bbci.co.uk/news/rss.xml",
'cnn':'http://rss.cnn.com/rss/edition.rss',
'fox':'http://feeds.foxnews.com/foxnews/latest',
'iol':'http://www.iol.co.za/cmlink/1.640',
'dw':"https://rss.dw.com/rdf/rss-en-all",
'dta':"https://www.dta.gov.au/news-blogs/feed/blog_post",
'france24':"https://www.france24.com/en/france/rss"}

@app.route("/",methods=['GET','POST'])
def get_news():
    query = request.form.get("publication")
    if not query or query.lower() not in RSS_FEEDS:
        publication = "dta"
    else:
        publication = query.lower()

    feed = feedparser.parse(RSS_FEEDS[publication])
    return render_template("headline.html",articles = feed['entries'])

if __name__ == '__main__':
    app.run(port=5000,debug=True)

headline.html

<!DOCTYPE html>
<html>
   
    <body>
        <form action="/" method="POST">
            <input type="text" name="publication" placeholder="search"/>
            <input type="submit" value="Submit"/>
        </form>
        <h1>Headlines</h1>
        {% for article in articles %}
            <b><a href="{{article.link}}">{{ article.title }}</a></b><br/>
            <i>{{ article.published}}</i> </br>
            <p>{{ article.summary }} </p> </br>
            <hr/>
        {% endfor %}
     
    </body>
</html>

Output

The output does not changes too much except the url

Adding Weather information with openweathermap.org

Code for weather.py

import json
import json
import urllib3
import urllib
from urllib.parse import quote
import urllib.request as urll
import feedparser
from flask import Flask,render_template
from flask import request

app = Flask(__name__)
def get_weather(query):
    api_url = "http://api.openweathermap.org/data/2.5/weather?q={}&units=metric&appid=cb932829eacb6a0e9ee4f38bfbf112ed"
    query = quote(query)
    url = api_url.format(query)
    data = urll.urlopen(url).read()
    parsed = json.loads(data)
    weather = None
    if parsed.get("weather"):
        weather = {"description":parsed["weather"][0]["description"],
        "temperature":parsed["main"]["temp"],
        "city":parsed["name"]}

    return weather



RSS_FEEDS = {'bbc':"http://feeds.bbci.co.uk/news/rss.xml",
'cnn':'http://rss.cnn.com/rss/edition.rss',
'fox':'http://feeds.foxnews.com/foxnews/latest',
'iol':'http://www.iol.co.za/cmlink/1.640',
'dw':"https://rss.dw.com/rdf/rss-en-all",
'dta':"https://www.dta.gov.au/news-blogs/feed/blog_post",
'france24':"https://www.france24.com/en/france/rss"}

@app.route("/",methods=['GET','POST'])
def get_news():
    query = request.form.get("publication")
    if not query or query.lower() not in RSS_FEEDS:
        publication = "dta"
    else:
        publication = query.lower()

    feed = feedparser.parse(RSS_FEEDS[publication])
    weather = get_weather("London,UK")
    print(weather)
    return render_template("weather.html",articles = feed['entries'],weather=weather)

if __name__ == '__main__':
    app.run(port=5000,debug=True)

Code for weather.html

<!DOCTYPE html>
<html>
   
    <body>
        <form action="/" method="POST">
            <input type="text" name="publication" placeholder="search"/>
            <input type="submit" value="Submit"/>
        </form>
        <h2>Weather</h2>
        <p>City: <b> {{ weather.city }}</b></p>
        <p>{{ weather.description }} | {{ weather.temperature }}  &#8451;</p>
        <h1>Headlines</h1>
        {% for article in articles %}
            <b><a href="{{article.link}}">{{ article.title }}</a></b><br/>
            <i>{{ article.published}}</i> </br>
            <p>{{ article.summary }} </p> </br>
            <hr/>
        {% endfor %}
     
    </body>
</html>

Output

Allowing user to enter city of their choice

The code for weather.py

import json
import json
from unittest.mock import DEFAULT
import urllib3
import urllib
from urllib.parse import quote
import urllib.request as urll
import feedparser
from flask import Flask,render_template
from flask import request

app = Flask(__name__)




RSS_FEEDS = {'bbc':"http://feeds.bbci.co.uk/news/rss.xml",
'cnn':'http://rss.cnn.com/rss/edition.rss',
'fox':'http://feeds.foxnews.com/foxnews/latest',
'iol':'http://www.iol.co.za/cmlink/1.640',
'dw':"https://rss.dw.com/rdf/rss-en-all",
'dta':"https://www.dta.gov.au/news-blogs/feed/blog_post",
'france24':"https://www.france24.com/en/france/rss"}

DEFAULTS = {'publication':'dta',
'city':'LONDON,UK'}

def get_news(query):
    
    if not query or query.lower() not in RSS_FEEDS:
        publication = DEFAULTS["publication"]
    else:
        publication = query.lower()

    feed = feedparser.parse(RSS_FEEDS[publication])
    #print(feed)
    return feed['entries']

def get_weather(query):
    api_url = "http://api.openweathermap.org/data/2.5/weather?q={}&units=metric&appid=cb932829eacb6a0e9ee4f38bfbf112ed"
    query = quote(query)
    url = api_url.format(query)
    data = urll.urlopen(url).read()
    parsed = json.loads(data)
    weather = None
    if parsed.get("weather"):
        weather = {"description":parsed["weather"][0]["description"],
        "temperature":parsed["main"]["temp"],
        "city":parsed["name"]}

    return weather

@app.route("/",methods=['GET','POST'])
def home():
    publication = request.args.get('publication')
    if not publication:
        publication = DEFAULTS['publication']
    articles = get_news(publication)
    print(articles)
    city = request.args.get('city')
    if not city:
        city = DEFAULTS['city']
    weather = get_weather(city)

    return render_template('weather.html',articles=articles,weather=weather)


if __name__ == '__main__':
    app.run(port=5000,debug=True)

Code for weather.html

<!DOCTYPE html>
<html>
   
    <body>
        <form>
            <input type="text" name="city" placeholder="weather search">
            <input type="submit" value="Submit">
        </form>
        <p>City: <b> {{ weather.city }}</b></p>
        <p>{{ weather.description }} | {{ weather.temperature }}  &#8451;</p>
        <form action="/" method="POST">
            <input type="text" name="publication" placeholder="search"/>
            <input type="submit" value="Submit"/>
        </form>
        

        <h1>Headlines</h1>
        {% for article in articles %}
            <b><a href="{{article.link}}">{{ article.title }}</a></b><br/>
            <i>{{ article.published}}</i> </br>
            <p>{{ article.summary }} </p> </br>
            <hr/>
        {% endfor %}
     
    </body>
</html>

Output

Making it user friendly, searching ‘news agency’ and ‘city’ at once.

Changing the ‘weather.html’ file a little

<!DOCTYPE html>
<html>
   
    <body>
        <form action="/" method="POST">
            <input type="text" name="publication" placeholder="news agency"/></br>
            <input type="text" name="city" placeholder="weather search"></br>
            <input type="submit" value="Submit"/>
        </form>

        <p>City: <b> {{ weather.city }}</b></p>
        <p>{{ weather.description }} | {{ weather.temperature }}  &#8451;</p>
       
        

        <h1>Headlines</h1>
        {% for article in articles %}
            <b><a href="{{article.link}}">{{ article.title }}</a></b><br/>
            <i>{{ article.published}}</i> </br>
            <p>{{ article.summary }} </p> </br>
            <hr/>
        {% endfor %}
     
    </body>
</html>

Output