Now that we have some data to work with, we can start working on a web application. We’ll start by creating a simple “course of the day” application that will randomly pick a course from our dataset and display information in the browser. Later, we’re going to publish the application to the web using sites.haverford.edu. If time permits, we can try a more advanced chatbot following this tutorial.

While it’s not common, you can write an application in pure Python. You’ll need this courses.csv in your current directory.

This example comes from from Dr. Chuck, who is a wonderful resource for improving your Python skills. Python for Everybody is a free version of his world-famous Coursera and edX courses. There is also a Django for Everybody course in the works.

py_socket.py

# https://docs.python.org/3/howto/sockets.html
# https://stackoverflow.com/questions/8627986/how-to-keep-a-socket-open-until-client-closes-it
# https://stackoverflow.com/questions/10091271/how-can-i-implement-a-simple-web-server-using-python-without-using-any-libraries
import csv
import random
import socket 

def createServer():
    serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try :
        serversocket.bind(('localhost',9000))
        serversocket.listen(5)
        while True:
            (clientsocket, address) = serversocket.accept()

            rd = clientsocket.recv(5000).decode()
            pieces = rd.split("\n")
            if ( len(pieces) > 0 ) : print(pieces[0])

            with open("courses.csv", "r") as f:
                    reader = csv.DictReader(f)
                    random_course = random.choice(list(reader))
                    course_text = ""
                    for i in random_course:
                        course_text += i + ":  " + random_course[i] + "<br>"
                    data = "HTTP/1.1 200 OK\r\n"
                    data += "Content-Type: text/html; charset=utf-8\r\n"
                    data += "\r\n"
                    data += "<html><body>{}</body></html>\r\n\r\n".format(course_text)
                    clientsocket.sendall(data.encode())
                    clientsocket.shutdown(SHUT_WR)

    except KeyboardInterrupt :
        print("\nShutting down...\n");
    except Exception as exc :
        print("Error:\n");
        print(exc)

    serversocket.close()
    
if __name__ == "__main__":
    print('Access http://localhost:9000')
    createServer()

Flask

Flask is one of the simplest Python web frameworks available and has a lot in common with Django. In the next few steps, we’re going to:

  • Create a new folder called flask_app
  • Create app.py in the flask_app directory
  • Download courses.csv to the flask_app directory
  • create a templates subfolder for our index.html file
  • create a static subfolder for our main.css file
flask_app
    ├── app.py  
    ├── courses.csv
    ├── static    # Home to all of your images, javascript and CSS
    │   └── main.css
    └── templates  # Home for all of your HTML templates
        └── index.html

app.py

import csv
import random
from flask import Flask, render_template


app = Flask(__name__)
application = app 


@app.route("/")   #This is the root URL. We can also create an absolute path @app.route("/about") or a relative one @app.route("/<user>")   
def index():
    with open("courses.csv", "r") as f:
        reader = csv.DictReader(f)
        random_course = random.choice(list(reader))
        info = ""
        for i in random_course:
            info += i + ":  " + random_course[i] + "<br>"
        return info


if __name__ == "__main__":
    app.run()

In the terminal run $ python app.py

You’ll get an error if you haven’t installed Flask. Just use pip install flask. In the future we’ll use virtual enviornments. If you’d like to get started now, you can install virtualenv or Anaconda. Real Python has a great tutorial on virtual enviornments here.

We can now serve content from our csv file to the web. Without any styling it’s really ugly. Let’s add some HTML and CSS to make this look better.

We’ll need to make a few small changes to the application so that we’re rendering an HTML template and not just sending text to the browser. Change this

info = ""
for i in random_course:
    info += i + ":  " + random_course[i] + "<br>"
return info

to this

info = ""
for i in random_course:
    info += "<tr>" + "<th>"+ i +"</th>" + "<td>" + random_course[i] + "</td>" + "</tr>"
return render_template('index.html', course_info=info)

Here we’re adding HTML tr and th tags which will create a table. For more on HTML tables, see this w3schools tutorial

Create an index.html file in the templates directory (mkdir templates).

./templates/index.html

<!DOCTYPE>
<html>

<head>
    <link rel="stylesheet" href="" 
</head>

    <body>

        <table style="width:100%">

            

        </table>

    </body>

</html>

Now create static/main.css.

./static/main.css

@import url('https://fonts.googleapis.com/css?family=Cinzel');

table {
  border-collapse: collapse;
  width: 80%;
}

td, th {
  font-family: 'Cinzel', serif;
  border: 1px solid #4C061D;
  text-align: left;
  padding: 12px;
}

tr {
  background-color: #ffffff;
}

Note the @import url(). This comes from Google Fonts. You can use any of their thousands of multi-lingual fonts just by adding this import to your css. For example, @import url('https://fonts.googleapis.com/css?family=Roboto'); and then font-family: 'Roboto', sans-serif;

your page should look something like this

The cycle of life is complete. You’ve taken data from the web and can now serve it back to your browser. More importantly, you can transform that information using Python. You can sort classes by timeslot and create a schedule builder that integrates with Google Calendar. It’s all up to you. In the next section, we discuss how to deploy your application using sites.haverford.edu.

continue…

Bonus

One of the most useful features of dynamic web frameworks is the option to sort and organize data. What if we wanted just courses in Physics? You can add a new path that will take the subject from the URL in the browser and use that to filter your data. Just add the subject to your route and pass it as an argument to your view. Django does this very elegantly, but I wanted to be sure you know that this is possible in Flask.

@app.route('/<department>')
def by_subject(department):
    with open('courses.csv','r') as f:
        reader = csv.DictReader(f) 
        info = ""
        for row in reader:
            if department in row['department']:
                for i in row:
                    info += "<tr>" + "<th>"+ i +"</th>" + "<td>" + row[i] + "</td>" + "</tr>"
        return render_template('index.html', course_info=info)

Click here to download the complete app.py