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.
# 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
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 thenfont-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.
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