Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update flaskr and todo to use SQLAlchemy 2.0 style #1253

Merged
merged 1 commit into from Sep 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 3 additions & 3 deletions examples/flaskr/README.rst
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
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):
pamelafox marked this conversation as resolved.
Show resolved Hide resolved
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
@@ -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
@@ -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
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
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