Skip to content

Commit

Permalink
Update flaskr and todo to use SQLAlchemy 2.0 style (#1253)
Browse files Browse the repository at this point in the history
  • Loading branch information
davidism authored Sep 9, 2023
2 parents 7d1ce4c + 144495a commit e5397f5
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 30 deletions.
6 changes: 3 additions & 3 deletions examples/flaskr/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Install

**Be sure to use the same version of the code as the version of the docs
you're reading.** You probably want the latest tagged version, but the
default Git version is the master branch.
default Git version is the main branch.

.. code-block:: text
Expand Down Expand Up @@ -42,7 +42,7 @@ Install Flaskr:
$ pip install -e .
Or if you are using the master branch, install Flask-SQLAlchemy from
Or if you are using the main branch, install Flask-SQLAlchemy from
source before installing Flaskr:

.. code-block:: text
Expand Down Expand Up @@ -79,7 +79,7 @@ Test
.. code-block:: text
$ pip install -e '.[test]'
$ pytest
$ python3 -m pytest
Run with coverage report:

Expand Down
10 changes: 8 additions & 2 deletions examples/flaskr/flaskr/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,16 @@
from flask import Flask
from flask.cli import with_appcontext
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.orm import DeclarativeBase

__version__ = (1, 0, 0, "dev")
__version__ = (1, 1, 0, "dev")

db = SQLAlchemy()

class Base(DeclarativeBase):
pass


db = SQLAlchemy(model_class=Base)


def create_app(test_config=None):
Expand Down
21 changes: 14 additions & 7 deletions examples/flaskr/flaskr/auth/models.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
from __future__ import annotations

from typing import TYPE_CHECKING

from sqlalchemy.orm import Mapped, mapped_column, relationship
from werkzeug.security import check_password_hash
from werkzeug.security import generate_password_hash

from flaskr import db

if TYPE_CHECKING:
from ..blog.models import Post

class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String, unique=True, nullable=False)
password_hash = db.Column(db.String, nullable=False)

posts = db.relationship("Post", back_populates="author")
class User(db.Model):
id: Mapped[int] = mapped_column(primary_key=True)
username: Mapped[str] = mapped_column(unique=True)
password_hash: Mapped[str]
posts: Mapped[list[Post]] = relationship("Post", back_populates="author")

def set_password(self, value):
def set_password(self, value: str) -> None:
"""Store the password as a hash for security."""
self.password_hash = generate_password_hash(value)

# allow password = "..." to set a password
password = property(fset=set_password)

def check_password(self, value):
def check_password(self, value: str) -> bool:
return check_password_hash(self.password_hash, value)
20 changes: 11 additions & 9 deletions examples/flaskr/flaskr/blog/models.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy import ForeignKey
from datetime import datetime
from datetime import timezone

Expand All @@ -7,25 +9,25 @@
from flaskr.auth.models import User


def now_utc():
def now_utc() -> datetime:
return datetime.now(timezone.utc)


class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
author_id = db.Column(db.ForeignKey(User.id), nullable=False)
created = db.Column(db.DateTime, nullable=False, default=now_utc)
title = db.Column(db.String, nullable=False)
body = db.Column(db.String, nullable=False)
id: Mapped[int] = mapped_column(primary_key=True)
author_id: Mapped[int] = mapped_column(ForeignKey("user.id"))
created: Mapped[datetime] = mapped_column(default=now_utc)
title: Mapped[str]
body: Mapped[str]

# User object backed by author_id
# lazy="joined" means the user is returned with the post in one query
author = db.relationship(User, lazy="joined", back_populates="posts")
author: Mapped[User] = relationship(lazy="joined", back_populates="posts")

@property
def update_url(self):
def update_url(self) -> str:
return url_for("blog.update", id=self.id)

@property
def delete_url(self):
def delete_url(self) -> str:
return url_for("blog.delete", id=self.id)
3 changes: 1 addition & 2 deletions examples/flaskr/setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ include_package_data = true
python_requires = >= 3.8
install_requires =
Flask>=2.2
Flask-SQLAlchemy>=3
SQLAlchemy>=1.4.18
Flask-SQLAlchemy>=3.1.0

[options.extras_require]
test =
Expand Down
23 changes: 16 additions & 7 deletions examples/todo/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,32 @@
from flask import request
from flask import url_for
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import Mapped, mapped_column


app = Flask(__name__)
app.secret_key = "Achee6phIexoh8dagiQuew0ephuga4Ih"
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///todo.sqlite"
db = SQLAlchemy(app)


def now_utc():
class Base(DeclarativeBase):
pass


db = SQLAlchemy(app, model_class=Base)


def now_utc() -> datetime:
return datetime.now(timezone.utc)


class Todo(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String, nullable=False)
text = db.Column(db.String, nullable=False)
done = db.Column(db.Boolean, nullable=False, default=False)
pub_date = db.Column(db.DateTime, nullable=False, default=now_utc)
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str]
text: Mapped[str]
done: Mapped[bool] = mapped_column(default=False)
pub_date: Mapped[datetime] = mapped_column(default=now_utc)


with app.app_context():
Expand Down

0 comments on commit e5397f5

Please sign in to comment.