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.
|
||||
|
||||
```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"
|
||||
```
|
||||
|
||||
@@ -37,8 +37,8 @@ We'll expand from the basic SQLAlchemy configuration.
|
||||
```py
|
||||
class AccessToken(SQLAlchemyBaseAccessTokenTable[int], Base):
|
||||
@declared_attr
|
||||
def user_id(cls):
|
||||
return Column(Integer, ForeignKey("user.id", ondelete="cascade"), nullable=False)
|
||||
def user_id(cls) -> Mapped[int]:
|
||||
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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
```py hl_lines="13-14"
|
||||
```py hl_lines="15-16"
|
||||
--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
|
||||
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.
|
||||
@@ -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.
|
||||
|
||||
```py hl_lines="21-23"
|
||||
```py hl_lines="23-25"
|
||||
--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.
|
||||
|
||||
```py hl_lines="26-33"
|
||||
```py hl_lines="28-34"
|
||||
--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:
|
||||
|
||||
```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"
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
@@ -45,11 +45,11 @@ Besides, when instantiating the database adapter, we need pass this SQLAlchemy m
|
||||
|
||||
```py
|
||||
class OAuthAccount(SQLAlchemyBaseOAuthAccountTable[int], Base):
|
||||
id = Column(Integer, primary_key=True)
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
||||
|
||||
@declared_attr
|
||||
def user_id(cls):
|
||||
return Column(Integer, ForeignKey("user.id", ondelete="cascade"), nullable=False)
|
||||
def user_id(cls) -> Mapped[int]:
|
||||
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_users.db import SQLAlchemyBaseUserTableUUID, SQLAlchemyUserDatabase
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
|
||||
from sqlalchemy.orm import DeclarativeMeta, declarative_base, sessionmaker
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
|
||||
from sqlalchemy.orm import DeclarativeBase
|
||||
|
||||
DATABASE_URL = "sqlite+aiosqlite:///./test.db"
|
||||
Base: DeclarativeMeta = declarative_base()
|
||||
|
||||
|
||||
class Base(DeclarativeBase):
|
||||
pass
|
||||
|
||||
|
||||
class User(SQLAlchemyBaseUserTableUUID, Base):
|
||||
@@ -14,7 +17,7 @@ class User(SQLAlchemyBaseUserTableUUID, Base):
|
||||
|
||||
|
||||
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():
|
||||
|
||||
@@ -6,11 +6,14 @@ from fastapi_users_db_sqlalchemy.access_token import (
|
||||
SQLAlchemyAccessTokenDatabase,
|
||||
SQLAlchemyBaseAccessTokenTableUUID,
|
||||
)
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
|
||||
from sqlalchemy.orm import DeclarativeMeta, declarative_base, sessionmaker
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
|
||||
from sqlalchemy.orm import DeclarativeBase
|
||||
|
||||
DATABASE_URL = "sqlite+aiosqlite:///./test.db"
|
||||
Base: DeclarativeMeta = declarative_base()
|
||||
|
||||
|
||||
class Base(DeclarativeBase):
|
||||
pass
|
||||
|
||||
|
||||
class User(SQLAlchemyBaseUserTableUUID, Base):
|
||||
@@ -22,7 +25,7 @@ class AccessToken(SQLAlchemyBaseAccessTokenTableUUID, Base): # (1)!
|
||||
|
||||
|
||||
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():
|
||||
|
||||
@@ -6,11 +6,14 @@ from fastapi_users.db import (
|
||||
SQLAlchemyBaseUserTableUUID,
|
||||
SQLAlchemyUserDatabase,
|
||||
)
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
|
||||
from sqlalchemy.orm import DeclarativeMeta, declarative_base, relationship, sessionmaker
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
|
||||
from sqlalchemy.orm import DeclarativeBase, Mapped, relationship
|
||||
|
||||
DATABASE_URL = "sqlite+aiosqlite:///./test.db"
|
||||
Base: DeclarativeMeta = declarative_base()
|
||||
|
||||
|
||||
class Base(DeclarativeBase):
|
||||
pass
|
||||
|
||||
|
||||
class OAuthAccount(SQLAlchemyBaseOAuthAccountTableUUID, Base):
|
||||
@@ -18,11 +21,13 @@ class OAuthAccount(SQLAlchemyBaseOAuthAccountTableUUID, 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)
|
||||
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():
|
||||
|
||||
@@ -6,11 +6,14 @@ from fastapi_users.db import (
|
||||
SQLAlchemyBaseUserTableUUID,
|
||||
SQLAlchemyUserDatabase,
|
||||
)
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
|
||||
from sqlalchemy.orm import DeclarativeMeta, declarative_base, relationship, sessionmaker
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
|
||||
from sqlalchemy.orm import DeclarativeBase, Mapped, relationship
|
||||
|
||||
DATABASE_URL = "sqlite+aiosqlite:///./test.db"
|
||||
Base: DeclarativeMeta = declarative_base()
|
||||
|
||||
|
||||
class Base(DeclarativeBase):
|
||||
pass
|
||||
|
||||
|
||||
class OAuthAccount(SQLAlchemyBaseOAuthAccountTableUUID, Base):
|
||||
@@ -18,11 +21,13 @@ class OAuthAccount(SQLAlchemyBaseOAuthAccountTableUUID, 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)
|
||||
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():
|
||||
|
||||
@@ -2,11 +2,14 @@ from typing import AsyncGenerator
|
||||
|
||||
from fastapi import Depends
|
||||
from fastapi_users.db import SQLAlchemyBaseUserTableUUID, SQLAlchemyUserDatabase
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
|
||||
from sqlalchemy.orm import DeclarativeMeta, declarative_base, sessionmaker
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
|
||||
from sqlalchemy.orm import DeclarativeBase
|
||||
|
||||
DATABASE_URL = "sqlite+aiosqlite:///./test.db"
|
||||
Base: DeclarativeMeta = declarative_base()
|
||||
|
||||
|
||||
class Base(DeclarativeBase):
|
||||
pass
|
||||
|
||||
|
||||
class User(SQLAlchemyBaseUserTableUUID, Base):
|
||||
@@ -14,7 +17,7 @@ class User(SQLAlchemyBaseUserTableUUID, Base):
|
||||
|
||||
|
||||
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():
|
||||
|
||||
@@ -156,7 +156,7 @@ class BaseUserManager(Generic[models.UP, models.ID]):
|
||||
refresh_token: Optional[str] = None,
|
||||
request: Optional[Request] = None,
|
||||
*,
|
||||
associate_by_email: bool = False
|
||||
associate_by_email: bool = False,
|
||||
) -> models.UOAP:
|
||||
"""
|
||||
Handle the callback after a successful OAuth authentication.
|
||||
|
||||
@@ -63,9 +63,9 @@ def forgot_password_token(user_manager: UserManagerMock[UserModel]):
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def create_oauth2_password_request_form() -> Callable[
|
||||
[str, str], OAuth2PasswordRequestForm
|
||||
]:
|
||||
def create_oauth2_password_request_form() -> (
|
||||
Callable[[str, str], OAuth2PasswordRequestForm]
|
||||
):
|
||||
def _create_oauth2_password_request_form(username, password):
|
||||
return OAuth2PasswordRequestForm(username=username, password=password, scope="")
|
||||
|
||||
@@ -252,7 +252,6 @@ class TestOAuthAssociateCallback:
|
||||
user_manager_oauth: UserManagerMock[UserOAuthModel],
|
||||
superuser_oauth: UserOAuthModel,
|
||||
):
|
||||
|
||||
user = await user_manager_oauth.oauth_associate_callback(
|
||||
superuser_oauth,
|
||||
"service1",
|
||||
|
||||
Reference in New Issue
Block a user