[Python] Displayed data disappears after successfully adding data to sqlite database

Discussão em 'Python' iniciado por Stack, Dezembro 1, 2025.

  1. Stack

    Stack Membro Participativo

    Please help me! I'm building a simple stock search app using Flask (backend) and plain HTML/JS (frontend). When the user enters a ticker, the app:

    Send a GET request to my Flask backend (/search)

    Display the stock data returned from the Tiingo API

    After successful display, send a POST request to /add_to_history to store the ticker in a SQLite database

    The GET request works correctly — the data displays as expected in my table.

    The problem: As soon as the POST request (/add_to_history) returns a 200 response, the table that was displaying the fetched stock data immediately disappears from the page. There are no errors in the console, and both network requests return status 200. The UI simply hides the content right after the POST call finishes. Here is my index.html code

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="style.css">
    <title>Stock App</title>
    <script>
    window.stockData = {
    "companyOutLook": null,
    "stockSummary": null
    }
    function onBtnClick(event) {
    event.preventDefault();
    const inputField = document.getElementById('stockTicker');
    const tickerSymbol = inputField.value;

    fetch(`http://127.0.0.1:5000/search?ticker=${encodeURIComponent(tickerSymbol)}`)
    .then(response => {
    if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
    }
    return response.json();
    })
    .then(data => {
    console.log('Data received:', data);
    // Check if response contains an error
    if (data.error) {

    hideTabsAndTable();
    showErrorMessage();
    return;
    }
    // Store data for later use
    if (Array.isArray(data) && data.length > 0) {
    window.stockData.companyOutLook = data[0];
    if (data.length > 1) {
    window.stockData.stockSummary = data[1];
    }
    else {
    window.stockData.stockSummary = null;
    }

    // Show tabs and table when data is available
    hideErrorMessage();

    showTabsAndTable();
    showCompanyOutlook();
    // add to sqlite history
    fetch(`http://127.0.0.1:5000/add_to_history`, {
    method: 'POST',
    headers: {
    'Content-Type': 'application/json',
    },
    body: JSON.stringify({ticker: tickerSymbol}),
    })
    .then(response => {
    console.log('Response:', response);

    })
    .catch(error => {
    console.error('Error:', error);
    });
    }
    else {
    window.stockData.companyOutLook = null;
    window.stockData.stockSummary = null;
    hideTabsAndTable();
    showErrorMessage();
    }

    })
    .catch(error => {
    hideTabsAndTable();
    showErrorMessage();
    });
    }

    function showTabsAndTable() {
    const tabs = document.querySelector('.tabs');
    const table = document.querySelector('.content');
    if (tabs) tabs.style.display = 'flex';
    if (table) table.style.display = 'table';
    }

    function hideTabsAndTable() {
    const tabs = document.querySelector('.tabs');
    const table = document.querySelector('.content');
    if (tabs) tabs.style.display = 'none';
    if (table) table.style.display = 'none';
    }

    function showCompanyOutlook() {
    const table = document.querySelector('.content');
    table.innerHTML = '';

    const rows = [
    'Company Name',
    'Ticker Symbol',
    'Exchange Code',
    'Start Date',
    'Description'
    ];
    const dataNames = [
    "name",
    "ticker",
    "exchangeCode",
    "startDate",
    "description"
    ]
    if (window.stockData.companyOutLook) {
    rows.forEach((header, i) => {
    const row = document.createElement('tr');
    const headerCell = document.createElement('td');
    headerCell.className = 'content-header';
    headerCell.textContent = header;
    const dataCell = document.createElement('td');
    dataCell.className = 'content-data';
    const value = window.stockData.companyOutLook[dataNames] ?? '';
    dataCell.textContent = value;
    row.appendChild(headerCell);
    row.appendChild(dataCell);
    table.appendChild(row);
    });
    }
    else {
    table.innerHTML = "<tr><td colspan='2'><p>Error: No record has been found, please enter a valid symbol.</p></td></tr>";
    }



    // Update active tab styling
    updateActiveTab(0);
    }

    function showStockSummary() {
    const table = document.querySelector('.content');
    table.innerHTML = '';

    const rows = [
    'Ticker Symbol',
    'Trading Day',
    'Previous Closing Price',
    'Opening Price',
    'High Price',
    'Low Price',
    'Last Price',
    'Change',
    'Change Percent',
    'Number of Shares Traded'
    ];
    if (window.stockData.stockSummary) {
    const summary = window.stockData.stockSummary;
    const last = Number(summary.last ?? summary.tngoLast ?? 0);
    const prevClose = Number(summary.prevClose ?? 0);
    const change = prevClose ? last - prevClose : 0;
    const changePercent = prevClose ? (change / prevClose) * 100 : 0;


    const tradingDay = summary.timestamp
    ? String(summary.timestamp).split('T')[0]
    : '';

    const data = [
    summary.ticker ?? '',
    tradingDay,
    prevClose || '',
    summary.open ?? '',
    summary.high ?? '',
    summary.low ?? '',
    last || '',
    (change > 0 ? "+" + change.toFixed(2) : change < 0 ? change.toFixed(2) : "0") || '',
    (changePercent > 0 ? "+" + changePercent.toFixed(2) + "%" : changePercent < 0 ? changePercent.toFixed(2) + "%" : "0%") || '',
    summary.volume ?? '',
    ];

    rows.forEach((header, i) => {
    const row = document.createElement('tr');
    const headerCell = document.createElement('td');
    headerCell.className = 'content-header';
    headerCell.textContent = header;
    const dataCell = document.createElement('td');
    dataCell.className = 'content-data';
    dataCell.id = `data-${i}`;
    dataCell.textContent = data;
    row.appendChild(headerCell);
    row.appendChild(dataCell);
    table.appendChild(row);
    });

    // add image to data 7 and 8
    const data7 = document.getElementById('data-7');
    const data8 = document.getElementById('data-8');
    if (data7 && data7.textContent.includes("+")) {
    data7.innerHTML += "<img src='GreenArrowUP.png' alt='Green Arrow Up' width='10' height='10' />"
    } else if (data7 && data7.textContent.includes("-")) {
    data7.innerHTML += "<img src='RedArrowDown.png' alt='Red Arrow Down' width='10' height='10' />"
    }
    if (data8 && data8.textContent.includes("+")) {
    data8.innerHTML += "<img src='GreenArrowUP.png' alt='Green Arrow Up' width='10' height='10' />"
    } else if (data8 && data8.textContent.includes("-")) {
    data8.innerHTML += "<img src='RedArrowDown.png' alt='Red Arrow Down' width='10' height='10' />"
    }

    }
    else {
    table.innerHTML = "<p>Error: No record has been found, please enter a valid symbol.</p>";
    }


    // Update active tab styling
    updateActiveTab(1);
    }

    function updateActiveTab(activeIndex) {
    const tabs = document.querySelectorAll('.tabs > div');
    tabs.forEach((tab, index) => {
    if (index === activeIndex) {
    tab.classList.add('active');
    } else {
    tab.classList.remove('active');
    }
    });
    }

    function showErrorMessage() {
    const errorMessage = document.querySelector('.error-message');
    errorMessage.style.display = 'block';
    }
    function hideErrorMessage() {
    const errorMessage = document.querySelector('.error-message');
    errorMessage.style.display = 'none';
    }
    // Initialize tabs with click handlers
    document.addEventListener('DOMContentLoaded', function() {
    const tabs = document.querySelectorAll('.tabs > div');
    tabs[0].addEventListener('click', showCompanyOutlook);
    tabs[1].addEventListener('click', showStockSummary);
    // Search History tab - no action for now
    });
    function clearInput() {
    const inputField = document.getElementById('stockTicker');
    inputField.value = '';
    window.stockData.companyOutLook = null;
    window.stockData.stockSummary = null;
    hideTabsAndTable();
    hideErrorMessage();
    }
    </script>
    </head>
    <body>
    <div class="container">
    <h1>Stock Search</h1>
    <form onsubmit="onBtnClick(event)">
    <span>Enter Stock Ticker Symbol<span class="required">*</span></span>
    <input type="text" id="stockTicker" required>
    <div class="buttons">
    <button type="submit" >Search</button>
    <button type="button" onclick="clearInput()">Clear</button></div>
    </form>

    </div>
    <div class="divider"></div>


    <div class="error-message" style="display: none;">
    <p>Error: No record has been found, please enter a valid symbol.</p>
    </div>

    <div class="tabs" style="display: none;">
    <div>Company Outlook</div>
    <div>Stock Summary</div>
    <div>Search History</div>
    </div>

    <table class="content" style="display: none;">
    <!-- Table rows will be dynamically generated by JavaScript -->
    <tbody id="table-body"></tbody>
    </table>

    </body>
    </html>


    Here is the app.py file

    from flask import Flask, request, jsonify
    from flask_cors import CORS
    import requests
    import sqlite3
    app = Flask(__name__)
    CORS(app, resources={r"/search*": {"origins": "*"}, r"/add_to_history*": {"origins": "*"}})
    API_KEY = "SECRET_API_KEY"
    DB_NAME = "search_history.db"
    @app.route('/')
    def index():
    return "Hello, World!"


    def init_db():
    with sqlite3.connect(DB_NAME) as conn:
    conn.execute('''CREATE TABLE IF NOT EXISTS SearchHistory (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    ticker TEXT NOT NULL,
    timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
    )''')

    # initialize the database
    # run init_db() when the app starts
    init_db()

    @app.route('/history', methods=['GET'])
    def get_search_history():
    with sqlite3.connect(DB_NAME) as conn:
    conn.row_factory = sqlite3.Row
    rows = conn.execute('SELECT ticker, timestamp FROM SearchHistory LIMIT 10').fetchall()
    results = [dict(row) for row in rows]
    return jsonify(results)


    @app.route('/add_to_history', methods=['POST'])
    def add_to_history():
    try:
    data = request.get_json()
    if not data:
    return jsonify({'error': 'No JSON data provided'}), 400

    ticker = data.get('ticker')
    if not ticker:
    return jsonify({'error': 'Ticker is required'}), 400

    with sqlite3.connect(DB_NAME) as conn:
    conn.execute('INSERT INTO SearchHistory(ticker) VALUES (?)', (ticker,))
    conn.commit()

    return jsonify({'message': 'Record added to history'}), 200
    except Exception as e:
    return jsonify({'error': str(e)}), 500

    def get_history():
    with sqlite3.connect(DB_NAME) as conn:
    conn.row_factory = sqlite3.Row
    rows = conn.execute('SELECT ticker, timestamp FROM SearchHistory LIMIT 10').fetchall()
    results = [dict(row) for row in rows]
    return results


    @app.route('/search', methods=['GET'])
    def search():
    try:
    ticker = request.args.get('ticker', "")
    # if not ticker is passed, return error message
    if not ticker:
    return jsonify({'error': "No record has been found, please enter a valid symbol" })

    # define a return object
    results = []
    # fetch company outlook tab
    url = f"https://api.tiingo.com/tiingo/daily/{ticker}?token={API_KEY}"
    response = requests.get(url)
    data = response.json()
    if data and data.get('detail', "") != "Not found.":
    results.append(data)
    # fetch stock summary tab
    url = f"https://api.tiingo.com/iex/{ticker}?token={API_KEY}"
    response = requests.get(url)
    data = response.json()
    if data and len(data) > 0:
    results.append(data[0])
    # add to history if fetched successfully
    # if results:
    # add_to_history(ticker)

    return jsonify(results)

    except Exception as e:
    return jsonify({'error': str(e) })

    if __name__ == '__main__':
    app.run(debug=True)

    Continue reading...

Compartilhe esta Página