-2

I am creating a Python Flask application where the name of the user's account is being passed from a MySQL database into a Flask application where it can be used on webpages.

I've successfully been able to retrieve the first name from the user's credentials in the database using this:

if sha256_crypt.verify(userDetails['password'], str (data[0])):
    cursor.execute("SELECT fname FROM user_details WHERE email = %s;", (email, ))
    name = cursor.fetchone()
    session['user'] = name
    return redirect(url_for('success', name=name))

To explain what this snippet does, once the user's entered login details have been checked against the database and authorised, the query pulls the first name from the user_details table and assigns it to the name variable, to which the name is used to initiate a session.

The user is then returned to the login page (now logged in) where another variable called name (I will probably change this so it's easier to differentiate) is passed the name that is stored in the session to display on the website using this function:

@app.route('/loginpage', methods=['POST', 'GET'])
def loginpage():
    if 'user' in session:
        name = session['user']
        return render_template('login.html', name=name, loggedOut=False, loggedIn=True)
    return render_template('login.html', loggedOut=True, loggedIn=False)

This is all successfully working and retrieves the user's first name from the database, the only problem though is that when the name is displayed with {{name}} in the HTML, the name shows up as ('John',), which means for example this:

<div class="container logout-greeting">
    <h5 style="text-align: center">Hello {{name}}, it appears you are logged in, click here to log out</h5>
</div>

Which should display as:

"Hello John, it appears you are logged in, click here to log out"

Is instead displaying as:

"Hello ('John,'), it appears you are logged in, click here to log out"

I've checked with someone that is more experienced with building Web Applications and they couldn't spot the issue, so is it possible anyone else could give me a pointer as to what is causing this?

davidism
  • 121,510
  • 29
  • 395
  • 339

2 Answers2

1

cursor.fetchone() returns all the selected fields from one row as a tuple. For example, if you did something like SELECT first, last ..., you'd get a 2-tuple ("John", "Smith").

You only requested one field, so you get 1-tuple ("John",): you do not get a string "John"! Change to:

name = cursor.fetchone()[0]

EDIT: Or, as Vincent warns below, more robustly:

row = cursor.fetchone()
name = row[0] if row else None

See How to create a tuple with only one element for discussion of 1-tuples, and why there is a comma there.

Amadan
  • 191,408
  • 23
  • 240
  • 301
0

cursor.fetchone() returns a tuple (similar to a list) containing all columns of the row. Its string representation looks like this.

You can solve this by selecting the first item in the response:

values = cursor.fetchone()
if values:
    name = values[0]
Vincent
  • 482
  • 4
  • 15
  • It does not return a set. A set has no ordering, and can't have multiples of the same value. If it was a set, and you selected a first and a last name, you could not know if you got a Regina George or a George Regina, and if someone was called Jerome Jerome you would just get a single Jerome back. – Amadan Apr 26 '22 at 00:01
  • You are right, it returns a tuple. I confused the two for a moment. :) I updated my answer accordingly. – Vincent Apr 26 '22 at 00:02
  • 1
    Also, `cursor.fetchone()` returns `None` if no further rows are found, not a 0-tuple. This will generate `TypeError: object of type 'NoneType' has no len()` when no rows are found. – Amadan Apr 26 '22 at 00:05