This is an old revision of the document!


Lab 01 - Web Basics (Flask)

Objectives

  • Basic Web frontend coding (HTML + CSS)
  • Browser Development Tools (i.e., Web Inspector)
  • Server intro: Python / Flask backend
  • Forms and authentication (user sessions)
  • Advanced HTTP: file uploading

Contents

Introduction

With the emergence of the Internet and its undeniable commercial importance, web development became a necessary software skill for an engineer to have.

A web site / application has two major components:

  • the frontend: the user interface, displayed with the help of a client-side browser; written in HTML + CSS, optionally employing JavaScript for better interactivity;
  • the backend: an optional server-side program used to provide additional web services to the users such as authentication, data persistence, database searching etc.

In the typical scenario, the user requests to open a website by using a known URL. After optionally doing the DNS resolution to obtain an IP address, the browser connects to the server using the HTTP protocol (optionally encrypted using TLS) and requests the web page using specific HTTP headers. The server software will then parse the message, identify the requested document or dynamic application, do optional processing (e.g., invoke a routine / server-side script / CGI program to generate the webpage's HTML contents) and send the results back to the client's browser for displaying (or download, in some cases).

Frontend Basics

On the client-side, HyperText Markup Language (HTML) is the de-facto standard language accepted by all browsers to describe the aspect and contents of a web page. A HTML document is built using nested elements (i.e., tags) describing the structure (layout) of the page, text / graphical content and, optionally, client-side scripts and metadata. Each HTML element may have a series of pre-defined properties (e.g., paragraph / line splitting, bigger/smaller font sizes, form input behavior etc.) which may (or may not) be altered using attributes specified between a tag's angle brackets:

<tag1 attribute1="attribute value" id="unique-name-here">
  <anothertag style="CSS properties">inside</anothertag>
  <p>paragraph <b>bold face</b></p>
</tag1>

HTML is often paired together with Cascading Style Sheets, a style definition language used to modify layout / content properties for multiple elements at once by using special pattern matching rules using selectors. The general syntax is the selector (note: there are multiple types / rules), followed by the list of style properties to apply (in { } brackets, separated by ;):

/* tag selector (matches all <tag1> elements) */
tag1 { property1: value; ... }
/* ID selector (matches <tag id="unique-name-here">) */
#unique-name-here { color: red; ... }
/* Class selectors (matches <tag class="normal-text gray-bold">) */
/* Note: an element may have multiple classes */
.normal-text { font-size: 14pt; ... }
.gray-bold { color: gray; font-weight: bold; }
/* Combined selectors: e.g. matches only <tag1> with class="special" */
tag1.special { ... }
/* Nested selectors (element contained in another element) */
#my-header h1 { ... }
/* or direct descentant rule: */
.nav > .nav-item { ... } 

Thus, it becomes possible to create re-usable page elements (e.g., menus, various font styles, context boxes). This has led to the emergence of many CSS frameworks (e.g., Bootstrap, Foundation) facilitating the creation of responsive (accessible to both desktop + mobile devices) designs.

Serverside: Python / Flask

On the server-side, software must be running and listen for HTTP connections, optionally do application-specific processing and serve the requested web pages or files.

There are many standalone web server programs available on the market, with open-source software being the norm (e.g., Apache httpd, nginx, lighttpd) that can readily serve static resources and can be configured to execute third party interpreters to do server-side processing (e.g., PHP).

Moreover, modern programming languages (e.g., NodeJS, Golang, Python) have built-in HTTP servers and third-party libraries that makes web development setup a breeze and well integrated with the web application's processing needs.

Today, we will introduce Flask, a web framework for the Python language. Flask uses Python decorators (e.g., @decorator) to enhance functions and register them to be executed whenever the web server receives a HTTP request:

from flask import Flask, request
 
# first, create a Flask application instance
app = Flask("my_website")
 
@app.route("/page.html")
def serve_page():
  """ Returns some basic HTML content. """
  return "<h1>hello world</h1>"

Of course, URL patterns can also be captured by a single function, check the official Flask route documentation.

The routine must return a HTTP response which may either be HTML string, a rendered template, a redirection or a custom-built Response object:

from Flask import Flask, render_template, redirect, Response
@app.route("/")
def serve_template():
  return render_template("index.html", title="Hello World")
 
@app.route("/admin")
def serve_unauthorized():
  # Note: 307 is standard HTTP code for TEMPORARY REDIRECT
  return redirect("/login.html", 307, "<h1>Redirecting, please wait...</h1>")
 
@app.route("/special.xml")
def serve_special_xml():
  return Response("<xml><author>Me</author></xml>", mimetype='text/xml')

Check Flask's Response object documentation for all available options.

Template Engines

A typical website has a common HTML design, with only portions of its code changing on a per-page basis with specific content. In order to prevent needless code duplication, a template engine is usually employed to obtain HTML documents from common layouts. A template is, basically, a HTML page interleaved with specific code blocks used to insert dynamically generated content from variables; many engines feature full programming languages that support loops and conditionals.\

Flask readily integrates with the Jinja templating engine which uses Python-like statements to enrich a HTML page with programmatic content:

<!-- ... -->
<body>
    <h1>My Webpage is {{ awesome_variable }}</h1>
 
    <ul id="main-menu">
    {% for item in navigation %}
        <li><a href="{{ item.href }}">{{ item.caption }}</a></li>
    {% endfor %}
    </ul>
 
    {# a comment #}
</body>

The Jinja templates usually reside inside the project's templates/ directory (check the Flask documentation if you want to change it) and can be rendered using the render_template utility function.

Accessing HTTP request data

When Python is executing a Flask-decorated function, the request context is made available using the request member of the Flask package.

It contains all request data provided by the browser:

  • request.method: the requested HTTP method string (e.g., GET or POST);
  • request.args: a Python dict object with URL query string parameters, e.g. http://hostname/page.html?arg1=value&arg2=value;
  • request.form: HTML form data (for HTTP POST methods) as a dict object;
  • request.cookies: cookies stored by the browser (also a dict);
  • request.headers: other HTTP request headers;

Example code for printing data to the console:

from Flask import request # and many others
# ...
@app.route("/")
def my_request_handler():
  print("Method is", request.method)
  print("URL parameters:", request.args)
  # hint: access members using dict.get() method to have a default value:
  print(request.args.get("arg1", "default value"))
  if request.method == "POST":
    print("Any form data:", request.form)
  print("Cookies:", str(request.cookies))
  print("Headers:", str(request.headers))

Flask also parses many other request data formats (XML, JSON, multipart / file upload requests etc.) and provides helpers to manipulating them.

Finally, we note that the HTTP protocol is stateless: on its own, it doesn't retain anything from previous requests, e.g., the user's identity or navigation history.

Thus, it becomes the server's responsibility to use browser-assisted persistence mechanisms such as cookies to associate a HTTP request with a specific user, also called a Session. For security reasons, the server must specifically validate any data received from the user, often through cryptographic means.

Preparation

In order to solve the tasks, you will need a modern browser (duh), a code editor supporting HTML, CSS and Python (e.g., Visual Studio Code with plugins), a Python 3 distribution (you must also have pip installed).

Next, we will need to install the Flask Python package using the PIP package manager:

# NOTE: choose the most appropriate command:
# install globally (requires root / admin)
python3 -mpip install flask
# .. or for the current user only (e.g., inside ~/.local/lib/python/ on Linux)
python3 -mpip install --user flask

Tasks

01. [25p] String manipulation

First, let's familiarize ourselves with Python's string type:

  • Read a string input from the user's console (hint: input()); next sub-tasks will use this value and apply various string transformations on it;
  • Print the reversed string (e.g., “hello world” ⇒ “dlrow olleh”); hint: there are at least 3 built-in ways to do this in a single line of code ;)
  • Print the same string in “aLtErNaTe CaSe” (if you're out of ideas, simply use the for loop);
  • Finally: encrypt the given message using Caesar's Cipher (aka, shift each of its alphabet letters to n positions to the: right for encryption, left for decryption); use the number 17' for testing!

Hints for the last subtask:

  • Remember the ASCII Table?
  • You can use the ord() built-in function to get the ASCII code of a character (as int);
  • For the reverse process (int to str character) you have chr();
  • Don't forget to wrap around when you reach the last letter of the alphabet: Z + 1 ⇒ A!

02. [25p] Let's do the math!

Python is also popular for its numeric manipulation features (it can handle very large numbers!). Let's find out:

  • Read a number from the console (you should know how to do it by now; don't forget to convert it to an int!);
  • Reverse the number's digits and print the result (e.g., 13568 ⇒ 86531)!
  • Define a new function, generate_prime(k), which takes in an argument and will generate a prime number of exactly k digits; use it to generate a 15-digit prime number (decrease this if it's taking too long :( )!

03. [25p] Making the list

Solve these subtasks all in the same file (use print() statements to display the results):

Use the following list:

sample = ["a", 90, 8, "X55", "1z", 102, "asdf", 65, 10, "word", "567", 567]

Well:

  • Sort the list (does it work? if not, why?);
  • Reverse the list (this again? note: save the original one!);
  • Filter out all non-numbers from the list (i.e., only int type values should remain)… can you make it using a single line of code? now it's the time to introduce list comprehensions;

Don't know how to check the type of a variable? LMGTFY!

  • Print the original list (remember the first 2 subtasks? read this answer!);
  • Define a function that builds a matrix filled with numbers from 1 to n like the following example:
    m = [[1, 2, 3, 4],
         [4, 1, 2, 3],
         [3, 4, 1, 2],
         [2, 3, 4, 1]]

04. [25p] Word Map

First, take a couple (3-4) of paragraphs from here and store them inside a .txt file.

  • Open the file and read its contents into string;
  • Build a dict with each word from this text (lower cased as key), counting their frequency (as its value);
  • Use it to print out the most frequent 5 words in this text (together with their value!), e.g.:
[('the', 29), ('of', 18), ('and', 15), ('to', 10), ('a', 9)]

05. [10p] Bonus: Lyrics retrieval

What else can you do easily using Python… ?

Let's try this one:

  • fetch the lyrics of your favorite song from this site.

Ofc, you can do this very easy using the requests library! (Note: you must first install it using pip).

  • Extract just the lyrics part from the HTML code and print it to the console! (also, please get rid of those <br> line break tags, replace them with newlines instead).

Although you could use regular expressions for capturing the contents inside a specific HTML tag, it's a bit overkill…

Instead: simply use the standard string search methods and Python sequence indexing / slices to accomplish this much easier ;)

ii/labs/s2/01.1648740693.txt.gz · Last modified: 2022/03/31 18:31 by florin.stancu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0