Python 3: Designing a Tasklist Application

0
2010
7 min read

 

Python 3 Web Development Beginner’s Guide

Python 3 Web Development Beginner's Guide

Use Python to create, theme, and deploy unique web applications

        Read more about this book      

(For more resources on Python, see here.)

Designing a tasklist application


 

Designing an application should start with a clear idea of what is expected. Not only to determine what is technically required, but almost as important, to define clear boundaries so that we don’t lose time on things that are just nice to have. Nice to have features are something to be added if there is time left in the project.

Thehighlightedcodesetstherotationofthecircletofalse.Withoutthis,therevolute jointwouldbejustaweld jointintheend.

So let’s draw up a shortlist of the relevant features of our tasklist application. Some of these may seem obvious, but as we will see, these have a direct impact on some implementation choices that we have to make, such as:

  • The application will be used by multiple users
  • Task lists should be stored indefinitely
  • A task list may contain an unlimited number of tasks but the user interface is designed for optimal performance for up to 25 tasks or so
  • Tasks may be added, deleted, and marked as done

Although this list isn’t exhaustive, it has some important implications.

The fact that the tasklist application will be used by more than one user means that we have to identify and authorize people who want to use it. In other words, we will need some sort of logon screen and a way to check people against some sort of password database. Because we do not want to burden the user with identifying himself/herself each and every time a task list is refreshed or altered, we need some way of implementing the concept of a session.

Web applications use the stateless HTTP protocol. This means, from the server’s point of view, every request is a single, unrelated event, and no information is retained at the server. This obviously presents us with a problem if we want to perform a set of related actions. The solution is to ask the web browser to send a small piece of information along with every request it makes to the application after the application has identified the user.

This might be accomplished in a number of ways. The server may add an extra parameter to all links inside any web page it generates, commonly referred to as a session id, or use the even more general concept of a cookie.

Once the server asks the web browser to store a cookie, this cookie is sent with every following request to the same website. The advantage of cookies is that common web application frameworks (like CherryPy) are already equipped to deal with them and implementing sessions with cookies is much simpler than designing the application to alter all hyperlinks it generates to include a proper session ID. The disadvantage might be that people may block their browser from storing cookies because some websites use them to track their clicking behavior.

We let the simplicity of implementation prevail and opt for cookies. If users want to block cookies this is not much of a problem as most browsers also have the option to selectively allow cookies from designated websites.

The following image illustrates the way CherryPy manages sessions with the help of cookies:

Python 3: Designing a Tasklist Application

It starts when the client (the web browser) sends a request to CherryPy. Upon receiving the request, the first check is to see if the web browser has sent along a cookie with a session ID. If it didn’t, a new session idea is generated. Also, if there was a cookie with a session ID, if this ID is no longer valid (because it has expired, for example, or is a remnant from a very old interaction and doesn’t exist in the current cache of session IDs) CherryPy also generates a new session ID.

At this point, no persistent information is stored if this is a new session, but if it’s an existing session there might be persistent data available. If there is, CherryPy creates a Session object and initializes it with the available persistent data. If not, it creates an empty Session object. This object is available as a global variable cherrypy.session.

The next step for CherryPy is to pass control to the function that will handle the request. This handler has access to the Session object and may change it, for example, by storing additional information for later reuse. (Note that the Session object acts like a dictionary so you can simply associate values with keys with cherrypy.session[‘key’]=value.
The only restriction to the keys and values is that they must be serializable if the persistent storage is on disk).

Then before returning the results generated by the handler, CherryPy checks if the Session object has changed. If (and only if) it has, are the contents of the Session object saved to a more permanent storage.

Finally, the response is returned accompanied by a cookie with the session ID.

Time for action – creating a logon screen

Our first task is to create a small application that does little more than present the user with a logon screen. It will be the starting point of our tasklist application and many others as well.

The code for this example is available from the Packt website. If you have not downloaded it yet, this might be a good time to do so.

Enter the following pieces of code and save it in a file called logonapp.py

import cherrypy
import logon
class Root(object):
 logon = logon.Logon(path="/logon",
 authenticated="/",
 not_authenticated="/goaway")
 @cherrypy.expose
 def index(self):
 username=logon.checkauth('/logon')
 return '''
 <html><body>
 <p>Hello user <b>%s</b></p>
 </body></html>'''%username
 @cherrypy.expose
 def goaway(self):
 return '''
 <html>
 <body><h1>Not authenticated, please go away.</h1>
 </body></html>'''
 @cherrypy.expose
 def somepage(self):
 username=logon.checkauth('/logon',returntopage=True)
 return '''<html>
 <body><h1>This is some page.</h1>
 </body>
 </html>'''

if __name__ == "__main__":
 import os.path
 current_dir = os.path.dirname(os.path.abspath(__file__))
 
 cherrypy.quickstart(Root(),config={
 '/': {'tools.sessions.on': True }
 }
 )

If you now run logonapp.py, a very simple application is available on port 8080. It presents the user with a logon screen when the top level page http://localhost:8080/ is accessed. An example is shown in the following illustration:

Python 3: Designing a Tasklist Application

If a correct username/password combination is entered, a welcome message is shown. If an unknown username or wrong password is entered, the user is redirected to http://localhost:8080/goaway.

The somepage() method (highlighted) returns a page with (presumably) some useful content. If the user is not yet authenticated, the logon screen is shown and upon entering the correct credentials, the user is directed back to http://localhost:8080/somepage.

The complete tree of web pages within the logon sample application and the possible paths the user may pick through is shown next:

Python 3: Designing a Tasklist Application

Logon + session ID vs. HTTP basic authentication
You may wonder why we choose not to reuse CherryPy’s bundled auth_basic tool that offers basic authentication (for more information on this tool, see http://www.cherrypy.org/wiki/BuiltinTools#tools.auth_ basic). If all we wanted was to check whether a user is allowed access to a single page, this would be a good choice. The basic authentication is sufficient to authenticate a user, but has no concept of a session. This means we lack a way to store data that needs to be accessible when we process subsequent requests by the same user. The sessions tool we use here does provide this additional functionality.

LEAVE A REPLY

Please enter your comment!
Please enter your name here