How to run Flask-Login, Flask-BrowserID and Flask-SQLAlchemy in harmony?
Question: **The Whole Point**

I am attempting to make a fairly basic website with Flask (noob!) and am
running into trouble with the user login system. I've decided that I want to
use Flask-Login, Flask-BrowserID (Mozilla Persona) and SQLAlchemy. I am going
to have Persona be the part that takes care of storing user passwords and
such, I am going to use Flask-Login once the user has been authenticated to
keep track of their sessions and I am going to use SQLAlchemy to store
everything in an sqlite3 db. I've done a lot of bouncing around and I think I
have almost finished these features, but I cannot seem to get back a specific
error.

**Update 1**

Based on the comment by davidism, I had to add db.Model to the User class.
Unfortunately, that solved the first error, but now there is a new one to deal
with. Traceback found below.

**The Question**

What gives? I am obviously missing something, but I cannot seem to find what
that is.

**Resources I have been working with**

  * Flask-BrowserID: <https://github.com/garbados/flask-browserid/wiki>
  * Flask-Login: <http://flask-login.readthedocs.org/en/latest/>
  * Flask-SQLAlchemy: <http://pythonhosted.org/Flask-SQLAlchemy/quickstart.html#a-minimal-application>
  * [Is it possible to store Python class objects in SQLite?](http://stackoverflow.com/questions/2047814/is-it-possible-to-store-python-class-objects-in-sqlite)
  * SQLAlchemy Docs: <http://docs.sqlalchemy.org/en/rel_0_9/orm/tutorial.html>
  * WORKING Flask-BrowserID: init.py">https://github.com/garbados/flask-browserid/blob/master/tests/**init**.py

**Additional Information**

Here is my main.py and index.html I am using with Flask and the Traceback I am
getting:

**MAIN.py**

    
    
    import sqlite3
    from flask import Flask, request, session, g, redirect, url_for, abort, render_template, flash
    from contextlib import closing
    import time
    from flask.ext.login import LoginManager, UserMixin
    from flaskext.browserid import BrowserID
    from flask.ext.sqlalchemy import SQLAlchemy
    
    ## SETUP
    DEBUG = True
    SECRET_KEY = 'development key'
    USERNAME = 'admin'
    PASSWORD = 'default'
    
    app = Flask(__name__)
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/flaskr.db'
    db = SQLAlchemy(app)
    app.config.from_object(__name__)
    
    app.config['BROWSERID_LOGIN_URL'] = "/login"
    app.config['BROWSERID_LOGOUT_URL'] = "/logout"
    app.config['SECRET_KEY'] = "deterministic"
    app.config['TESTING'] = True
    
    class User(UserMixin, db.Model):
        id = db.Column(db.Integer, primary_key=True)
        email = db.Column(db.UnicodeText, unique=True)
        firstname = db.Column(db.Unicode(40))
        lastname = db.Column(db.Unicode(40))
        date_register = db.Column(db.Integer)
        bio = db.Column(db.Text)
        facebook = db.Column(db.Unicode(1000))
        twitter = db.Column(db.Unicode(1000))
        website = db.Column(db.Unicode(1000))
        image = db.Column(db.LargeBinary)
    
        def __init__(self, email, firstname=None, lastname=None, date_register=None, bio=None, facebook=None, twitter=None, 
                        website=None, image=None):
            self.email = email
            self.firstname = firstname
            self.lastname = lastname
            self.date_register = time.time()
            self.bio = bio
            self.facebook = facebook
            self.twitter = twitter
            self.website = website
            self.image = image
            self.email = email
    
        def __repr__(self):
            return '<User %r>' % self.email
    
    ### Login Functions ###
    def get_user_by_id(id):
        """
        Given a unicode ID, returns the user that matches it.
        """
        for row in db.session.query(User).filter(User.id == id):
            if row is not None:
                return row.User
        return None
    
    def create_browserid_user(kwargs):
        """
        Takes browserid response and creates a user.
        """
        if kwargs['status'] == 'okay':
            user = User(kwargs['email'])
            db.session.add(user)
            db.session.commit()
            return user
        else:
            return None
    
    def get_user(kwargs):
        """
        Given the response from BrowserID, finds or creates a user.
        If a user can neither be found nor created, returns None.
        """
        import pdb; pdb.set_trace()
        # try to find the user
        for row in db.session.query(User).filter(User.email == kwargs.get('email')):
            if row is not None:
                return row.User
        for row in db.session.query(User).filter(User.id == kwargs.get('id')):
            if row is not None:
                return row.User
        # try to create the user
        return create_browserid_user(kwargs)
    
    login_manager = LoginManager()
    login_manager.user_loader(get_user_by_id)
    login_manager.init_app(app)
    
    browserid = BrowserID()
    browserid.user_loader(get_user)
    browserid.init_app(app)
    
    ### Routing ###
    @app.route('/')
    def home():
        return render_template('index.html')
    
    if __name__ == '__main__':
        app.run()
    

**INDEX.html**

    
    
    <html>
        <head>
            <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
            <script src="https://login.persona.org/include.js" type="text/javascript"></script>
            <script type="text/javascript">{{ auth_script|safe }}</script>
        </head>
        <body>
            {% if current_user.is_authenticated() %}
                <button id="browserid-logout">Logout</button>
            {% else %}        
                <button id="browserid-login">Login</button>
            {% endif %}
        </body>
    </html>
    

**Traceback**

    
    
    Traceback (most recent call last):
      File "/Library/Python/2.7/site-packages/flask/app.py", line 1701, in __call__
        return self.wsgi_app(environ, start_response)
      File "/Library/Python/2.7/site-packages/flask/app.py", line 1689, in wsgi_app
        response = self.make_response(self.handle_exception(e))
      File "/Library/Python/2.7/site-packages/flask/app.py", line 1687, in wsgi_app
        response = self.full_dispatch_request()
      File "/Library/Python/2.7/site-packages/flask/app.py", line 1360, in full_dispatch_request
        rv = self.handle_user_exception(e)
      File "/Library/Python/2.7/site-packages/flask/app.py", line 1358, in full_dispatch_request
        rv = self.dispatch_request()
      File "/Library/Python/2.7/site-packages/flask/app.py", line 1344, in dispatch_request
        return self.view_functions[rule.endpoint](**req.view_args)
      File "/Users/jzeller/Classes/CS494/main.py", line 106, in home
        return render_template('test.html')
      File "/Library/Python/2.7/site-packages/flask/templating.py", line 123, in render_template
        ctx.app.update_template_context(context)
      File "/Library/Python/2.7/site-packages/flask/app.py", line 692, in update_template_context
        context.update(func())
      File "/Library/Python/2.7/site-packages/flask_login.py", line 799, in _user_context_processor
        return dict(current_user=_get_user())
      File "/Library/Python/2.7/site-packages/flask_login.py", line 768, in _get_user
        current_app.login_manager._load_user()
      File "/Library/Python/2.7/site-packages/flask_login.py", line 348, in _load_user
        return self.reload_user()
      File "/Library/Python/2.7/site-packages/flask_login.py", line 312, in reload_user
        user = self.user_callback(user_id)
      File "/Users/jzeller/Classes/CS494/main.py", line 60, in get_user_by_id
        print "get_user_by_id - " + str(type(row.User)) + " - " + str(row.User)
    AttributeError: 'User' object has no attribute 'User'
    


Answer: ### Answer to original question

The `User` model needs to be a subclass of `db.Model` (or a mapped class) to
work with SQLAlchemy.

    
    
    class User(UserMixin, db.Model):
        ...
    

### Answer to first update

You don't seem to understand what is getting returned by session.query. If you
query a single model, the "rows" that are returned are instances of the model.
The rows will never be None. When you're checking for existence, you should
just use `.first()` if you are applying filters, or `.get(primary_key)` if you
are filtering by primary key. This gets the first result only since the users
are unique anyway

This is what your `get_user_by_id` should look like:

    
    
    def get_user_by_id(id):
        return User.query.get(id)
    

This is what your `get_user` should look like:

    
    
    def get_user(kwargs):
        u = User.query.filter(db.or_(
            User.id == kwargs.get('id'),
            User.email == kwargs.get('email')
        )).first()
        if u is None: # user didn't exist in db
            return create_browserid_user(kwargs)
        return u
    

