igorbenav / FastAPI-boilerplate

An extendable async API using FastAPI, Pydantic V2, SQLAlchemy 2.0, PostgreSQL and Redis.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Cannot create new model in database

vnlebaoduy opened this issue · comments

Problem 1: When i create a new model, but when i run docker-compose. It's not exists in my database.

from datetime import UTC, datetime
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy import DateTime, ForeignKey, String,Integer
from ..core.db.database import Base

class Template(Base):
    __tablename__ = "template"

    id: Mapped[int] = mapped_column("id", autoincrement=True, nullable=False, unique=True, primary_key=True, init=False)
    text: Mapped[str] = mapped_column(String)
    description: Mapped[str] = mapped_column(String)
    created_by: Mapped[int] = mapped_column(Integer, nullable=False)
    updated_by: Mapped[int] = mapped_column(Integer, nullable=False)
    deleted_by: Mapped[int] = mapped_column(Integer, nullable=False)
    created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default_factory=lambda: datetime.now(UTC))
    updated_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), default=None)
    deleted_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), default=None)
    is_deleted: Mapped[bool] = mapped_column(default=False, index=True)

Screenshots
CleanShot 2024-04-10 at 00 11 33@2x

Problem 2: When i migrating, my database has been delete all table. This is log migration

poetry run alembic revision --autogenerate
INFO  [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO  [alembic.runtime.migration] Will assume transactional DDL.
INFO  [alembic.ddl.postgresql] Detected sequence named 'rate_limit_id_seq' as owned by integer column 'rate_limit(id)', assuming SERIAL and omitting
INFO  [alembic.autogenerate.compare] Detected removed index 'ix_rate_limit_tier_id' on 'rate_limit'
INFO  [alembic.autogenerate.compare] Detected removed table 'rate_limit'
INFO  [alembic.ddl.postgresql] Detected sequence named 'token_blacklist_id_seq' as owned by integer column 'token_blacklist(id)', assuming SERIAL and omitting
INFO  [alembic.autogenerate.compare] Detected removed index 'ix_token_blacklist_token' on 'token_blacklist'
INFO  [alembic.autogenerate.compare] Detected removed table 'token_blacklist'
INFO  [alembic.ddl.postgresql] Detected sequence named 'post_id_seq' as owned by integer column 'post(id)', assuming SERIAL and omitting
INFO  [alembic.autogenerate.compare] Detected removed index 'ix_post_created_by_user_id' on 'post'
INFO  [alembic.autogenerate.compare] Detected removed index 'ix_post_is_deleted' on 'post'
INFO  [alembic.autogenerate.compare] Detected removed table 'post'
INFO  [alembic.autogenerate.compare] Detected removed index 'ix_user_email' on 'user'
INFO  [alembic.autogenerate.compare] Detected removed index 'ix_user_is_deleted' on 'user'
INFO  [alembic.autogenerate.compare] Detected removed index 'ix_user_tier_id' on 'user'
INFO  [alembic.autogenerate.compare] Detected removed index 'ix_user_username' on 'user'
INFO  [alembic.autogenerate.compare] Detected removed table 'user'
INFO  [alembic.autogenerate.compare] Detected removed table 'tier'
  Generating /src/migrations/versions/d02f4a524850_.py ...  done

This is probably happening because you (and I'm supposing, so correct me if I'm wrong) are creating the model, but not importing it anywhere.

If you create the model but don't use it anywhere, SQLAlchemy isn't aware that it exists. To fix this you can just create the Template model's CRUD with FastCRUD or you can just import the Template model in src/app/core/setup.py and SQLAlchemy will do the rest.

If I add the app/core/setup.py file, the database can be created, but that's not sound good.

I have already created the model file, schema file, and curd file. But they are still not initialized in the database. I don't know if I'm missing any other steps? And do I have to add the curd file somewhere so it can initialize the table in the database?

This is my file

Model File

from datetime import UTC, datetime
from sqlalchemy.dialects.postgresql import JSON
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy import DateTime, ForeignKey, String,Integer
from ..core.db.database import Base

class EncryptTemplate(Base):
    __tablename__ = "encrypt_template"

    id: Mapped[int] = mapped_column("id", autoincrement=True, nullable=False, unique=True, primary_key=True, init=False)
    text: Mapped[str] = mapped_column(String)
    description: Mapped[str] = mapped_column(String)
    created_by: Mapped[int] = mapped_column(Integer, nullable=False)
    updated_by: Mapped[int] = mapped_column(Integer, nullable=False)
    deleted_by: Mapped[int] = mapped_column(Integer, nullable=False)
    created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default_factory=lambda: datetime.now(UTC))
    updated_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), default=None)
    deleted_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), default=None)
    is_deleted: Mapped[bool] = mapped_column(default=False, index=True)

Schema File

from datetime import datetime
from typing import Annotated, Optional
from pydantic import BaseModel, Field


class EncryptTemplateBase(BaseModel):
    text: Annotated[str, Field(examples=["Example text"])]
    description: Annotated[str, Field(examples=["Example description for template"])]


class EncryptTemplateCreate(EncryptTemplateBase):
    created_by: Annotated[int, Field(...)]  
    updated_by: Annotated[int, Field(...)]  
    deleted_by: Annotated[int, Field(...)]  


class EncryptTemplateRead(EncryptTemplateBase):
    id: Annotated[int, Field(...)]  
    created_at: datetime
    updated_at: Optional[datetime] = None
    deleted_at: Optional[datetime] = None
    is_deleted: bool


class EncryptTemplateUpdate(BaseModel):
    text: Optional[str] = None
    description: Optional[str] = None
    updated_by: Optional[int] = None
    updated_at: Optional[datetime] = Field(default_factory=datetime.utcnow)


class EncryptTemplateDelete(BaseModel):
    deleted_by: int
    deleted_at: datetime = Field(default_factory=datetime.utcnow)
    is_deleted: bool = Field(default=True)

CURD File

from fastcrud import FastCRUD

from ..models.encrypt_template import EncryptTemplate
from ..schemas.encrypt_template import EncryptTemplateRead, EncryptTemplateCreate, EncryptTemplateUpdate, EncryptTemplateDelete

CRUDEncryptTemplate= FastCRUD[EncryptTemplate, EncryptTemplateRead, EncryptTemplateCreate, EncryptTemplateUpdate, EncryptTemplateDelete]
crud_encrypt_template = CRUDEncryptTemplate(EncryptTemplate)

Can you help me, please ? Thank you so much

Yeah, I just tested here and it's really not creating. As a temporary solution, if you create the endpoints, it will work, I did it like this:

# src/app/api/v1/encrypt_template.py

from fastcrud import crud_router

from ...core.db.database import async_get_db
from ...models.encrypt_template import EncryptTemplate
from ...schemas.encrypt_template import EncryptTemplateCreate, EncryptTemplateUpdate

router = crud_router(
    async_get_db, 
    EncryptTemplate, 
    EncryptTemplateCreate, 
    EncryptTemplateUpdate
)

Then pass it in the v1 __init__:

# src/app/api/v1/__init__.py

from fastapi import APIRouter

from .login import router as login_router
...
from .encrypt_template import router as encrypt_router

router = APIRouter(prefix="/v1")
router.include_router(login_router)
...
router.include_router(encrypt_router)

And the table will be created:

Screenshot 2024-04-14 at 19 47 13

I'll see if I can find a better way to do this and fix it eventually.

@igorbenav I got it.thank you so much. I have more a question about get multi_joined. When i joined 2 table many to one. I can't not create response object in object. Example: I only create like that

"data": [
    {
      "id": 0,
      "title": "string",
      "template_id": 0,
      "description": "string",
      "created_at": "2024-04-14T16:28:01.403Z",
      "created_by": "string",
      "template_title": "Example text for encryption",
      "template_description": "Example description for encryption template"
    }
  ],

This is response that i want

"data": [
    {
      "id": 0,
      "title": "string",
      "template_id": 0,
      "description": "string",
      "created_at": "2024-04-14T16:28:01.403Z",
      "created_by": "string",
      "created_at": "2024-04-14T16:28:01.403Z",
      "created_by": "string",
      "template":{
              "title": "Example text for encryption",
              "description": "Example description for encryption template"
       }
    }
  ],

Please help me :(

Hey, @vnlebaoduy, can you please open an issue on fastcrud's repo specifying the version and a minimal way to reproduce the issue?