EpicEvents Journal

Displaying Tables in Terminal Using tabulate


In this project, I used the tabulate library to display formatted tables in the terminal. The pretty table format was chosen to enhance the readability of the displayed data. Below is an explanation of the key functions related to displaying tables:

1. display_table_title Function

This function prints the title of the table with specified styling, ensuring that the title is centered with padding for better visibility. It also raises an error if the title text is empty or None.

Example:

def display_table_title(text):
    if text is None or text.strip() == "":
        raise ValueError("Title text cannot be empty or None")
    styled_text = f"{'':^3}{text} {'':^3}"
    style_text_display(styled_text, color=CYAN, bold=True)

2. display_info Function

This function prints information regarding the filtering of the dataset (for example, the fields being ordered). It lists whether the fields are in ascending or descending order, providing clarity on the filter applied to the data.

Example:

def display_info(order_by_fields):
    if order_by_fields is None:
        raise ValueError("Info cannot be None")
    ordering_info = []
    for item in order_by_fields:
        if item.startswith("-"):
            field = item[1:]
            ordering_info.append(f"descending {field}")
        else:
            ordering_info.append(f"ascending {item}")
    styled_text = f"{'':^3}{ordering_info} {'':^3}"
    style_text_display(styled_text, color=WHITE)

3. create_pretty_table Function

This is the main function responsible for creating and displaying the table. It takes the following parameters:

      • table_list: List of lists containing the rows of the table.
      • title: Optional title for the table.
      • headers: Optional headers for the columns.
      • order_by_fields: Optional fields used for filtering and displaying information about the filter applied.

The function uses tabulate to format the table and adds indentation to make the table more readable. It also handles the case where no data is available.

Example:

def create_pretty_table(table_list, title=None, headers=None, order_by_fields=None):
    if not table_list:
        print("No data available to create table.")
        return

    if title:
        display_table_title(title)

    if order_by_fields:
        display_info(order_by_fields)

    table_format = "pretty"
    if headers is not None:
        table = tabulate(table_list, headers=headers, tablefmt=table_format)
    else:
        table = tabulate(table_list, tablefmt=table_format)

    indented_table = "\n".join("   " + line for line in table.split("\n"))
    print(indented_table)
    display_new_line()

4. create_model_table Function

This function is designed to create a table based on a Django model. It retrieves all items from the model and displays them in a tabular format. The function also handles nested attributes if the column label contains a dot notation (e.g., address.city).

Example:

def create_model_table(model, column_label, title):
    all_items = model.objects.all()
    all_items_list = []

    if all_items:
        for item in all_items:
            if "." in column_label:
                # Handle nested attributes
                attribute_chain = column_label.split(".")
                attribute_value = item
                for attr in attribute_chain:
                    attribute_value = getattr(attribute_value, attr)
                column_title = attribute_chain[-1].title()
            else:
                attribute_value = getattr(item, column_label)
                column_title = column_label.title()

            all_items_table = [column_title + ": ", attribute_value]
            all_items_list.append(all_items_table)

        create_pretty_table(all_items_list, f"All {title}: ")
    else:
        create_info_message(f"No table available, until now!")

5. create_queryset_table Function

This function creates a formatted table based on a Django queryset. It accepts parameters such as title, label, headers, and order_by_fields, and it is capable of handling both labeled rows and headers.

Example:

def create_queryset_table(queryset, title, label=None, headers=None, order_by_fields=None):
    if not queryset:
        create_info_message("No data available!")
        return

    all_items_list = []
    if label is not None:
        for item in queryset.values():
            item_table = [label + ": ", item]
            all_items_list.append(item_table)
        create_pretty_table(all_items_list, f"All {title}: ", order_by_fields=order_by_fields)

    if headers is not None:
        for key, values in queryset.items():
            item_table = [f"{key}: "]
            for value in values.values():
                item_table.append(value)
            all_items_list.append(item_table)

        create_pretty_table(all_items_list, headers=headers, title=f"All {title}: ", order_by_fields=order_by_fields)

Summary

The tabulate library was utilized in this project to present data in a clean and readable format within the terminal. Several utility functions were created to handle:

    • Displaying titles and additional information.
    • Formatting the table based on the data passed to it.
    • Handling optional headers, labels, and filters.
    • Displaying information related to the filters applied to the data.

This structured approach to displaying data ensures that users can easily understand and navigate through large sets of information in the terminal.


Designed by BootstrapMade and modified by DoriDoro