• No results found

Web applications

In document Real Python 2-4 (Page 194-200)

Assignment 12.2: Return of the poet

13) Web applications

13.1) Create a simple web application

ou know how to write useful Python scripts, and now you want to show them off to the world... but how? Most non-programmers won't have any use for your .py script files. Programs like PyInstaller and cx_Freeze help turn Python scripts into executable programs that can be run by themselves on different platforms without the need to use Python to interpret the code. More and more, however, we're seeing a trend away from “desktop”-based applications and toward web applications that can be

accessed and run through Internet browsers.

Y

Historically, websites on the Internet were full of plain webpages that offered the exact same information to every user; you would request a page, and the information from that page would be displayed. These webpages were “static” because their content never changed; a web server would simply respond to a user's request for a webpage by sending along that page, regardless of who the user was or what other actions the user took.

Today, most websites are actually web applications, which offer “dynamic” webpages that can change their content in any number of ways. For instance, a webmail

application allows the user to interact with it, displaying all sorts of different information, often while staying in a single webpage.

The idea behind creating a Python-driven web application is that you can use Python code to determine what content to show a user and what actions to take. The code is actually run by the web server that hosts your website, so your user doesn't need to install anything to use your application; if the user has a browser and an Internet connection, then everything else will be run online.

The task of getting Python code to run on a website is a complicated one, but there are a number of different web frameworks available for Python that automatically take care

of a lot of the details.

The first thing that you will need is a web hosting plan that allows and supports the ability to run Python code. Since these usually cost money (and since not everyone even has a website), we'll stick with a free alternative that is one of the simplest to set up:

Google App Engine, which uses a web framework called webapp2.

There are a number of other alternatives (both free and paid) that are more

customizable, and you can use webapp2 on its own later without relying on Google App Engine, but getting started with Google App Engine will be the quickest and easiest way to begin learning about web application development in Python.

First, go here to download and install the appropriate Python SDK for Google App Engine.35 SDK stands for Software Development Kit. This particular SDK includes two main resources: a “web server” application, which will allow you to run your web

applications on your own computer without actually putting them online, and the Google App Engine Launcher, which will help to put your web applications online.

Python 3 note: Unfortunately, Google App Engine only works with Python 2.7 and has no immediate plans to support Python 3 code.

!

Before we dive into writing a web application, let's get a very broad, generalized overview of what's about to happen. There are a lot of different pieces involved, and they all have to communicate with each other to function correctly:

– First, your user makes a “request” for a particular webpage on your website (i.e., by typing a URL into a browser).

– This request gets received by the web server that hosts your website.

– The web server uses App Engine to look at the configuration file for your application. App Engine matches the user's request to a particular portion of your Python script.

– This Python code is called up by App Engine. When your code runs, it writes out a “response” webpage.

– App Engine delivers this response back to your user through the web server.

– The user can then view the web server's response (i.e., by displaying the resulting webpage in a browser).

The application we're going to create will rely on a couple different files, so the first thing we need to do is make a project folder to hold all of these files. Create a new folder named “first_app” anywhere you like (just remember where it is).36 First we will write a very simple Python script that can “respond” with the content of your webpage:

print "Content-Type: text/plain"

print ""

print "Congratulations, it's a web app!"

Save this code in a script named “hello.py” inside your “first_app” folder.

So what's with the first two print statements? Web servers communicate with users (usually browsers) through HTTP by receiving HTTP requests and sending HTTP

responses. The HTTP response that our application sends can have both header lines and a body.

We added a header line to our HTTP response in the first line. Header lines contain optional information to let a browser know how to interpret the body of the response. In this case, setting our header's “Content-Type” equal to the value “text/plain” is the way that our HTTP response lets a browser know to expect the body to contain plain text as opposed to HTML code, an image, or some other type of file.37 Leaving a blank line after this header line is how we told the browser, “the header lines are over now;

here comes the actual body to display.”

The body of the response is what we will actually see when we load the page in a browser. In this case, it's just a simple string of text: “Congratulations, it's a web app!”

Before we can run our web application, we need to provide App Engine with a

configuration file. This is the file that the web server will use to get information about what Python code we want it to run. Open up any text editor (or another script window

36 Linux users, you should save the folder in your /home/username directory to keep your life simple.

37 Most browsers are smart enough to correctly infer the content type without having to be told

in IDLE) and copy the following text into a new file:

application: hello version: 1

runtime: python27 api_version: 1 threadsafe: false

handlers:

- url: /.*

script: hello.py

Now name this file “app.yaml” and save it in the same “first_app” folder as the Python script.38 Make sure you get the spacing correct; the last line includes two leading spaces so that “script” lines up under “url”. Just like Python, YAML39 files rely on precise indentation.

The YAML configuration file gives App Engine all the necessary information it needs to run the web application. First, “application: hello” provides a unique identifying name for the application so that we will be able to launch it later; we are giving the name “hello” to our web app.

The line “version: 1” lets App Engine know that this is version 1 of our application. (If we update this later to “version: 2”, App Engine will keep a copy of version 1 in memory so that we can go back to running this previous version if necessary.)

The lines “runtime: python27” and “api_version: 1” let App Engine know that we want to use Python 2.7 to run our application. (There is currently only one version of the Python API offered by Google.)

The line “threadsafe: false” means that our web application isn't designed to be able to receive multiple requests at once; if App Engine has multiple requests then it will send them to our application one at a time instead of all at once.

Finally we define our “handlers” to handle different webpage requests from our users (i.e., if a user requested the main page at “/” or another page at a different address on our site). These requested paths can each be assigned to a different piece of Python

38 Make sure that you've save this file with a .yaml extension and that your text editor didn't add a file extension of its own (i.e., creating a file like app.yaml.py or app.yaml.txt).

code. In this case, we only have one script, hello.py, so we want to direct user requests for any page on the website to the same script. In these last two lines of the configuration file, we say that any URL matching the regular expression “/.*” (which is any URL on our site) should be directed to the “hello.py” script.

Okay, now we can finally take a look at our application! It's not online yet, but we can view it by running the application through our own “local” web server (that can't be accessed by other users) using Google App Engine. This will help us simulate what things will look like to a user once our application is online.

Open the Google App Engine Launcher program, then choose File → Add Existing Application… You can then browse to and select your first_app folder that contains the web application. Add the application using port 8080, then select the application in the main window and click the green “Run” button.

Linux users: you will need to navigate in your Terminal to the directory just before the first_app folder (i.e., its parent directory), then type the following command to launch the web application (which will run on port 8080 by default):

google_appengine/dev_appserver.py first_app/

The console window that appears will track lots of extra information, but your web application is up and running once you see a blinking cursor.

The “port” number can be thought of as selecting a particular channel to use, similar to broadcasting a television or radio channel. We chose to run the web application on port 8080, meaning that the user can essentially “tune in” to this port number and receive communication from our web server. (We could host a completely different web application using a different port number and the two would not interfere with each other.)

Once the web application is running (this might take a little while), we can click

“Browse” to view the web application in the default web browser. This will open up the page at the URL “localhost:8080” (which we can also type into a browser manually

to load the web application).40 The web address “localhost” is just a way of saying

“the web address of my own computer” (since the application isn't actually online yet).

The “:8080” specifies that we should listen for communication on port number 8080.41 If everything has been set up correctly, your browser should load a page that displays the plain text:

Congratulations, it's a web app!

If you make any changes to your script, as long as Google App Engine Launcher is still running your application, all you need to do in order to view the newest version of the web application is to save the script and reload the webpage. App Engine will automatically listen for any changes that might have been made.

!

Well, that's a start. As far as an “application” goes, however, the Python script involved was fairly useless. In order to make something with a bit more potential, we need to create a special object in our Python code called a WSGIApplication. WSGI stands for Web Server Gateway Interface and is a way to allow Python to communicate with the web server in a better way than simply “printing” a single chunk of information back as a response. Our new Python script, which still just displays the same line of text, is considerably more complicated:

import webapp2

class MainPage(webapp2.RequestHandler):

def get(self):

self.response.headers["Content-Type"] = "text/plain"

self.response.write("Congratulations, it's a web app!") routes = [("/", MainPage)]

myApp = webapp2.WSGIApplication(routes, debug=True)

We now had to import webapp2 in order to use WSGI. In the last line of our script, we are using the webapp2 web framework to create a WSGIApplication object named

“myApp” that will allow our code to communicate with the web server.

This time we are creating a new class using the “class” keyword; this means that

40 Using Internet Explorer, you'll have to add “http://” to the URL. Alternatively, use a real browser.

41 You will only need to specify a port number when running the web application from your own computer.

HTTP communication online always occurs on port 80 by default (to prove this to yourself, try going to

MainPage is a new type of object (specifically, a type of webapp2.RequestHandler object) that can have its own methods and attributes just like any other object. Even though it looks like the get() method takes an argument of “self”, this special

keyword is automatically created and used internally by the new object as a way to keep track of itself. We have to use this “self” keyword within a new object that we've defined, because the object needs to know when it's referring to its own methods and attributes. For instance, we have to call self.response in order to access the response stored in our MainPage RequestHandler object. For a deeper look into how to make and use a Python class, you might want to take a look at Codecademy's Introduction to Classes and my accompanying practice project.

As the first argument of our WSGIApplication, we passed a list of tuples called routes. In this case, routes only contains one tuple, ("/", MainPage). This

“route” tells our WSGI application that anyone accessing the main directory of our application should get directed to MainPage. We call MainPage a “request handler”

because it is in charge of handling any user requests for that particular webpage.

The “/” is how we represent the main “root” directory of our application (i.e., our website). If we had provided a second tuple, ("/images/", ImagesPage), then anyone who accesses the (hypothetical) “images” directory of our website would be directed to the class ImagesPage in the Python script.

If we make a mistake in the code, our application's “debug=True” argument will allow us to see the errors reported by Python in our web application; otherwise, all we would see is a “500 Internal Server Error” message.

Because of how we defined routes, when our web server receives a request to load the page “/”, webapp2 creates a new MainPage object (called a request handler because it responds to the request for a webpage). The get() method of MainPage is

automatically called when it is created, which is how our WSGIApplication responds to the web server. The response is written out with these two lines:

self.response.headers["Content-Type"] = "text/plain"

self.response.write("Congratulations, it's a web app!")

In document Real Python 2-4 (Page 194-200)