GithubHelp home page GithubHelp logo

fastapi-users / fastapi-users-db-sqlalchemy Goto Github PK

View Code? Open in Web Editor NEW
27.0 3.0 13.0 105 KB

FastAPI Users - Database adapter for SQLAlchemy + encode/databases

License: MIT License

Makefile 1.23% Python 98.77%
fastapi-users

fastapi-users-db-sqlalchemy's Introduction

FastAPI Users - Database adapter for SQLAlchemy ORM

FastAPI Users

Ready-to-use and customizable users management for FastAPI

build codecov PyPI version Downloads


Documentation: https://fastapi-users.github.io/fastapi-users/

Source Code: https://github.com/fastapi-users/fastapi-users


Add quickly a registration and authentication system to your FastAPI project. FastAPI Users is designed to be as customizable and adaptable as possible.

Sub-package for SQLAlchemy ORM support in FastAPI Users.

Development

Setup environment

We use Hatch to manage the development environment and production build. Ensure it's installed on your system.

Run unit tests

You can run all the tests with:

hatch run test

Format the code

Execute the following command to apply isort and black formatting:

hatch run lint

License

This project is licensed under the terms of the MIT license.

fastapi-users-db-sqlalchemy's People

Contributors

dipwave avatar frankie567 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

fastapi-users-db-sqlalchemy's Issues

User returned from register endpoint actually is the same as the user passed

Describe the bug

User create endpoint returns user that have been sent, not the user that was created at database.

To Reproduce

Just add custom column to User database model and set it's server_default or default value.
When creating new user don't set that columns' value. Than in response this value will not have default value but sent value.

Simple reproducable example.

Database User model:

class User(Base, SQLAlchemyBaseUserTable):
    """Table for storing users"""

    created_at = Column(DateTime, default=datetime.now, nullable=False)

Pydantic User schemas:

class User(models.BaseUser):
    """User fetch pydantic model"""

    created_at: datetime | None  # None is to create users without Pydantic's validation exception


class UserCreate(models.BaseUserCreate):
    """User's creation pydantic scheme"""


class UserUpdate(models.BaseUserUpdate):
    """User's update pydantic scheme"""


class UserDB(User, models.BaseUserDB):
    """User stored in DB pydantic model"""

Than add registration router and test.

Request and response examples

Request:

{
  "email": "[email protected]",
  "password": "some-password",
  "is_active": true,
  "is_superuser": true,
  "is_verified": true
}

Response:

{
  "id": "ecdd896e-2c76-42ba-b374-d5281e588e87",
  "email": "[email protected]",
  "is_active": true,
  "is_superuser": false,
  "is_verified": false,
  "created_at": null
}

Expected behavior

Successful user creation with automatically set created_at returned from registration endpoint.

For above request expected response is:

{
  "id": "ecdd896e-2c76-42ba-b374-d5281e588e87",
  "email": "[email protected]",
  "is_active": true,
  "is_superuser": false,
  "is_verified": false,
  "created_at": "2022-01-16T00:16:22.626191"
}

Configuration

  • Python version : 3.10.1
  • FastAPI version : 0.71.0
  • FastAPI Users version : 9.2.2

FastAPI Users configuration

Standard configuration from docs

can guid impl be changed?

Hi there,
While testing fastapi-users [sqlalchemy] along with sqladmin I bumped on this

  File "/mnt/1T/work/user-management/.venv/lib/python3.8/site-packages/sqladmin/forms.py", line 78, in get_converter
    raise Exception(  # pragma: nocover
Exception: Could not find field converter for column id (<class 'fastapi_users_db_sqlalchemy.guid.GUID'>).

I understand that sqladmin does not know how to handle this since it does not have converter for UUIDChar (https://github.com/aminalaee/sqladmin/blob/main/sqladmin/forms.py#L78). It does handle UUID though.

This is provoqued by the following line at fastapi-users-db-sqlalchemy/

.venv/lib/python3.8/site-packages/fastapi_users_db_sqlalchemy/guid.py
image

Is impl = UUIDChar a "standard" implementation or it should be named impl = UUID instead?

Otherwise, any way can I overwrite this?

_get_user() fails when no user in db

    async def _get_user(self, statement: Select) -> Optional[UP]:
        results = await self.session.execute(statement)
        user = results.first()

fails at .first() when there is no records in user table and then results is None

SQLAlchemy ORM implementation repository needed ๐Ÿ—ก๏ธ Provided draft implementation

Hi!

Thanks for your great work!. As a short background, I made small minimal repo with template for async starter for FastAPI (based on official template) and got a question about including FastAPI Users. I like async style of 1.4 SQLAlchemy ORM and prefer it over whatsoever databases.

But in the docs:
image

Here's the working adapter for SQLAlchemy ORM: https://github.com/rafsaf/fastapi_users_db_sqlalchemy_orm

I tried to implement it first before creating an issue, seems to be working just fine, it's not very much different from this repo implementation, I of course changed pytest fixtures (sqlalchemy orm + aiosqlite instead of databases) but the tests logic is the same. Disclaimer: I didn't spend a lot of time on it, review is a must (It's only a piece of code, not a full repo setup too)

The docs like here for new adapter may look like that

import asyncio

from fastapi_users.db import SQLAlchemyORMBaseUserTable, SQLAlchemyORMUserDatabase
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
from sqlalchemy.ext.declarative import DeclarativeMeta, declarative_base
from sqlalchemy.orm.session import sessionmaker

from .models import UserDB

DATABASE_URL = "sqlite+aiosqlite:///./test.db"

Base: DeclarativeMeta = declarative_base()

class UserTable(Base, SQLAlchemyORMBaseUserTable):
    pass

async_engine = create_async_engine(DATABASE_URL, pool_pre_ping=True)
async_session = sessionmaker(async_engine, expire_on_commit=False, class_=AsyncSession)


async def setup():
    async with async_engine.begin() as conn:
        await conn.run_sync(Base.metadata.create_all)

asyncio.run(setup())


async def get_user_db():
    async with async_session() as session:
        yield SQLAlchemyORMUserDatabase(UserDB, session, UserTable)

I'm waiting for your opinion about moving/creating new adapter in another repository so this topic can be continued :) Thanks a lot ๐Ÿ‘

The email index is not used by `get_by_email()` method

Describe the bug

An index is created on the email field:
https://github.com/fastapi-users/fastapi-users-db-sqlalchemy/blob/main/fastapi_users_db_sqlalchemy/__init__.py#L61

but the index can't be used by the get_by_email() method because the filtering uses a function on the SQL field.

To Reproduce

explain analyze 
SELECT auth_user.hashed_password, auth_user.is_active, auth_user.is_superuser, auth_user.is_verified, auth_user.id, auth_user.email, auth_user.first_name, auth_user.last_name 
FROM auth_user 
WHERE lower(auth_user.email) = lower('[email protected]');
Seq Scan on auth_user  (cost=0.00..10.90 rows=1 width=1245) (actual time=0.030..0.030 rows=0 loops=1)
   Filter: (lower((email)::text) = '[email protected]'::text)

Sequential scan is used instead of index scan.

Expected behavior

explain analyze 
SELECT auth_user.hashed_password, auth_user.is_active, auth_user.is_superuser, auth_user.is_verified, auth_user.id, auth_user.email, auth_user.first_name, auth_user.last_name 
FROM auth_user 
WHERE auth_user.email = lower('[email protected]');
Index Scan using ix_auth_user_email on auth_user  (cost=0.14..2.36 rows=1 width=1245) (actual time=0.044..0.045 rows=0 loops=1)
   Index Cond: ((email)::text = '[email protected]'::text)

There is several ways to fix the issue:

  1. use CIText extension but it's not standard in SQLAlchemy (https://pypi.org/project/sqlalchemy-citext/).
  2. create a functional index: CREATE INDEX ix_auth_user ON auth_user (lower(email) text_pattern_ops);
  3. store email in lower case (my favorite even though on rare occasions, an outdated server or program might not interpret the capitalization correctly).

I can provide a PR when we'll agree on a solution.

Configuration

  • FastAPI Users version : 0.7

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.