Quiz

  1. Could you film the demo of it working (as you had mentioned in the reading)?

    Okay, I'll do that, but I'm behind in a few things, so it might take me a while. I'll demo today. It's not very interesting.

  2. Could you explain handlers and/vs. processor variables again?

    Sure. It's an outgrowth of what I hoped would be helpful pedagogically, but which has had mixed results. I sometimes have forms (in template files) that look like this:

    
    <form method="POST" action="{{processor}}"> ...</form>
    
    

    Then, in app.py, I would have:

    
    @app.route('/form1/')
    def send_blank_form():
       render_template('foo.html', processor=url_for('process_form1'))
    
    @app.route('/do_form1/')
    def process_form1():
        item = request.form['item']
        print(f'customer is ordering an {item}')
        ...
    
    

    The pedagogical idea was to make the connection between the two endpoints more explicit, and to put the relevant code all in app.py. I think some people found that helpful, and others didn't.

    In real life, we would almost always hard-code the value of the ACTION attribute:

    
    <form method="POST" action="{{url_for('process_form1')}}"> ...</form>
    
    
  3. When a link is clicked on a website to a different page, is this first associated with a given html file which then calls an associated function with url_for or does the link fist match to a python function which then renders an html template file?

    The latter. Flask routes the request to our Python function, which then renders the response. There might not be an HTML file at all! That's how our first examples were.

    
    @app.route('/foo/')
    def foo():    
        foo_cnt += 1
        return f'You have accessed this page {foo_cnt} times. Enjoying it?'
    
    

    The template files like F-strings on steroids.

  4. If we are only using post forms, is it best practice to still check if the request.method is a get? The examples in today's reading only have post forms, but we still check for get forms.

    Great question. If your handler function doesn't support GET, Flask will render an error, something like "no handler for GET of /foo". That's fine.

    Alternatively, your handler can support GET and create your own custom response, which might just be a different phrasing of that error message, say using flashing, maybe along with a redirect to a better endpoint.

  5. Is there a difference in how you should handle / route form submissions when the form is part of the base.html file rather than it's own file? I'm trying to connect the example we saw in flask3 countries lookup to the lookup homework assignment

    No, there's really no difference. It doesn't matter where the template for the form is located.

    All that matters is that it ends up in the rendered page, with a valid METHOD and ACTION.

  6. As our project grows, when should we start splitting routes into multiple Python files instead of keeping everything in one app.py?

    What a great question! In principle, yes, though in practice most teams do not do this.

    However, there are some tricky bits because all the Python files would need to share the same app global variable.

    One option is to have app.py contain:

    
    from flask import (Flask, render_template, make_response, url_for, request,
                       redirect, flash, session, send_from_directory, jsonify)
    app = Flask(__name__)
    
    import secrets
    import cs304dbi as dbi
    
    # we need a secret_key to use flash() and sessions
    app.secret_key = secrets.token_hex()
    
    from alice import *
    from betty import *
    from cathy import *
    ...
    
    
    

    And then the teammates files look like this:

    
    from flask import (Flask, render_template, make_response, url_for, request,
                       redirect, flash, session, send_from_directory, jsonify)
    
    from app import app
    ...
    app.route('/alice1')
    def alice1():
        ...
    
    
    

    Which is deeply weird, because each module is importing the other. But it does work.

    A conceptually easier approach is to put all the app.route() endpoints into the main app.py file, but with references to

    
    from flask import (Flask, render_template, make_response, url_for, request,
                       redirect, flash, session, send_from_directory, jsonify)
    app = Flask(__name__)
    
    import secrets
    import cs304dbi as dbi
    
    # we need a secret_key to use flash() and sessions
    app.secret_key = secrets.token_hex()
    
    import alice
    import betty
    import cathy
    ...
    @app.route('/alice1')
    alice.alice1
    
    @app.route('/betty1')
    betty.betty1
    
    
    

    Since the team should agree on the endpoints and keep those stable, this approach has some advantages.

    Note, the above code is from memory and is just for answering this question conceptually. I haven't double-checked the syntax and such.