Python 10

Flask

If you know Javascript, there is a famous framework called react. If you don’t know Javascript or react, it is fine. In python, prominent frameworks are Flask and Django.

It helps to build an app with many built-in functions that allow connecting with a web server.

Let’s look at the basic structure of Flask with the counter app.

Check out the original app build here 👉 https://youtu.be/B9nFMZIYQl0

Please use replit to follow; it is simple to use for beginners! 👉 https://replit.com/

Counter App with Flask

At the top of the file, there are some codes for importing. import brings another function from a different file

from flask import Flask, render_template_string
from replit import db
# original
# import counter_app
# from counter_app import home_page, app, show, db

Ignore this part for now, and press run

Alt text

Basic Flask functions

import counter_app
from counter_app import home_page, app, show, db

@app.route('/')
def home():
  return 'HOME PAGE'

# running the app
app.run(host='0.0.0.0', port=81)

There are some helper functions from counter_app, and later we will replace it to flask functions.

The first replacement is the app function that can be replaced with app = Flask(__name__)

This is how we initialize the flask app, and we need to import Flask function from flask. You don’t need to memorize this, and we can go to the flask webpage to learn more 👇 https://flask.palletsprojects.com/en/2.2.x/quickstart/

For now, we need to focus on app.route('/')

@app.route('/')
def home():
  return 'HOME PAGE'

We already know what the home page is. It shows the root of the page, and / means the path for the URL.

@app.route('/'), routing us to the page where inside of (), and in this case, it is the home page(root page).

def home():
  return 'HOME PAGE'

Another part is a function, which we are familiar with. It doesn’t have to be home, it is just the function’s name.

And it returns HOME PAGE in our preview. In this part, we need to return our html code like return <h1>Hello Python</h1>

Try to change your return statement with HTML tags and refresh(press stop and re-run the server) the app.

app.route('/') and function def home(): goes together 👇

# For example...
@app.route('/')
def home():
  return 'HOME PAGE'

# Another route
@app.route('/my_page')
def my_page():
  return 'My page'

HTML & CSS

Now we need to write our html code for the home page. HTML is a static code, meaning it cannot calculate or do action-like functions. It can only show the page that is written in the file.

my_home_page = '''
  <h1>Number here</h1>

  <div>
    <form action='/decrement'>
      <button type='submit'>-</button>
    </form>

    <form action='/increment'>
      <button type='submit'>+</button>
    </form>
  </div>
'''

Here is a simple html code for the home page, now we want to render this page in our app.

How do we render this in our app? It is simple, we can just return the variable my_home_page

And in flask, there is a helpful function to render html tags without an error: render_template_string

Now our app should look below

import counter_app
from counter_app import db # deleted
from flask import Flask, render_template_string # 👈 don't forget to add

app = Flask(__name__)

my_home_page = '''
  <h1>Number here</h1>

  <div>
    <form action='/decrement'>
      <button type='submit'>-</button>
    </form>

    <form action='/increment'>
      <button type='submit'>+</button>
    </form>
  </div>
'''

@app.route('/')
def home():
  return render_template_string(my_home_page)

app.run(host='0.0.0.0', port=81)

If you see the Number here and -, + buttons, we are ready to go next step.

We now have render_template_string to replace show(), my_home_page to replace home_page and app = Flask(__name__) to replace app from counter_app. We can delete three of them, but keep db

Route

When we click the plus and minus buttons, we will see 404 Not found pages. That’s because we haven’t created the routes for that pages.

We can create another app.route() to create another route. But this time, the name in the parenthesis will be different.

@app.route('/decrement')

Create your own function that returns a page with the text decrement page

Toggle Answer 👇
@app.route('/decrement')
def decrement():
  return 'decrement page'

Now try to finish the increment route with the same logic.

And when we click the minus button, we can now see it takes us to /decrement route in the address bar.

Alt text

Dynamic data

By far, we connect our buttons to each route. But we don’t want to see a different page. We want to increment or decrement numbers.

In order to do that, let’s briefly talk about dynamic data. Unlike static data, python can calculate numbers or take an action and we call this dynamic data.

But how do we pass python code into html?

my_home_page = '''
  <h1></h1>

  <div>
    <form action='/decrement'>
      <button type='submit'>-</button>
    </form>

    <form action='/increment'>
      <button type='submit'>+</button>
    </form>
  </div>
'''

@app.route('/')
def home():
  return render_template_string(my_home_page, number=0)

Take a look code above. Do you notice the differences compared to the previous code?

We added hard coded number=0 in the render_template_string() function, and `` inside of the <h1> tag. It can be <span> too.

And to see the same result in different browsers routes, we can render the same number and my_home_page like this:

my_home_page = '''
  <span></span>

  <div>
    <form action='/decrement'>
      <button type='submit'>-</button>
    </form>

    <form action='/increment'>
      <button type='submit'>+</button>
    </form>
  </div>
'''

@app.route('/')
def home():
  return render_template_string(my_home_page, number=0)

@app.route('/decrement')
def decrement():
  return render_template_string(my_home_page, number=0)

@app.route('/increment')
def increment():
  return render_template_string(my_home_page, number=0)

app.run(host='0.0.0.0', port=81)

By doing this, we now have the hard-coded number 0 in our file. Also, if we click the buttons, it takes us to a different route, but still, we see the same html.

Counter database

We have the hard-coded number 0, but it is not counting the numbers. To count numbers, we are going to create a temporary database.

database = {
  'number': 0
}

Do you remember how to access the dictionary data? To change our hard coded number=0, you can call database['number'] database in the app.

@app.route('/')
def home():
  return render_template_string(my_home_page, number=database['number'])

Now we have the database, we can finish our increment and decrement function.

To decrement function with the data, we need to access the database and decrement the number.

  database['number'] -= 1

  # This code is the same as
  database['number'] = database['number'] - 1

As a result, our decrement function should look like this with route

@app.route('/decrement')
def decrement():
  database['number'] -= 1
  return render_template_string(my_home_page, number=database['number'])

Try to write your own increment function and continue.

Now we have a ‘temporary’ database, which means when we run the server each time, the database will reset the number to 0. If we want to save the number in a real-time database, we can use replit databse

Alt text

Take the steps above, and cut and paste the line from replit import db to the top.

Replace database with db, but there is one additional step we need to remember. What if db from replit does not have number and 0 key-value pair?

To prevent that case, add this code where database existed.

if 'number' not in db:
  db['number'] = 0

Our code now should look like this:

import counter_app
from flask import Flask, render_template_string # 👈 don't forget to add
from replit import db

app = Flask(__name__)

# db = { 'number': 0 }

if 'number' not in db:
  db['number'] = 0

my_home_page = '''
  <span></span>

  <div>
    <form action='/decrement'>
      <button type='submit'>-</button>
    </form>

    <form action='/increment'>
      <button type='submit'>+</button>
    </form>
  </div>
'''

@app.route('/')
def home():
  return render_template_string(my_home_page, number=db['number'])

@app.route('/decrement')
def decrement():
  db['number'] -= 1
  return render_template_string(my_home_page, number=db['number'])

@app.route('/increment')
def increment():
  db['number'] += 1
  return render_template_string(my_home_page, number=db['number'])

app.run(host='0.0.0.0', port=81)

CSS styling

Since this is not a CSS course, our focus is python code. But thankfully, clever programmer prepared the CSS styling for us.

All we have to do is add this magical line in our html. <link rel='stylesheet' href='./static/counter_styles.css' />

my_home_page = '''
  <link rel='stylesheet' href='./static/counter_styles.css' />
  <span></span>

  <div>
    <form action='/decrement'>
      <button type='submit'>-</button>
    </form>

    <form action='/increment'>
      <button type='submit'>+</button>
    </form>
  </div>
'''

As a result, the CSS styles are applied.

Alt text

Best practices

As beginner developers, we need to keep the code clean and keep the rules that most companies follow.

In most cases, we need to separate our html codes because of performance and architectural issues.

In order to do that, let’s create a new folder called templates and inside the folder tempaltes, create a file index.html

And copy and paste the html codes to index.html file, and we are going to import index.html from our main.py

Alt text

Now we have to import index.html with the function called render_template. This function comes from the flask, so we need to change our code like this: from flask import Flask, render_template

And to use index.html file, change our route function

@app.route('/')
def home():
  # This part has changed! 🌟
  return render_template('index.html', number=db['number'])

render_template_string has changed to render_template and my_home_page has changed to index.html

Finally, our code should look like the one below. Check if anything changed from the previous result.

import counter_app
from flask import Flask, render_template # 👈 this part changed!
from replit import db

app = Flask(__name__)

# db = { 'number': 0 }

if 'number' not in db:
  db['number'] = 0

# my_home_page = ''' We don't need this anymore '''

@app.route('/')
def home():
  return render_template('index.html', number=db['number'])

@app.route('/decrement')
def decrement():
  db['number'] -= 1
  return render_template('index.html', number=db['number'])

@app.route('/increment')
def increment():
  db['number'] += 1
  return render_template('index.html', number=db['number'])

app.run(host='0.0.0.0', port=81)

Done! If you want to change styling, you can click the three dots from the bar where we created our folder, and choose show hidden file

There is static folder and solutions too. Feel free to check solutions and change the styling by yourself!

Categories:

Updated:

Comments