mirror of
https://github.com/fastapi-users/fastapi-users.git
synced 2026-03-13 07:49:55 +08:00
Update docs for SQLAlchemy 2.0
This commit is contained in:
@@ -21,7 +21,7 @@ We are providing a base model with those fields for each database we are support
|
|||||||
|
|
||||||
We'll expand from the basic SQLAlchemy configuration.
|
We'll expand from the basic SQLAlchemy configuration.
|
||||||
|
|
||||||
```py hl_lines="5-8 21-22 43-46"
|
```py hl_lines="5-8 23-24 45-48"
|
||||||
--8<-- "docs/src/db_sqlalchemy_access_tokens.py"
|
--8<-- "docs/src/db_sqlalchemy_access_tokens.py"
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -37,8 +37,8 @@ We'll expand from the basic SQLAlchemy configuration.
|
|||||||
```py
|
```py
|
||||||
class AccessToken(SQLAlchemyBaseAccessTokenTable[int], Base):
|
class AccessToken(SQLAlchemyBaseAccessTokenTable[int], Base):
|
||||||
@declared_attr
|
@declared_attr
|
||||||
def user_id(cls):
|
def user_id(cls) -> Mapped[int]:
|
||||||
return Column(Integer, ForeignKey("user.id", ondelete="cascade"), nullable=False)
|
return mapped_column(Integer, ForeignKey("user.id", ondelete="cascade"), nullable=False)
|
||||||
```
|
```
|
||||||
|
|
||||||
Notice that `SQLAlchemyBaseAccessTokenTable` expects a generic type to define the actual type of ID you use.
|
Notice that `SQLAlchemyBaseAccessTokenTable` expects a generic type to define the actual type of ID you use.
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ For the sake of this tutorial from now on, we'll use a simple SQLite database.
|
|||||||
|
|
||||||
As for any SQLAlchemy ORM model, we'll create a `User` model.
|
As for any SQLAlchemy ORM model, we'll create a `User` model.
|
||||||
|
|
||||||
```py hl_lines="13-14"
|
```py hl_lines="15-16"
|
||||||
--8<-- "docs/src/db_sqlalchemy.py"
|
--8<-- "docs/src/db_sqlalchemy.py"
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ As you can see, **FastAPI Users** provides a base class that will include base f
|
|||||||
|
|
||||||
```py
|
```py
|
||||||
class User(SQLAlchemyBaseUserTable[int], Base):
|
class User(SQLAlchemyBaseUserTable[int], Base):
|
||||||
id = Column(Integer, primary_key=True)
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
||||||
```
|
```
|
||||||
|
|
||||||
Notice that `SQLAlchemyBaseUserTable` expects a generic type to define the actual type of ID you use.
|
Notice that `SQLAlchemyBaseUserTable` expects a generic type to define the actual type of ID you use.
|
||||||
@@ -40,7 +40,7 @@ As you can see, **FastAPI Users** provides a base class that will include base f
|
|||||||
|
|
||||||
We'll now create an utility function to create all the defined tables.
|
We'll now create an utility function to create all the defined tables.
|
||||||
|
|
||||||
```py hl_lines="21-23"
|
```py hl_lines="23-25"
|
||||||
--8<-- "docs/src/db_sqlalchemy.py"
|
--8<-- "docs/src/db_sqlalchemy.py"
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ This function can be called, for example, during the initialization of your Fast
|
|||||||
|
|
||||||
The database adapter of **FastAPI Users** makes the link between your database configuration and the users logic. It should be generated by a FastAPI dependency.
|
The database adapter of **FastAPI Users** makes the link between your database configuration and the users logic. It should be generated by a FastAPI dependency.
|
||||||
|
|
||||||
```py hl_lines="26-33"
|
```py hl_lines="28-34"
|
||||||
--8<-- "docs/src/db_sqlalchemy.py"
|
--8<-- "docs/src/db_sqlalchemy.py"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -32,11 +32,11 @@ google_oauth_client = GoogleOAuth2("CLIENT_ID", "CLIENT_SECRET")
|
|||||||
|
|
||||||
You'll need to define the SQLAlchemy model for storing OAuth accounts. We provide a base one for this:
|
You'll need to define the SQLAlchemy model for storing OAuth accounts. We provide a base one for this:
|
||||||
|
|
||||||
```py hl_lines="5 17-18 22 39-40"
|
```py hl_lines="5 19-20 24-26 43-44"
|
||||||
--8<-- "docs/src/db_sqlalchemy_oauth.py"
|
--8<-- "docs/src/db_sqlalchemy_oauth.py"
|
||||||
```
|
```
|
||||||
|
|
||||||
Notice that we also manually added a `relationship` on the `UserTable` so that SQLAlchemy can properly retrieve the OAuth accounts of the user.
|
Notice that we also manually added a `relationship` on `User` so that SQLAlchemy can properly retrieve the OAuth accounts of the user.
|
||||||
|
|
||||||
Besides, when instantiating the database adapter, we need pass this SQLAlchemy model as third argument.
|
Besides, when instantiating the database adapter, we need pass this SQLAlchemy model as third argument.
|
||||||
|
|
||||||
@@ -45,11 +45,11 @@ Besides, when instantiating the database adapter, we need pass this SQLAlchemy m
|
|||||||
|
|
||||||
```py
|
```py
|
||||||
class OAuthAccount(SQLAlchemyBaseOAuthAccountTable[int], Base):
|
class OAuthAccount(SQLAlchemyBaseOAuthAccountTable[int], Base):
|
||||||
id = Column(Integer, primary_key=True)
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
||||||
|
|
||||||
@declared_attr
|
@declared_attr
|
||||||
def user_id(cls):
|
def user_id(cls) -> Mapped[int]:
|
||||||
return Column(Integer, ForeignKey("user.id", ondelete="cascade"), nullable=False)
|
return mapped_column(Integer, ForeignKey("user.id", ondelete="cascade"), nullable=False)
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,14 @@ from typing import AsyncGenerator
|
|||||||
|
|
||||||
from fastapi import Depends
|
from fastapi import Depends
|
||||||
from fastapi_users.db import SQLAlchemyBaseUserTableUUID, SQLAlchemyUserDatabase
|
from fastapi_users.db import SQLAlchemyBaseUserTableUUID, SQLAlchemyUserDatabase
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
|
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
|
||||||
from sqlalchemy.orm import DeclarativeMeta, declarative_base, sessionmaker
|
from sqlalchemy.orm import DeclarativeBase
|
||||||
|
|
||||||
DATABASE_URL = "sqlite+aiosqlite:///./test.db"
|
DATABASE_URL = "sqlite+aiosqlite:///./test.db"
|
||||||
Base: DeclarativeMeta = declarative_base()
|
|
||||||
|
|
||||||
|
class Base(DeclarativeBase):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class User(SQLAlchemyBaseUserTableUUID, Base):
|
class User(SQLAlchemyBaseUserTableUUID, Base):
|
||||||
@@ -14,7 +17,7 @@ class User(SQLAlchemyBaseUserTableUUID, Base):
|
|||||||
|
|
||||||
|
|
||||||
engine = create_async_engine(DATABASE_URL)
|
engine = create_async_engine(DATABASE_URL)
|
||||||
async_session_maker = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
|
async_session_maker = async_sessionmaker(engine, expire_on_commit=False)
|
||||||
|
|
||||||
|
|
||||||
async def create_db_and_tables():
|
async def create_db_and_tables():
|
||||||
|
|||||||
@@ -6,11 +6,14 @@ from fastapi_users_db_sqlalchemy.access_token import (
|
|||||||
SQLAlchemyAccessTokenDatabase,
|
SQLAlchemyAccessTokenDatabase,
|
||||||
SQLAlchemyBaseAccessTokenTableUUID,
|
SQLAlchemyBaseAccessTokenTableUUID,
|
||||||
)
|
)
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
|
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
|
||||||
from sqlalchemy.orm import DeclarativeMeta, declarative_base, sessionmaker
|
from sqlalchemy.orm import DeclarativeBase
|
||||||
|
|
||||||
DATABASE_URL = "sqlite+aiosqlite:///./test.db"
|
DATABASE_URL = "sqlite+aiosqlite:///./test.db"
|
||||||
Base: DeclarativeMeta = declarative_base()
|
|
||||||
|
|
||||||
|
class Base(DeclarativeBase):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class User(SQLAlchemyBaseUserTableUUID, Base):
|
class User(SQLAlchemyBaseUserTableUUID, Base):
|
||||||
@@ -22,7 +25,7 @@ class AccessToken(SQLAlchemyBaseAccessTokenTableUUID, Base): # (1)!
|
|||||||
|
|
||||||
|
|
||||||
engine = create_async_engine(DATABASE_URL)
|
engine = create_async_engine(DATABASE_URL)
|
||||||
async_session_maker = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
|
async_session_maker = async_sessionmaker(engine, expire_on_commit=False)
|
||||||
|
|
||||||
|
|
||||||
async def create_db_and_tables():
|
async def create_db_and_tables():
|
||||||
|
|||||||
@@ -6,11 +6,14 @@ from fastapi_users.db import (
|
|||||||
SQLAlchemyBaseUserTableUUID,
|
SQLAlchemyBaseUserTableUUID,
|
||||||
SQLAlchemyUserDatabase,
|
SQLAlchemyUserDatabase,
|
||||||
)
|
)
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
|
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
|
||||||
from sqlalchemy.orm import DeclarativeMeta, declarative_base, relationship, sessionmaker
|
from sqlalchemy.orm import DeclarativeBase, Mapped, relationship
|
||||||
|
|
||||||
DATABASE_URL = "sqlite+aiosqlite:///./test.db"
|
DATABASE_URL = "sqlite+aiosqlite:///./test.db"
|
||||||
Base: DeclarativeMeta = declarative_base()
|
|
||||||
|
|
||||||
|
class Base(DeclarativeBase):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class OAuthAccount(SQLAlchemyBaseOAuthAccountTableUUID, Base):
|
class OAuthAccount(SQLAlchemyBaseOAuthAccountTableUUID, Base):
|
||||||
@@ -18,11 +21,13 @@ class OAuthAccount(SQLAlchemyBaseOAuthAccountTableUUID, Base):
|
|||||||
|
|
||||||
|
|
||||||
class User(SQLAlchemyBaseUserTableUUID, Base):
|
class User(SQLAlchemyBaseUserTableUUID, Base):
|
||||||
oauth_accounts: List[OAuthAccount] = relationship("OAuthAccount", lazy="joined")
|
oauth_accounts: Mapped[List[OAuthAccount]] = relationship(
|
||||||
|
"OAuthAccount", lazy="joined"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
engine = create_async_engine(DATABASE_URL)
|
engine = create_async_engine(DATABASE_URL)
|
||||||
async_session_maker = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
|
async_session_maker = async_sessionmaker(engine, expire_on_commit=False)
|
||||||
|
|
||||||
|
|
||||||
async def create_db_and_tables():
|
async def create_db_and_tables():
|
||||||
|
|||||||
@@ -6,11 +6,14 @@ from fastapi_users.db import (
|
|||||||
SQLAlchemyBaseUserTableUUID,
|
SQLAlchemyBaseUserTableUUID,
|
||||||
SQLAlchemyUserDatabase,
|
SQLAlchemyUserDatabase,
|
||||||
)
|
)
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
|
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
|
||||||
from sqlalchemy.orm import DeclarativeMeta, declarative_base, relationship, sessionmaker
|
from sqlalchemy.orm import DeclarativeBase, Mapped, relationship
|
||||||
|
|
||||||
DATABASE_URL = "sqlite+aiosqlite:///./test.db"
|
DATABASE_URL = "sqlite+aiosqlite:///./test.db"
|
||||||
Base: DeclarativeMeta = declarative_base()
|
|
||||||
|
|
||||||
|
class Base(DeclarativeBase):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class OAuthAccount(SQLAlchemyBaseOAuthAccountTableUUID, Base):
|
class OAuthAccount(SQLAlchemyBaseOAuthAccountTableUUID, Base):
|
||||||
@@ -18,11 +21,13 @@ class OAuthAccount(SQLAlchemyBaseOAuthAccountTableUUID, Base):
|
|||||||
|
|
||||||
|
|
||||||
class User(SQLAlchemyBaseUserTableUUID, Base):
|
class User(SQLAlchemyBaseUserTableUUID, Base):
|
||||||
oauth_accounts: List[OAuthAccount] = relationship("OAuthAccount", lazy="joined")
|
oauth_accounts: Mapped[List[OAuthAccount]] = relationship(
|
||||||
|
"OAuthAccount", lazy="joined"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
engine = create_async_engine(DATABASE_URL)
|
engine = create_async_engine(DATABASE_URL)
|
||||||
async_session_maker = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
|
async_session_maker = async_sessionmaker(engine, expire_on_commit=False)
|
||||||
|
|
||||||
|
|
||||||
async def create_db_and_tables():
|
async def create_db_and_tables():
|
||||||
|
|||||||
@@ -2,11 +2,14 @@ from typing import AsyncGenerator
|
|||||||
|
|
||||||
from fastapi import Depends
|
from fastapi import Depends
|
||||||
from fastapi_users.db import SQLAlchemyBaseUserTableUUID, SQLAlchemyUserDatabase
|
from fastapi_users.db import SQLAlchemyBaseUserTableUUID, SQLAlchemyUserDatabase
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
|
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
|
||||||
from sqlalchemy.orm import DeclarativeMeta, declarative_base, sessionmaker
|
from sqlalchemy.orm import DeclarativeBase
|
||||||
|
|
||||||
DATABASE_URL = "sqlite+aiosqlite:///./test.db"
|
DATABASE_URL = "sqlite+aiosqlite:///./test.db"
|
||||||
Base: DeclarativeMeta = declarative_base()
|
|
||||||
|
|
||||||
|
class Base(DeclarativeBase):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class User(SQLAlchemyBaseUserTableUUID, Base):
|
class User(SQLAlchemyBaseUserTableUUID, Base):
|
||||||
@@ -14,7 +17,7 @@ class User(SQLAlchemyBaseUserTableUUID, Base):
|
|||||||
|
|
||||||
|
|
||||||
engine = create_async_engine(DATABASE_URL)
|
engine = create_async_engine(DATABASE_URL)
|
||||||
async_session_maker = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
|
async_session_maker = async_sessionmaker(engine, expire_on_commit=False)
|
||||||
|
|
||||||
|
|
||||||
async def create_db_and_tables():
|
async def create_db_and_tables():
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ class BaseUserManager(Generic[models.UP, models.ID]):
|
|||||||
refresh_token: Optional[str] = None,
|
refresh_token: Optional[str] = None,
|
||||||
request: Optional[Request] = None,
|
request: Optional[Request] = None,
|
||||||
*,
|
*,
|
||||||
associate_by_email: bool = False
|
associate_by_email: bool = False,
|
||||||
) -> models.UOAP:
|
) -> models.UOAP:
|
||||||
"""
|
"""
|
||||||
Handle the callback after a successful OAuth authentication.
|
Handle the callback after a successful OAuth authentication.
|
||||||
|
|||||||
@@ -63,9 +63,9 @@ def forgot_password_token(user_manager: UserManagerMock[UserModel]):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def create_oauth2_password_request_form() -> Callable[
|
def create_oauth2_password_request_form() -> (
|
||||||
[str, str], OAuth2PasswordRequestForm
|
Callable[[str, str], OAuth2PasswordRequestForm]
|
||||||
]:
|
):
|
||||||
def _create_oauth2_password_request_form(username, password):
|
def _create_oauth2_password_request_form(username, password):
|
||||||
return OAuth2PasswordRequestForm(username=username, password=password, scope="")
|
return OAuth2PasswordRequestForm(username=username, password=password, scope="")
|
||||||
|
|
||||||
@@ -252,7 +252,6 @@ class TestOAuthAssociateCallback:
|
|||||||
user_manager_oauth: UserManagerMock[UserOAuthModel],
|
user_manager_oauth: UserManagerMock[UserOAuthModel],
|
||||||
superuser_oauth: UserOAuthModel,
|
superuser_oauth: UserOAuthModel,
|
||||||
):
|
):
|
||||||
|
|
||||||
user = await user_manager_oauth.oauth_associate_callback(
|
user = await user_manager_oauth.oauth_associate_callback(
|
||||||
superuser_oauth,
|
superuser_oauth,
|
||||||
"service1",
|
"service1",
|
||||||
|
|||||||
Reference in New Issue
Block a user