Vamsee.
Vamsee.

Reputation: 299

sqlalchemy.exc.DataError: (psycopg2.errors.InvalidTextRepresentation) invalid input syntax for type integer: "B1"

I am tryng to login the admin on my flask app using ID, when i signup it is taking inputs perfectly, but while getting values from database(postgresql) it showing "DataError" I have taken input as alphanumeric in HTML form

here are my code:

in model.py i have written code for databese to make columns

model.py

class Admin(UserMixin, db.Model):
    id = db.Column(db.String(1000), primary_key=True )
    name = db.Column(db.String(1000))
    email = db.Column(db.String(100), unique=True)
    password = db.Column(db.String(100))
    timestamp = db.Column(db.DateTime)

in this auth.py I writen code for POST methods for signup and login

auth.py

@auth.route('/admin')
def admin():
    return render_template('admin.html')


@auth.route('/admin', methods=['POST'])
def admin_post():
    id = request.form.get('id')
    password = request.form.get('password')
    remember = True if request.form.get('remember') else False

admins = Admin.query.filter_by(id=id).first()

# check if the user actually exists
# take the user-supplied password, hash it, and compare it to the hashed password in the database
if not admins or not check_password_hash(admins.password, password):
    flash('Please check your login details and try again.')
    # if the user doesn't exist or password is wrong, reload the page
    return redirect(url_for('auth.admin'))

# if the above check passes, then we know the user has the right credentials
login_user(admins, remember=remember)
return redirect(url_for('main.adminOP'))


 @auth.route('/admin-signup')
 def adminsignup():
     return render_template('admin-signup.html')


 @auth.route('/admin-signup', methods=['POST'])
 def adminsignup_post():
     id = request.form.get('id')
     email = request.form.get('email')
     name = request.form.get('name')
     password = request.form.get('password')
     timestamp = datetime.now()

# if this returns a admin, then the email already exists in database
admins = Admin.query.filter_by(email=email).first()

if admins:  # if a user is found, we want to redirect back to signup page so user can try again
    flash('Email address already exists')
    return redirect(url_for('auth.adminsignup'))

# create a new user with the form data. Hash the password so the plaintext version isn't saved.
new_admin = Admin(id=id, email=email, name=name,
                  password=generate_password_hash(password, method='sha256'), timestamp=timestamp)

# add the new user to the database
db.session.add(new_admin)
db.session.commit()

return redirect(url_for('auth.admin'))

The error caught in trace back is:

sqlalchemy.exc.DataError: (psycopg2.errors.InvalidTextRepresentation) invalid input syntax for type 
integer: "B1"
LINE 3: WHERE person.id = 'B1'
                          ^

[SQL: SELECT person.id AS person_id, person.email AS person_email, person.password AS person_password, 
person.name AS person_name, person.timestamp AS person_timestamp
FROM person
WHERE person.id = %(pk_1)s]
[parameters: {'pk_1': 'B1'}]
(Background on this error at: http://sqlalche.me/e/14/9h9h)

Here B1 is id

admin-signup.html

As I said earlier I have used alhapanumeric in input field

{% extends "base.html" %}

{% block content %}
<div class="column is-4 is-offset-4">
    <h3 class="title has-text-info">Sign Up</h3>
    <div class="box">
        {% with messages = get_flashed_messages() %}
        {% if messages %}
        <div class="notification is-danger">
            {{ messages[0] }}. Go to <a href="{{ url_for('auth.admin') }}">login page</a>.
        </div>
        {% endif %}
        {% endwith %}
        <form method="POST" action="/admin-signup">
            <div class="field">
                <div class="control has-icons-left has-icons-right">
                    <input class="input is-large" type="text" name="id" placeholder="Your ID" autofocus="" pattern="[a-zA-Z0-9]+"><span
                        class="icon is-small is-left">
                        🆔
                    </span>
                    <small> Remember: ID is you employee number </small>
                </div>
            </div>
            <div class="field">
                <div class="control has-icons-left has-icons-right">
                    <input class="input is-large" type="email" aria-required="true" name="email" placeholder="Email"
                        autofocus=""><span class="icon is-small is-left">
                        📧
                    </span>
                </div>
            </div>

            <div class="field">
                <div class="control has-icons-left has-icons-right">
                    <input class="input is-large" type="text" aria-required="true" name="name" placeholder="Name"
                        autofocus=""><span class="icon is-small is-left">
                        👱
                    </span>
                </div>
            </div>

            <div class="field">
                <div class="control has-icons-left has-icons-right">
                    <input class="input is-large" type="password" aria-required="true" name="password"
                        placeholder="Password"><span class="icon is-small is-left">
                        🔑
                    </span>
                </div>
            </div>

            <button class="button is-block is-info is-large is-fullwidth">Sign Up</button>
        </form>
    </div>
</div>
{% endblock %}

admin.html

{% extends "base.html" %}

{% block content %}
<div class="column is-4 is-offset-4">
    <h3 class="title has-text-info">Admin Login</h3>
    <div class="box">
        {% with messages = get_flashed_messages() %}
        {% if messages %}
        <div class="notification is-danger">
            {{ messages[0] }}
        </div>
        {% endif %}
        {% endwith %}
        <form method="POST" action="/admin">
            <div class="field">
                <div class="control has-icons-left has-icons-right">
                    <input class="input is-large" type="text" name="id" placeholder="Your ID" autofocus="" required pattern="[a-zA-Z0-9]+"><span
                        class="icon is-small is-left">
                        🆔
                    </span>
                    <small> HINT: ID is you employee number </small>
                </div>
            </div>

            <div class="field">
                <div class="control has-icons-left has-icons-right">
                    <input class="input is-large" type="password" name="password" placeholder="Your Password"><span
                        class="icon is-small is-left">
                        🔑
                    </span>
                </div>
            </div>
            <div class="field">
                <label class="checkbox">
                    <input type="checkbox">
                    Remember me
                </label>
            </div>
            <button class="button is-block is-info is-large is-fullwidth">Login</button>
        </form>
    </div>
</div>
{% endblock %}

After editing code i got this same error caught in debugging enter image description here

this is person model

class person(UserMixin, db.Model):
    # primary keys are required by SQLAlchemy
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(100), unique=True)
    password = db.Column(db.String(100))
    name = db.Column(db.String(1000))
    timestamp = db.Column(db.DateTime)

Upvotes: 1

Views: 9207

Answers (1)

Magnun Leno
Magnun Leno

Reputation: 2738

The issue is that the column id from your person model is an Integer, not a string. Your load_user function queries the person model providing a key B1, which can not be converted to Integer.

If you intend to query your Admin model and also query your person model depending on who is logged, you should add an identifier in your user session during login and retrieve it in the load_user function. Check out this question for more details.

But if you need to treat your users differently (User#1 is an admin but User#2 is not), you should really consider using a boolean flag in your model, something like this:

class User(UserMixin, db.Model):
    id = db.Column(db.String(1000), primary_key=True )
    name = db.Column(db.String(1000))
    # ...
    is_admin = db.Column(db.Boolean)

You should really avoid having two user's models with different types of keys, it can get really messy over time.

If your Flask app tend to grow and have multiple kind of users, you should consider adopt the concept of 'user roles'. Check out Flask-Principal for this.

Old Answer

The issue is probably because your model and your database aren't synchronized. In some point the development processes you probably had id = db.Column(db.Integer, primary_key=True) then you ran db.create_all() and then altered the id to id = db.Column(db.String(1000), primary_key=True).

In simple words, Flask believes that id is a string, but PostgreSQL is sure that it is an int. Just to be sure, you could check the DDL of the table person with:

pg_dump -U your_user your_database -t person --schema-only

Note that flask/flask-sqlalchemy does not do automatic migrations, after changing your model you should recreate the database or apply the changes manually (the choice is up to you).

Upvotes: 1

Related Questions