Streamlit Part 3: Form Validation

Streamlit Part 3: Form Validation

Form Validation Part 1

A Roundhouse Kick into Streamlit Form Validation

Amid the rhythmic thuds of gloves hitting pads, Rick and Chris were immersed in their kickboxing class. Between combos, they exchanged thoughts—not just on perfecting their strikes but also on coding challenges. As they caught their breath, the conversation shifted to Streamlit and the importance of form validation.

Rick: Panting "You know, Chris, it's like the saying 'garbage in, garbage out.' If I don't validate the data properly in my Streamlit app, I can't expect good results. I need to guard the gate and make sure only clean data gets through."

Chris: Laughs "Nice analogy! Just as a misstep here could land you on the mat, bad input can crash your app. What are you working on?"

Rick: "I'm building an app that collects user information, and I want to ensure the data is valid before processing it. Any tips on implementing form validation in Streamlit?"

Chris: "Absolutely! Streamlit doesn't have built-in validation like some web frameworks, but you can create custom validation functions. It's like customizing your training routine."

Rick: "Sounds good. Maybe after class, you can guide me through setting it up?"

Chris: "Sure thing. But remember, no coding while kicking—you might accidentally roundhouse your laptop!"

They both chuckled, resuming their training with renewed energy.


The original article appears here at the Technologist: Article 3 Streamlits.


Implementing Form Validation in Streamlit

In this tutorial, we'll explore how to implement form validation in a Streamlit application. Just as proper form is crucial in kickboxing, validating user input ensures your app runs smoothly and securely.

We'll break down the implementation into manageable steps. The great thing about Streamlits is the code is simple to understand without any complex component wiring or fancy callbacks. It is very easy to read and edit.

In this article, we'll dive deep into form handling and validation in Streamlit applications. Streamlit, a popular Python library for creating web applications, offers a straightforward approach to building interactive forms. However, it doesn't provide built-in form validation, which is crucial for ensuring data integrity and enhancing user experience.

Here's an overview of the key concepts and steps we'll cover:

  • Streamlit Form Handling: We'll explore how Streamlit manages forms using the st.form() context manager and the st.form_submit_button() for form submission.
  • Custom Validation Functions: We'll create custom Python functions to validate different types of input, such as names, email addresses, phone numbers, and dates.
  • Real-time Validation: We'll implement immediate feedback as users input data, enhancing the user experience.
  • Session State Management: We'll use Streamlit's session state to persist form data across app reruns, ensuring a smooth user experience.
  • Form Layout and Design: We'll structure our form using Streamlit's layout options, including columns and sections, for a clean and organized appearance.
  • Error Handling and Feedback: We'll display appropriate error messages and success indicators based on validation results.

By the end of this tutorial, you'll have a comprehensive understanding of how to implement robust form validation in your Streamlit applications, combining the simplicity of Streamlit with the power of custom Python validation logic.



Let's outline the key steps we'll cover in implementing form validation in Streamlit:

  1. Setting up the Streamlit environment and importing necessary libraries
  2. Creating custom validation functions for different input types: Name validation Email validation Phone number validation Age validation Date validation
  3. Implementing session state management to persist form data
  4. Designing the form layout using Streamlit components: Personal information section Contact information section Age and birth date section
  5. Integrating real-time validation feedback
  6. Handling form submission and displaying results
  7. Testing the form with various input scenarios
  8. Best practices and tips for form validation in Streamlit

By following these steps, we'll create a robust, user-friendly form with comprehensive validation in Streamlit.

Setting Up the Project

First, let's set up the project environment and install the required packages.

Create and activate a virtual environment:

# Create and activate virtual environment
python -m venv venv
source venv/bin/activate  # On Windows: venv\\\\Scripts\\\\activate

        

Install Streamlit:

pip install streamlit

        

Create the application file:

touch form_validation.py

        

Step-by-Step Guide to Form Validation

1. Import Required Libraries

import streamlit as st
import re
from datetime import datetime, date, timedelta

        

These imports provide us with the necessary functions for handling dates, regular expressions, and Streamlit components.

2. Define Validation Functions

Creating separate functions for each validation makes the code modular and reusable.

2.1 Name Validation

def validate_name(name, field_name="Name"):
    if not name:
        return False, f"{field_name} is required"
    if not re.match(r'^[A-Za-z\\\\s-]+$', name):
        return False, f"{field_name} should only contain letters, spaces, and hyphens"
    if len(name) < 2:
        return False, f"{field_name} should be at least 2 characters long"
    return True, ""

        

This function, validate_name(), is designed to validate a name input. Here's a detailed breakdown of its functionality:

  • Flexibility: The function can be easily adapted for various name-related fields by changing the field_name parameter when calling it.
  • Purpose: Ensures the name contains only letters, spaces, and hyphens, and is at least two characters long.
  • Regex Explanation: ^[A-Za-z\\\\s-]+$ matches one or more letters, spaces, or hyphens from start to end.
  • Input Parameters: name: The name string to be validated field_name: An optional parameter to specify which field is being validated (default is "Name")
  • Validation Steps: Empty Check: If the name is empty, it returns False with an error message. Character Check: Uses a regular expression ^[A-Za-z\\\\s-]+$ to ensure the name only contains letters, spaces, and hyphens. Length Check: Verifies that the name is at least 2 characters long.
  • Return Value: A tuple containing a boolean (True if valid, False if invalid) and a string (empty for valid, error message for invalid)
  • Error Messages: Customized based on the field_name parameter, allowing reuse for different name fields (e.g., first name, last name)

2.2 Email Validation

def validate_email(email):
    pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[a-zA-Z]{2,}$'
    if not re.match(pattern, email):
        return False, "Please enter a valid email address"
    return True, ""

        

Purpose: Validates the email format using a regular expression.

The email validation function uses a regular expression pattern to check if the provided email address is in a valid format. Here's a breakdown of the pattern:

  • ^[a-zA-Z0-9._%+-]+: Matches one or more alphanumeric characters, dots, underscores, percent signs, plus signs, or hyphens at the start of the email address (username part).
  • @: Matches the @ symbol separating the username from the domain.
  • [a-zA-Z0-9.-]+: Matches one or more alphanumeric characters, dots, or hyphens for the domain name.
  • \\\\.: Matches a literal dot (escaped with a backslash).
  • [a-zA-Z]{2,}$: Matches two or more letters at the end of the email address (top-level domain).

If the email doesn't match this pattern, the function returns False with an error message. Otherwise, it returns True with an empty string, indicating a valid email format.

2.3 Phone Validation

def validate_phone(phone):
    pattern = r'^\\\\(?([0-9]{3})\\\\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$'
    if not re.match(pattern, phone):
        return False, "Please enter a valid phone number"
    return True, ""

        

  • Purpose: Checks if the phone number matches common U.S. formats.
  • Supports: Formats like (123) 456-7890, 123-456-7890, 1234567890.

The code above implements phone number validation using a regular expression pattern. Here's a detailed explanation of the regex pattern used:

  • ^: Matches the start of the string
  • \\\\(?: Optionally matches an opening parenthesis
  • ([0-9]{3}): Matches exactly three digits and captures them in a group
  • \\\\)?: Optionally matches a closing parenthesis
  • [-. ]?: Optionally matches a hyphen, dot, or space
  • ([0-9]{3}): Matches and captures another group of three digits
  • [-. ]?: Again, optionally matches a hyphen, dot, or space
  • ([0-9]{4}): Matches and captures a final group of four digits
  • $: Matches the end of the string

This pattern allows for flexibility in phone number formats while ensuring the basic structure of a 10-digit U.S. phone number is maintained.

2.4 Age Validation

def validate_age(age):
    try:
        age = int(age)
        if age < 0 or age > 120:
            return False, "Age must be between 0 and 120"
        return True, ""
    except ValueError:
        return False, "Please enter a valid number"

        

Purpose: Ensures the age is a valid integer between 0 and 120.

The validate_age() function is designed to ensure that the age entered by the user is valid. Here's a breakdown of its functionality:

  • Input: Takes an age value as input, which could be a string or an integer.
  • Conversion: Attempts to convert the input to an integer using int(age).
  • Range Check: Verifies that the age is between 0 and 120 years old, which covers all realistic human ages.
  • Error Handling: If the conversion fails (e.g., if a non-numeric value is entered), it catches the ValueError and returns an appropriate error message.
  • Return Value: Returns a tuple containing a boolean (True if valid, False if invalid) and a string (empty for valid, error message for invalid).

This function ensures that the age input is both numeric and within a reasonable range, providing appropriate feedback for invalid entries.

2.5 Date Validation

def validate_date(input_date, earliest_date=date(1990, 1, 1)):
    max_future_date = date.today() + timedelta(days=5 * 365)
    if input_date < earliest_date:
        return False, f"Date must be after {earliest_date.strftime('%Y-%m-%d')}"
    elif input_date > max_future_date:
        return False, f"Date cannot be more than 5 years in the future"
    return True, ""

        

Purpose: Validates that the date is within a reasonable range.

Example: Birth dates after 1990 and not more than five years into the future.

The validate_date() function is designed to ensure that a given date falls within an acceptable range. Here's a detailed breakdown of its functionality:

  • Input Parameters: input_date: The date to be validated earliest_date: An optional parameter setting the earliest acceptable date (default is January 1, 1990)
  • Date Range Calculation: Calculates max_future_date as 5 years from the current date
  • Validation Steps: Checks if the input date is before the earliest acceptable date Checks if the input date is more than 5 years in the future
  • Return Value: A tuple containing a boolean (True if valid, False if invalid) and a string (empty for valid, error message for invalid)
  • Error Messages: Provides specific error messages for dates that are too early or too far in the future

This function ensures that dates entered by users are within a reasonable range, preventing issues with unrealistic past or future dates.


3. Initialize Session State

if 'form_data' not in st.session_state:
    st.session_state.form_data = {
        'first_name': '',
        'last_name': '',
        'email': '',
        'phone': '',
        'age': '',
        'birth_date': date.today(),
        'start_date': date.today(),
        'end_date': date.today() + timedelta(days=1),
        'submitted': False
    }

        

Purpose: Stores form data persistently across reruns.

Why: Streamlit apps rerun on interactions; session state maintains the data.

This code snippet demonstrates the initialization of session state in a Streamlit application. Here's a breakdown of its functionality:

  • Session State Initialization: The code checks if 'form_data' exists in the session state. If not, it creates a dictionary with default values for various form fields.
  • Form Fields: The session state includes fields for personal information (first name, last name), contact details (email, phone), age, and various dates (birth date, start date, end date).
  • Default Values: Most string fields are initialized as empty strings. Age is set to an empty string, while date fields use the current date (date.today()).
  • Submission Flag: A 'submitted' boolean is included to track whether the form has been submitted.
  • Persistence: By storing these values in the session state, the application can maintain user input across reruns of the Streamlit app, providing a smoother user experience.

This initialization ensures that the form always has a consistent starting state, whether it's the user's first visit or a return to the page after navigation.


4. Create the Form Layout

4.1 Personal Information Section

with st.form("enhanced_validation"):
    st.header("?? Personal Information")

    col1, col2 = st.columns(2)
    with col1:
        first_name = st.text_input(
            "First Name",
            value=st.session_state.form_data['first_name']
        )
        # Real-time validation
        if first_name:
            is_valid, message = validate_name(first_name, "First name")
            if not is_valid:
                st.error(message)
            else:
                st.success("Valid first name!")

        

Explanation: Uses columns to place first and last name side by side.

Real-time Validation: Provides immediate feedback as the user types.

This code snippet demonstrates the creation of a form layout in Streamlit, focusing on the personal information section. Here's a breakdown of its key components:

  1. Form Creation: The code uses st.form("enhanced_validation") to create a form container.
  2. Section Header: It displays a header for the personal information section using st.header("?? Personal Information").
  3. Column Layout: The code creates two columns using st.columns(2) for a side-by-side layout of first and last name fields.
  4. Input Field: It uses st.text_input() to create a text input field for the first name, with the initial value retrieved from the session state.
  5. Real-time Validation: As the user types, it performs immediate validation of the first name using the validate_name() function.
  6. Feedback Display: Based on the validation result, it shows either an error message using st.error() or a success message using st.success().

This approach provides a user-friendly interface with instant feedback, enhancing the overall form-filling experience.

4.2 Contact Information

    st.header("?? Contact Information")
    email = st.text_input(
        "Email",
        value=st.session_state.form_data['email']
    )
    if email:
        is_valid, message = validate_email(email)
        if not is_valid:
            st.error(message)
        else:
            st.success("Valid email format!")

        

There's no special wiring required—the email validation code is straightforward and intuitive. It's both easy to write and easy to understand.

Purpose: Collects email and validates it on input.

The code snippet above demonstrates the implementation of email validation in a Streamlit form. Here's a detailed breakdown:

  • Email Input Field: Uses st.text_input() to create an input field for the user's email address.
  • Initial Value: The email field is pre-populated with the value stored in the session state (st.session_state.form_data['email']), ensuring persistence across app reruns.
  • Real-time Validation: As soon as the user enters or modifies the email, validation occurs.
  • Validation Logic: The validate_email() function is called to check the email format.
  • Error Handling: If the email is invalid, an error message is displayed using st.error().
  • Success Feedback: If the email is valid, a success message is shown using st.success().

This approach provides immediate feedback to the user, enhancing the user experience by catching and displaying errors in real-time, rather than waiting for form submission.

4.3 Age and Birth Date

    st.header("?? Personal Details")
    col3, col4 = st.columns(2)
    with col3:
        age = st.number_input(
            "Age",
            min_value=0,
            max_value=120,
            value=0 if not st.session_state.form_data['age'] else int(st.session_state.form_data['age'])
        )
        if age:
            is_valid, message = validate_age(age)
            if not is_valid:
                st.error(message)
            else:
                st.success("Valid age!")

        

Explanation: Ensures age is within a realistic range.

There's no special wiring required—the age validation code is straightforward and intuitive. It's both easy to write and easy to understand.

Behold, the age validation code so slick, it could slide into your form's DMs without breaking a sweat! It's so straightforward, it makes a straight line look like a pretzel. This code is the smooth operator of the validation world - James Bond in digital form, if you will.

It's like the Swiss Army knife of age checking - compact, efficient, and ready to tackle any age-related mischief faster than you can say "I swear I'm old enough to rent this car!" This validation is so intuitive, it practically reads your mind. It's the kind of code that makes other validators green with envy.

The point is, there's no special wiring required. It's just simple, easy-to-read Python code.


5. Implement Form Submission

    submitted = st.form_submit_button("Submit Form")
    if submitted:
        # Validate all fields
        validations = [
            validate_name(first_name, "First name"),
            validate_name(last_name, "Last name"),
            validate_email(email),
            validate_phone(phone),
            validate_age(age),
            validate_date(birth_date),
            (start_date < end_date, "Start date must be before end date")
        ]

        # Check if all validations pass
        if all(v[0] for v in validations):
            st.success("Form submitted successfully!")
            # Update session state
            st.session_state.form_data.update({
                'first_name': first_name,
                'last_name': last_name,
                'email': email,
                'phone': phone,
                'age': age,
                'birth_date': birth_date,
                'start_date': start_date,
                'end_date': end_date,
                'submitted': True
            })
            st.rerun()
        else:
            # Show all validation errors
            for valid, message in validations:
                if not valid:
                    st.error(message)

        

Explanation: Upon form submission, all fields undergo comprehensive validation.

Success: If all validations pass, the app updates the session state and reruns.

Errors: The user sees a clear display of any validation errors.

Let's break down the code step by step, similar to how we explained it for the consumer:

  1. Form Creation: The code uses st.form("enhanced_validation") to create a form container, grouping all input fields together.
  2. Personal Information Section: Uses st.columns(2) to create a two-column layout for first and last name fields. Implements real-time validation for each name field using the validate_name() function. Displays success or error messages immediately as the user types.
  3. Contact Information Section: Collects and validates email and phone number inputs. Uses validate_email() and validate_phone() functions for real-time validation. Provides immediate feedback on the validity of entered data.
  4. Personal Details Section: Uses another two-column layout for age and birth date inputs. Implements validate_age() and validate_date() functions for real-time validation. Ensures age is within a realistic range and birth date is valid.
  5. Schedule Section: Collects start and end dates using st.date_input(). Performs a simple validation to ensure the start date is before the end date.
  6. Form Submission: Uses st.form_submit_button() to create a submit button. On submission, performs a comprehensive validation of all fields. If all validations pass, updates the session state and reruns the app. If any validation fails, displays all relevant error messages.
  7. Session State Management: Initializes session state to store form data persistently across reruns. Updates session state when the form is successfully submitted.
  8. Sidebar Summary Display: Uses the create_sidebar_markdown() function to generate a summary of submitted data. Displays the summary in the sidebar when the form is successfully submitted. Includes a "Clear Form" button to reset all fields.

This structure provides a comprehensive, user-friendly form with real-time validation, persistent data storage, and a clear summary display, enhancing the overall user experience.


6. Display Submission Summary in Sidebar

if st.session_state.form_data['submitted']:
    if create_sidebar_markdown(st.session_state.form_data):
        # Clear form if button clicked
        for key in st.session_state.form_data:
            if key in ['start_date', 'end_date', 'birth_date']:
                st.session_state.form_data[key] = date.today()
            elif key == 'submitted':
                st.session_state.form_data[key] = False
            else:
                st.session_state.form_data[key] = ''
        st.rerun()

        

  • Purpose: Shows a summary of the submitted data in the sidebar.
  • Clear Form Functionality: Allows the user to reset the form and submit new data.


7. Create Sidebar Summary Function

def create_sidebar_markdown(form_data):
    """Create a markdown summary of form data for the sidebar."""
    st.sidebar.markdown("---")
    st.sidebar.title("? Submission Summary")

    # Personal Details Section
    st.sidebar.header(f"?? {form_data['first_name']} {form_data['last_name']}")

    # Contact Information
    st.sidebar.subheader("?? Contact Details")
    st.sidebar.markdown(f"""
    - ?? {form_data['email']}
    - ?? {form_data['phone']}
    """)

    # Personal Information
    st.sidebar.subheader("?? Personal Info")
    st.sidebar.markdown(f"""
    - ?? Age: {form_data['age']}
    - ?? Birth Date: {form_data['birth_date'].strftime('%Y-%m-%d')}
    """)

    # Schedule Information
    st.sidebar.subheader("?? Schedule")
    st.sidebar.markdown(f"""
    | Date Type | Value |
    |-----------|-------|
    | Start | {form_data['start_date'].strftime('%Y-%m-%d')} |
    | End | {form_data['end_date'].strftime('%Y-%m-%d')} |
    """)

    # Submission Details
    st.sidebar.markdown("---")
    st.sidebar.markdown(f"*Submitted: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}*")

    # Add Clear Form Button to Sidebar
    if st.sidebar.button("?? Clear Form"):
        return True
    return False

        

Explanation: Formats the submitted data into a readable summary using Markdown.

Features: Includes personal details, contact information, schedule, and a timestamp.

The above is not really part of form handling per se. It is just there so you can see what is going on with the form validation.


Full Code Listing

Here's the complete code for the form validation application.

import streamlit as st
from datetime import datetime, date, timedelta
import re

def create_sidebar_markdown(form_data):
    """Create a markdown summary of form data for the sidebar."""
    st.sidebar.markdown("---")
    st.sidebar.title("? Submission Summary")

    # Personal Details Section
    st.sidebar.header(f"?? {form_data['first_name']} {form_data['last_name']}")

    # Contact Information
    st.sidebar.subheader("?? Contact Details")
    st.sidebar.markdown(f"""
    - ?? {form_data['email']}
    - ?? {form_data['phone']}
    """)

    # Personal Information
    st.sidebar.subheader("?? Personal Info")
    st.sidebar.markdown(f"""
    - ?? Age: {form_data['age']}
    - ?? Birth Date: {form_data['birth_date'].strftime('%Y-%m-%d')}
    """)

    # Schedule Information
    st.sidebar.subheader("?? Schedule")
    st.sidebar.markdown(f"""
    | Date Type | Value |
    |-----------|-------|
    | Start | {form_data['start_date'].strftime('%Y-%m-%d')} |
    | End | {form_data['end_date'].strftime('%Y-%m-%d')} |
    """)

    # Submission Details
    st.sidebar.markdown("---")
    st.sidebar.markdown(f"*Submitted: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}*")

    # Add Clear Form Button to Sidebar
    if st.sidebar.button("?? Clear Form"):
        return True
    return False

def validate_name(name, field_name="Name"):
    """Validate name contains only letters, spaces, and hyphens."""
    if not name:
        return False, f"{field_name} is required"
    if not re.match(r'^[A-Za-z\\\\s-]+$', name):
        return False, f"{field_name} should only contain letters, spaces, and hyphens"
    if len(name) < 2:
        return False, f"{field_name} should be at least 2 characters long"
    return True, ""

def validate_email(email):
    """Validate email format."""
    pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[a-zA-Z]{2,}$'
    if not re.match(pattern, email):
        return False, "Please enter a valid email address"
    return True, ""

def validate_phone(phone):
    """Validate phone number format."""
    pattern = r'^\\\\(?([0-9]{3})\\\\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$'
    if not re.match(pattern, phone):
        return False, "Please enter a valid phone number"
    return True, ""

def validate_age(age):
    """Validate age is between 0 and 120."""
    try:
        age = int(age)
        if age < 0 or age > 120:
            return False, "Age must be between 0 and 120"
        return True, ""
    except ValueError:
        return False, "Please enter a valid number"

def validate_date(input_date, earliest_date=date(1990, 1, 1)):
    """Validate date is after 1989 and not more than 5 years in future."""
    max_future_date = date.today() + timedelta(days=5 * 365)
    if input_date < earliest_date:
        return False, f"Date must be after {earliest_date.strftime('%Y-%m-%d')}"
    elif input_date > max_future_date:
        return False, f"Date cannot be more than 5 years in the future"
    return True, ""

def main():
    st.title("? Enhanced Form Validation")

    # Initialize session state
    if 'form_data' not in st.session_state:
        st.session_state.form_data = {
            'first_name': '',
            'last_name': '',
            'email': '',
            'phone': '',
            'age': '',
            'birth_date': date.today(),
            'start_date': date.today(),
            'end_date': date.today() + timedelta(days=1),
            'submitted': False
        }

    # Display initial sidebar content
    if not st.session_state.form_data['submitted']:
        st.sidebar.title("?? Form Status")
        st.sidebar.info("Please fill out the form to see the summary.")

    # Main form
    with st.form("enhanced_validation"):
        st.header("?? Personal Information")

        # Name fields in columns
        col1, col2 = st.columns(2)
        with col1:
            first_name = st.text_input(
                "First Name",
                value=st.session_state.form_data['first_name']
            )
            if first_name:
                is_valid, message = validate_name(first_name, "First name")
                if not is_valid:
                    st.error(message)
                else:
                    st.success("Valid first name!")

        with col2:
            last_name = st.text_input(
                "Last Name",
                value=st.session_state.form_data['last_name']
            )
            if last_name:
                is_valid, message = validate_name(last_name, "Last name")
                if not is_valid:
                    st.error(message)
                else:
                    st.success("Valid last name!")

        # Contact Information
        st.header("?? Contact Information")
        email = st.text_input(
            "Email",
            value=st.session_state.form_data['email']
        )
        if email:
            is_valid, message = validate_email(email)
            if not is_valid:
                st.error(message)
            else:
                st.success("Valid email format!")

        phone = st.text_input(
            "Phone",
            value=st.session_state.form_data['phone'],
            help="Format: (123) 456-7890 or 123-456-7890"
        )
        if phone:
            is_valid, message = validate_phone(phone)
            if not is_valid:
                st.error(message)
            else:
                st.success("Valid phone number!")

        # Age and Birth Date
        st.header("?? Personal Details")
        col3, col4 = st.columns(2)
        with col3:
            age = st.number_input(
                "Age",
                min_value=0,
                max_value=120,
                value=0 if not st.session_state.form_data['age'] else int(st.session_state.form_data['age'])
            )
            if age:
                is_valid, message = validate_age(age)
                if not is_valid:
                    st.error(message)
                else:
                    st.success("Valid age!")

        with col4:
            birth_date = st.date_input(
                "Birth Date",
                value=st.session_state.form_data['birth_date']
            )
            if birth_date:
                is_valid, message = validate_date(birth_date)
                if not is_valid:
                    st.error(message)
                else:
                    st.success("Valid birth date!")

        # Schedule Information
        st.header("?? Schedule")
        col5, col6 = st.columns(2)
        with col5:
            start_date = st.date_input(
                "Start Date",
                value=st.session_state.form_data['start_date']
            )
        with col6:
            end_date = st.date_input(
                "End Date",
                value=st.session_state.form_data['end_date']
            )

        if start_date and end_date and start_date >= end_date:
            st.error("Start date must be before end date")

        submitted = st.form_submit_button("Submit Form")
        if submitted:
            # Validate all fields
            validations = [
                validate_name(first_name, "First name"),
                validate_name(last_name, "Last name"),
                validate_email(email),
                validate_phone(phone),
                validate_age(age),
                validate_date(birth_date),
                (start_date < end_date, "Start date must be before end date")
            ]

            # Check if all validations pass
            if all(v[0] for v in validations):
                st.success("Form submitted successfully!")
                # Update session state
                st.session_state.form_data.update({
                    'first_name': first_name,
                    'last_name': last_name,
                    'email': email,
                    'phone': phone,
                    'age': age,
                    'birth_date': birth_date,
                    'start_date': start_date,
                    'end_date': end_date,
                    'submitted': True
                })
                st.rerun()
            else:
                # Show all validation errors
                for valid, message in validations:
                    if not valid:
                        st.error(message)

    # Display summary in sidebar after successful submission
    if st.session_state.form_data['submitted']:
        if create_sidebar_markdown(st.session_state.form_data):
            # Clear form if button clicked
            for key in st.session_state.form_data:
                if key in ['start_date', 'end_date', 'birth_date']:
                    st.session_state.form_data[key] = date.today()
                elif key == 'submitted':
                    st.session_state.form_data[key] = False
                else:
                    st.session_state.form_data[key] = ''
            st.rerun()

if __name__ == "__main__":
    main()

        

Running the Application

To run the application, use the following command in your terminal:

streamlit run form_validation.py

        

Open the provided local URL in your web browser to interact with the app.


Conclusion

Implementing form validation in your Streamlit app ensures that collected data is reliable and meets the required criteria. This enhances both user experience and overall application robustness.

Just as mastering the perfect kick in kickboxing requires practice and attention to form, implementing effective form validation demands careful planning and testing. Keep iterating, and your app will soon be as strong and reliable as a seasoned martial artist.

Streamlit's simplicity in form validation stands out, especially when compared to other UI frameworks. While traditional web frameworks often require extensive setup and boilerplate code, Streamlit significantly streamlines this process.

In Streamlit, form validation integrates seamlessly into the app's flow. Built-in input widgets handle basic type checking automatically, and custom validation logic can be easily added using Python's standard libraries and control structures. This approach allows developers to focus on actual validation rules rather than grappling with complex form-handling mechanisms.

Moreover, Streamlit's reactive nature enables real-time validation feedback as users input data. This immediate response enhances user experience and reduces submission errors. The ability to display validation messages directly next to relevant input fields, as shown in our example, further simplifies the creation of user-friendly forms.

Compared to frameworks requiring separate client-side and server-side validation code or additional form-handling libraries, Streamlit's approach is refreshingly straightforward. It enables developers to implement robust form validation with just a few lines of Python code, making it an excellent choice for rapid prototyping and development of data-centric applications.


Rick and Chris finished their kickboxing class feeling invigorated and went to the coffee shop and completed some pair programming with Streamlits.

Rick: "Thanks for the guidance, Chris. With proper form in both kickboxing and coding, I feel unstoppable!"

Chris: Grins "Anytime! Remember, validation isn't just for code—it's also for making sure you don't accidentally kick your trainer!"

They both laughed, heading out with a sense of accomplishment and a plan to tackle their next coding challenge.


About the Author

Rick Hightower is a seasoned software engineer and technology enthusiast passionate about exploring cutting-edge data science and web development tools. With years of experience in the tech industry, Rick enjoys simplifying complex processes and making technology accessible to developers of all skill levels.

An advocate for continuous learning, Rick shares his knowledge through articles and tutorials, helping others navigate the ever-evolving software development landscape. His exploration of form validation in Streamlit demonstrates his commitment to empowering developers to create robust and user-friendly applications.

When not coding or writing, Rick can be found kickboxing, lifting weights, hiking or just blending his love for fitness with technology, or engaging in thought-provoking conversations about the future of tech with fellow enthusiasts.


Happy coding with Streamlit! If you have any questions or need more help, feel free to explore the official Streamlit documentation or reach out to the community.

要查看或添加评论,请登录