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

SQLalchemy ORM 2.0 #428

Closed
wants to merge 72 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
47c062f
Update tutorial.rst
cactuuus Jan 18, 2023
a0cf230
Update tutorial.rst
cactuuus Jan 18, 2023
711da2e
Update tutorial.rst
cactuuus Jan 19, 2023
37052a3
Update tutorial.rst
cactuuus Jan 19, 2023
1a7cfdb
Updated to SQLAlchemy 2.0
cactuuus Jan 19, 2023
8ea4d82
Merge branch 'patch-1'
cactuuus Jan 28, 2023
97b41d3
updated blog to SWLAlchemy 2.0 (ORM)
cactuuus Feb 6, 2023
7bdd424
Merge branch 'master' into master
Dreamsorcerer Feb 6, 2023
c0d403e
Update requirements.txt
cactuuus Feb 6, 2023
76c5265
Update to SQLAlchemy ORM 2.0
cactuuus Feb 6, 2023
64e5c91
Merge branch 'master' of https://github.com/cactuuus/aiohttp-demos
cactuuus Feb 6, 2023
b24fce0
update to SQLAlchemy 2.0
cactuuus Feb 12, 2023
0c3614d
Merge branch 'master' into master
Dreamsorcerer Feb 12, 2023
d1c53f6
Update conftest.py
cactuuus Feb 12, 2023
bfe68ff
Merge branch 'master' of https://github.com/cactuuus/aiohttp-demos
cactuuus Feb 12, 2023
d320e0a
Update conftest.py
cactuuus Feb 12, 2023
36a8d46
Update db_helpers.py
cactuuus Feb 12, 2023
309f61d
Update db_helpers.py
cactuuus Feb 12, 2023
8cdba93
Update db_helpers.py
cactuuus Feb 12, 2023
ea0414f
update SQLAlchemy 2.0
cactuuus Feb 12, 2023
35a2e80
Update db_auth.py
cactuuus Feb 26, 2023
d25c9bd
Merge branch 'master' into master
Dreamsorcerer Feb 26, 2023
bbf7be9
Update test_stuff.py
cactuuus Feb 26, 2023
dda2fe0
Merge branch 'master' of https://github.com/cactuuus/aiohttp-demos
cactuuus Feb 26, 2023
703ea67
Update test_stuff.py
cactuuus Feb 26, 2023
933c207
added async_sessiomaker
cactuuus Feb 26, 2023
9ddd004
Update db.py
cactuuus Feb 26, 2023
90011cd
update to SQLalchemy 2.0
cactuuus Feb 27, 2023
8840af1
Update db.py
Dreamsorcerer Feb 27, 2023
88372bc
Update ci.yml
Dreamsorcerer Feb 27, 2023
553c472
adding cleanup_ctx
cactuuus Feb 27, 2023
cc699d1
Merge branch 'master' of https://github.com/cactuuus/aiohttp-demos
cactuuus Feb 27, 2023
825ef59
Update db_auth.py
cactuuus Feb 27, 2023
9d816d2
updated polls & blog
cactuuus Aug 2, 2023
bb8ec8f
Merge branch 'master' into master
Dreamsorcerer Aug 2, 2023
31cc09d
Merge branch 'master' into master
Dreamsorcerer Aug 5, 2023
6f82f44
Update pytest.ini
Dreamsorcerer Aug 5, 2023
c2457ba
Update requirements-dev.txt
Dreamsorcerer Aug 7, 2023
9dfd626
Update requirements-dev.txt
Dreamsorcerer Aug 7, 2023
473e959
Merge branch 'master' into master
Dreamsorcerer Aug 7, 2023
9beb3b2
Update conftest.py
cactuuus Aug 9, 2023
87eaca2
Merge branch 'master' into master
Dreamsorcerer Aug 9, 2023
94f5b6b
Update requirements-dev.txt
Dreamsorcerer Aug 9, 2023
28eb880
Update tables.py
Dreamsorcerer Aug 24, 2023
ca33ee7
Merge branch 'master' into master
Dreamsorcerer Aug 24, 2023
9bba8e4
Update dataloaders.py
Dreamsorcerer Sep 19, 2023
b42d84d
Update and rename tables.py to models.py
Dreamsorcerer Sep 19, 2023
4cbbf24
Update db_utils.py
Dreamsorcerer Sep 19, 2023
20c74f0
Update dataloaders.py
Dreamsorcerer Sep 19, 2023
a5f43c6
Update db_utils.py
Dreamsorcerer Sep 19, 2023
212d446
Update and rename tables.py to models.py
Dreamsorcerer Sep 19, 2023
18515c5
Update rooms.py
Dreamsorcerer Sep 19, 2023
b118f34
Update db_utils.py
Dreamsorcerer Sep 19, 2023
ab37fd5
Update models.py
Dreamsorcerer Sep 19, 2023
5385e3d
Update conftest.py
Dreamsorcerer Sep 19, 2023
e8a4b0d
Update conftest.py
Dreamsorcerer Sep 19, 2023
68d336c
Update conftest.py
Dreamsorcerer Sep 19, 2023
c689d75
Update conftest.py
Dreamsorcerer Sep 19, 2023
7a22f6e
Update conftest.py
Dreamsorcerer Sep 19, 2023
e60eb13
Update conftest.py
Dreamsorcerer Sep 19, 2023
1471df3
Update conftest.py
Dreamsorcerer Sep 19, 2023
df84879
Update conftest.py
Dreamsorcerer Sep 19, 2023
3c470ef
Update test_chat_db_utils.py
Dreamsorcerer Sep 19, 2023
33987c2
Update conftest.py
Dreamsorcerer Sep 19, 2023
5085266
Update conftest.py
Dreamsorcerer Sep 19, 2023
6ff2a7a
Update db_utils.py
Dreamsorcerer Sep 23, 2023
0ce9eef
Update conftest.py
Dreamsorcerer Sep 23, 2023
3d16a86
Update conftest.py
Dreamsorcerer Sep 23, 2023
8afd023
Merge branch 'master' into master
Dreamsorcerer Mar 30, 2024
1263cb6
Update requirements-dev.txt
Dreamsorcerer Mar 30, 2024
cd2b27f
Update requirements.txt
cactuuus Mar 31, 2024
48982b0
downgraded aiohttp to version 3.8.5
cactuuus Mar 31, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ jobs:
make install
- name: Run tests
run: |
make test
PYTHONASYNCIODEBUG=1 make test

doc:
name: Documentation
Expand Down
96 changes: 44 additions & 52 deletions demos/blog/aiohttpdemo_blog/db.py
Original file line number Diff line number Diff line change
@@ -1,47 +1,50 @@
from datetime import datetime as dt
from datetime import datetime

import asyncpgsa
from sqlalchemy import (
MetaData, Table, Column, ForeignKey,
Integer, String, DateTime
)
from sqlalchemy import ForeignKey, String
from sqlalchemy.sql import select
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship, selectinload
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker

metadata = MetaData()
class Base(DeclarativeBase):
pass


users = Table(
'users', metadata,
class Users(Base):
__tablename__ = "users"

Column('id', Integer, primary_key=True),
Column('username', String(64), nullable=False, unique=True),
Column('email', String(120)),
Column('password_hash', String(128), nullable=False)
)
id: Mapped[int] = mapped_column(primary_key=True)
username: Mapped[str] = mapped_column(String(64), nullable=False, unique=True)
email: Mapped[str] = mapped_column(String(120))
password_hash: Mapped[str] = mapped_column(String(128), nullable=False)

posts: Mapped[list["Posts"]] = relationship(back_populates="user", lazy="raise_on_sql")

posts = Table(
'posts', metadata,

Column('id', Integer, primary_key=True),
Column('body', String(140)),
Column('timestamp', DateTime, index=True, default=dt.utcnow),
class Posts(Base):
__tablename__ = "posts"

id: Mapped[int] = mapped_column(primary_key=True)
body: Mapped[str] = mapped_column(String(140))
timestamp: Mapped[datetime] = mapped_column(index=True, default=datetime.utcnow)

user_id: Mapped[int] = mapped_column(ForeignKey("users.id"))
user: Mapped[Users] = relationship(back_populates="posts", lazy="raise_on_sql")


Column('user_id',
Integer,
ForeignKey('users.id'))
)


async def init_db(app):
dsn = construct_db_url(app['config']['database'])
pool = await asyncpgsa.create_pool(dsn=dsn)
app['db_pool'] = pool
return pool
engine = create_async_engine(dsn)
app['db_pool'] = async_sessionmaker(engine)

yield

await engine.dispose()


def construct_db_url(config):
DSN = "postgresql://{user}:{password}@{host}:{port}/{database}"
DSN = "postgresql+asyncpg://{user}:{password}@{host}:{port}/{database}"
return DSN.format(
user=config['DB_USER'],
password=config['DB_PASS'],
Expand All @@ -51,37 +54,26 @@ def construct_db_url(config):
)


async def get_user_by_name(conn, username):
result = await conn.fetchrow(
users
.select()
.where(users.c.username == username)
)
async def get_user_by_name(sess, username):
result = await sess.scalar(select(Users).where(Users.username == username))
return result


async def get_users(conn):
records = await conn.fetch(
users.select().order_by(users.c.id)
)
return records
async def get_users(sess):
records = await sess.scalars(select(Users).order_by(Users.id))
return records.all()


async def get_posts(conn):
records = await conn.fetch(
posts.select().order_by(posts.c.id)
)
return records
async def get_posts(sess):
records = await sess.scalars(select(Posts).order_by(Posts.id))
return records.all()


async def get_posts_with_joined_users(conn):
j = posts.join(users, posts.c.user_id == users.c.id)
stmt = select(
[posts, users.c.username]).select_from(j).order_by(posts.c.timestamp)
records = await conn.fetch(stmt)
return records
async def get_posts_with_joined_users(sess):
records = await sess.scalars(select(Posts).options(selectinload(Posts.user)).order_by(Posts.timestamp))
return records.all()


async def create_post(conn, post_body, user_id):
stmt = posts.insert().values(body=post_body, user_id=user_id)
await conn.execute(stmt)
async def create_post(sess, post_body, user_id):
new_post = Posts(body=post_body, user_id=user_id)
await sess.add(new_post)
12 changes: 6 additions & 6 deletions demos/blog/aiohttpdemo_blog/db_auth.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
from sqlalchemy.ext.asyncio import async_sessionmaker
from aiohttp_security.abc import AbstractAuthorizationPolicy

from aiohttpdemo_blog import db


class DBAuthorizationPolicy(AbstractAuthorizationPolicy):

def __init__(self, db_pool):
self.db_pool = db_pool
def __init__(self, app):
self.app = app

async def authorized_userid(self, identity):
async with self.db_pool.acquire() as conn:
user = await db.get_user_by_name(conn, identity)
async with self.app["db_pool"]() as sess:
user = await db.get_user_by_name(sess, identity)
if user:
return identity

return None

async def permits(self, identity, permission, context=None):
if identity is None:
return False
return True
return True
2 changes: 1 addition & 1 deletion demos/blog/aiohttpdemo_blog/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ async def validate_login_form(conn, form):

if not user:
return 'Invalid username'
if not check_password_hash(password, user['password_hash']):
if not check_password_hash(password, user.password_hash):
return 'Invalid password'

return None
4 changes: 2 additions & 2 deletions demos/blog/aiohttpdemo_blog/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ async def init_app(config):

setup_routes(app)

db_pool = await init_db(app)
app.cleanup_ctx.append(init_db)

redis = await setup_redis(app)
setup_session(app, RedisStorage(redis))
Expand All @@ -57,7 +57,7 @@ async def init_app(config):
setup_security(
app,
SessionIdentityPolicy(),
DBAuthorizationPolicy(db_pool)
DBAuthorizationPolicy(app)
)

log.debug(app['config'])
Expand Down
2 changes: 1 addition & 1 deletion demos/blog/aiohttpdemo_blog/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
{% block content %}
<h1>Hi, {{ user.username }}!</h1>
{% for post in posts %}
<div><p>[{{ post.timestamp.strftime('%Y-%m-%d %H:%M:%S') }}] {{ post.username }} posted: <b>{{ post.body }}</b></p></div>
<div><p>[{{ post.timestamp.strftime('%Y-%m-%d %H:%M:%S') }}] {{ post.user.username }} posted: <b>{{ post.body }}</b></p></div>
{% endfor %}
{% endblock %}
20 changes: 10 additions & 10 deletions demos/blog/aiohttpdemo_blog/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ async def index(request):
if not username:
raise redirect(request.app.router, 'login')

async with request.app['db_pool'].acquire() as conn:
current_user = await db.get_user_by_name(conn, username)
posts = await db.get_posts_with_joined_users(conn)
async with request.app['db_pool']() as sess:
current_user = await db.get_user_by_name(sess, username)
posts = await db.get_posts_with_joined_users(sess)

return {'user': current_user, 'posts': posts}

Expand All @@ -33,16 +33,16 @@ async def login(request):
if request.method == 'POST':
form = await request.post()

async with request.app['db_pool'].acquire() as conn:
error = await validate_login_form(conn, form)
async with request.app['db_pool']() as sess:
error = await validate_login_form(sess, form)

if error:
return {'error': error}
else:
response = redirect(request.app.router, 'index')

user = await db.get_user_by_name(conn, form['username'])
await remember(request, response, user['username'])
user = await db.get_user_by_name(sess, form['username'])
await remember(request, response, user.username)

raise response

Expand All @@ -64,9 +64,9 @@ async def create_post(request):
if request.method == 'POST':
form = await request.post()

async with request.app['db_pool'].acquire() as conn:
current_user = await db.get_user_by_name(conn, username)
await db.create_post(conn, form['body'], current_user['id'])
async with request.app['db_pool'].begin() as sess:
current_user = await db.get_user_by_name(sess, username)
await db.create_post(sess, form['body'], current_user.id)
raise redirect(request.app.router, 'index')

return {}
Loading
Loading