5

I am having a problem when trying to render a SQLAlchemy query into a template, the error I get is:

TypeError: 'Users' object is not iterable

The DB is a sqlite
I have been following the "Discover Real Python" tutorial on youtube and it has been a big help. The only things i have changed is in the tutorial he uses "BlogPosts", and I use "Users"

I am trying to understand how he got users to iterate in his version of the code in the template.

My Models.py file is this:

from app import db

class Users(db.Model):
    __tablename__="users"

    id= db.Column(db.Integer, primary_key=True)
    username=db.Column(db.String, nullable=False)
    password=db.Column(db.String, nullable=False)

    def __init__(self, username, password):
        self.username=username
        self.password=password

    def __repr__(self):
        return '<username{}'.format(self.username)

and my "app.py" file.

from flask import Flask, render_template, redirect, url_for, request, session, flash
from functools import wraps
#import sqlite3
from flask.ext.sqlalchemy import SQLAlchemy


app= Flask(__name__)

app.secret_key="this is the secret key"
#app.database="users.db"

app.config['SQLALCHEMY_DATABASE_URI']='sqlite:////users2.db'

db=SQLAlchemy(app)

from models import *

def login_required(f):
    @wraps(f)
    def wrap(*args, **kwargs):
        if 'logged_in' in session:
            return f(*args, **kwargs)
        else:
            flash('You must be logged in to complete this action')
            return redirect(url_for('login'))
    return wrap


@app.route('/')
def index():
    users= db.session.query(Users).all()
    return render_template('index.html', users=users)


@app.route('/testing')
def testing():
    users= db.session.query(Users).all()
    return render_template('testquery.html', users=users)


@app.route('/welcome')
def welcome():
    return render_template('index.html')


@app.route('/login', methods =['GET', 'POST'])
def login():
    error= None
    #form = LoginForm(request.form)
    if request.method == 'POST':
    #if request.form.validate_on_submit():
        if request.form['username'] !='admin' or request.form['password'] !='admin':
            error= 'invalid credentials'
        else:
            session ['logged_in']=True
            flash('login successful')
            return redirect(url_for('loggedin'))
    #else:
        #render_template('login.html', form=form, error=error)
    return render_template('login.html', error=error)


@app.route('/loggedin')
@login_required
def loggedin():
    return render_template('loggedin.html')


@app.route('/logout')
def logout():
    session.pop('logged_in', None)
    flash('You have been logged out')
    return redirect(url_for('welcome'))


#def connect_db():
#   return sqlite3.connect(app.database)

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

The method I have been using to text is the route of "/testing", the testquery.html file is what I have been trying to test with, and have been getting the error with.

<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
    <body>


        <table>
        {%for user in users%}
            <tr>
                <td>{{user.username}}</td>
                <td>{{user.password}}</td>
            </tr>

        </table>
        {%endfor%}

    </body>
</html>

I tried the fix i saw in another stack question:

def __init__(self, username, password):
    self.username=[username]
    self.password=[password]

To no avail, this changed nothing. Anyone have any idea what I need to do to make it iterable.

1
  • Please include the full traceback of the error. Commented Dec 8, 2014 at 21:27

1 Answer 1

5

In testing, you don't have a list of users. You have one user here:

users = db.session.query(Users).first()

This returns just the first user in your database. As such, you cannot loop over the user either. Rename that to user (dropping the s) and remove the loop in your template:

@app.route('/testing')
def testing():
    user = db.session.query(Users).first()
    return render_template('testquery.html', user=user)

and

<table>
  <tr>
    <td>{{user.username}}</td>
    <td>{{user.password}}</td>
  </tr>
</table>
Sign up to request clarification or add additional context in comments.

3 Comments

Edit made, while testing I changed a bunch of things. but I was originally using "all()"
@TheTimes: you do in the / route.
Ok, so I basically just did what you suggested, and got it to work. I then proceeded to change it back to what I had, and it magically worked :/ I hate when things happen like that, and im sure something changed, but it seemed like programming magic.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.