Modifying and Querying Data
***************************


Insert, Update, Delete
======================

See SQLAlchemy's ORM tutorial and other SQLAlchemy documentation for
more information about modifying data with the ORM.

To insert data, pass the model object to "db.session.add()":

   user = User()
   db.session.add(user)
   db.session.commit()

To update data, modify attributes on the model objects:

   user.verified = True
   db.session.commit()

To delete data, pass the model object to "db.session.delete()":

   db.session.delete(user)
   db.session.commit()

After modifying data, you must call "db.session.commit()" to commit
the changes to the database. Otherwise, they will be discarded at the
end of the request.


Select
======

See SQLAlchemy's Querying Guide and other SQLAlchemy documentation for
more information about querying data with the ORM.

Queries are executed through "db.session.execute()". They can be
constructed using "select()". Executing a select returns a "Result"
object that has many methods for working with the returned rows.

   user = db.session.execute(db.select(User).filter_by(username=username)).scalar_one()

   users = db.session.execute(db.select(User).order_by(User.username)).scalars()


Queries for Views
=================

If you write a Flask view function it's often useful to return a "404
Not Found" error for missing entries. Flask-SQLAlchemy provides some
extra query methods.

* "SQLAlchemy.get_or_404()" will raise a 404 if the row with the given
  id doesn't exist, otherwise it will return the instance.

* "SQLAlchemy.first_or_404()" will raise a 404 if the query does not
  return any results, otherwise it will return the first result.

* "SQLAlchemy.one_or_404()" will raise a 404 if the query does not
  return exactly one result, otherwise it will return the result.

   @app.route("/user-by-id/<int:id>")
   def user_by_id(id):
       user = db.get_or_404(User, id)
       return render_template("show_user.html", user=user)

   @app.route("/user-by-username/<username>")
   def user_by_username(username):
       user = db.one_or_404(db.select(User).filter_by(username=username))
       return render_template("show_user.html", user=user)

You can add a custom message to the 404 error:

      user = db.one_or_404(
          db.select(User).filter_by(username=username),
          description=f"No user named '{username}'."
      )


Legacy Query Interface
======================

You may see uses of "Model.query" or "session.query" to build queries.
That query interface is considered legacy in SQLAlchemy. Prefer using
the "session.execute(select(...))" instead.

See Legacy Query Interface for documentation.
