How to filter a table using dates but the user doesn't enter an 'end date' (CRUD Flask + SQLAlchemy)

Question:

I created a CRUD flask web app for scheduling truck appointments. I have an HTML form where the user enters a start and end date and the web page displays the appointments in the database within that period.

For situations where the user only enters a start date and not an end date, I’d like to set the ‘end date’ to 2050-01-01 so that the user can see all the appointments after the start date.

I tried to write an if-statement within my index() view function but I don’t know the correct syntax. Here’s what I’m trying to do in pseudo-code:

if the (end date).value.length = 0, then 
    end date = '2050-01-01'
else
    search_date_end = request.args.get('end_date_filter')

app.py:

@app.route('/', methods=['GET', 'POST'])
def index():

search_date_start = request.args.get('start_date_filter')
search_date_end = request.args.get('end_date_filter')

appts = appts_db.query 
    .filter(appts_db.pickup_date.between(search_date_start, search_date_end)) 
    .order_by(appts_db.pickup_date).all()

return render_template('index.html', appts=appts)

index.html:

<h3>Appointment List:</h3>
    <table>
        <tr>
            <th>Carrier</th>
            <th>Material</th>
            <th>Pickup Date [YYYY-MM-DD]</th>
        </tr>

        {% for appt in appts %}
             <tr>
                 <td>{{ appt.carrier }}</td>
                 <td>{{ appt.material }}</td>
                 <td>{{ appt.pickup_date }}</td>
             </tr>
        {% endfor %}
    </table>

<form action="/" method="GET">
    <label for="start_date_filter">Choose a start date:</label>
    <input type="date" id="start_date_filter" name="start_date_filter" 
        min="2022-01-01"><br>

    <label for="end_date_filter">Choose an end date:</label>
    <input type="date" id="end_date_filter" name="end_date_filter" 
        min="2022-01-01"><br>

    <input type="submit" value="Filter Appointments">
</form>
Asked By: Brandon H.

||

Answers:

You’re getting the value from the request.args dict.
Therefore, if the key is absent, you’ll have None.
Adding an if/else on the end value should be enough for what you want.

@app.route('/', methods=['GET', 'POST'])
def index():

    search_date_start = request.args.get('start_date_filter')
    search_date_end = request.args.get('end_date_filter')

    
    if search_date_end is None:  # open ended
        query = (
            appts_db.query
            .filter(appts_db.pickup_date >= search_date_start)
            .order_by(appts_db.pickup_date)
        )
    else:  # close ended
        query = (
            appts_db.query
            .filter(appts_db.pickup_date.between(search_date_start, search_date_end))
            .order_by(appts_db.pickup_date)
        )

    return render_template('index.html', appts=query.all())

With new style select statement (>= 1.4) it becomes even simpler as only the filter needs to be changed.

@app.route('/', methods=['GET', 'POST'])
def index():

    search_date_start = request.args.get('start_date_filter')
    search_date_end = request.args.get('end_date_filter')

    stmt = select(appts_db).order_by(appts_db.pickup_date)

    if search_date_end is None:  # open ended
        stmt = stmt.filter(appts_db.pickup_date >= search_date_start)
    else:  # close ended
        stmt = stmt.filter(appts_db.pickup_date.between(search_date_start, search_date_end))

    result = session.scalars(stmt)

    return render_template('index.html', appts=result.all())
Answered By: ljmc