Search code examples
pythonsqlalchemyfastapipydantic

The error when i try to get the nested pydantic nested data with FastAPI


I am having some problems trying to retrieve information from 3 models.

class User(Base):
__tablename__ = 'users'
id = Column(UUID(as_uuid=True), primary_key=True, nullable=False,
            default=uuid.uuid4)
username = Column(String, nullable=False)
email = Column(String, unique=True, nullable=False)
phone = Column(String, unique=True, nullable=False)
password = Column(String, nullable=False)
photo = Column(String, nullable=True)
company_id = Column(UUID(as_uuid=True), ForeignKey(
    'companies.id', ondelete='CASCADE'), nullable=True)
verified = Column(Boolean, nullable=False, server_default='False')
verification_code = Column(String, nullable=True, unique=True)
# role = Column(String, nullable=True, unique=False)
role = Column(UUID(as_uuid=True), ForeignKey(
    'permissions.id', ondelete='CASCADE'), nullable=True)
created_at = Column(TIMESTAMP(timezone=True),
                    nullable=False, server_default=text("now()"))
updated_at = Column(TIMESTAMP(timezone=True),
                    nullable=False, server_default=text("now()"))

class Company(Base):
    __tablename__ = 'companies'
    id = Column(UUID(as_uuid=True), primary_key=True, nullable=False,
                default=uuid.uuid4)
    company_name = Column(String, nullable=False)
    inn = Column(String, nullable=True)
    email = Column(String, nullable=False)
    phone = Column(String(255), nullable=False)
    type = Column(String(12), nullable=False)
    created_at = Column(TIMESTAMP(timezone=True),
                        nullable=False, server_default=text("now()"))
    updated_at = Column(TIMESTAMP(timezone=True),
                        nullable=False, server_default=text("now()"))
    users = relationship('User')


class UserPermissions(Base):
    __tablename__ = 'permissions'
    id = Column(UUID(as_uuid=True), primary_key=True, nullable=False,
                default=uuid.uuid4)
    order_read = Column(Boolean, nullable=False, server_default='False')
    item_write = Column(Boolean, nullable=False, server_default='False')
    is_admin = Column(Boolean, nullable=False, server_default='False')
    permission_name = Column(String, nullable=False)

    created_at = Column(TIMESTAMP(timezone=True),
                        nullable=False, server_default=text("now()"))
    updated_at = Column(TIMESTAMP(timezone=True),
                        nullable=False, server_default=text("now()"))
    users = relationship('User')

That is my schemas

class CompanyBaseSchema(BaseModel):
    company_name: str
    email: EmailStr
    phone: str
    inn: str | None = None
    type: str

    class Config:
        orm_mode = True
    
class CompanyInfoResponse(BaseModel):
        status: str
        users_amount: int
        company: CompanyUsersResponse

class CompanyUsersResponse(CompanyBaseSchema):
    id: uuid.UUID
    created_at: datetime
    inn: str | None = None
    users: List[FilteredUserResponse]
    updated_at: datetime

class PermissionBaseSchema(BaseModel):
    # id: uuid.UUID | None = None
    order_read: bool
    item_write: bool
    is_admin: bool
    permission_name: str
    created_at: datetime
    updated_at: datetime

    class Config:
        orm_mode = True

class FilteredPermissionSchema(PermissionBaseSchema):
    id: uuid.UUID | None = None

class UserBaseSchema(BaseModel):
    username: str
    email: EmailStr
    phone: str
    company_id: uuid.UUID | None = None
    role: uuid.UUID

    class Config:
        orm_mode = True

class FilteredUserResponse(UserBaseSchema):
    username: str | None = None
    email: EmailStr | None = None
    phone: str | None = None
    role: FilteredPermissionSchema

My rourte looks like

@router.get('/info', response_model=schemas.CompanyInfoResponse)
def get_company_info(db: Session = Depends(get_db),
                     user_id: str = Depends(require_user)):
    # user_company = db.query(models.User).filter(models.User.id == user_id)
    user_company_one = db.query(models.User).filter(models.User.id == user_id).first().company_id
    company_info = get_post(str(user_company_one), db, user_id)
    return {'status': 'success', 'users_amount': len(company_info.users), 'company': company_info}

When I try to get the data according the scheme CompanyInfoResponse I gain such message

    pydantic.error_wrappers.ValidationError: 18 validation errors for CompanyInfoResponse
response -> company -> users -> 0 -> role -> order_read
  field required (type=value_error.missing)
response -> company -> users -> 0 -> role -> item_write
  field required (type=value_error.missing)
response -> company -> users -> 0 -> role -> is_admin
  field required (type=value_error.missing)
response -> company -> users -> 0 -> role -> permission_name
  field required (type=value_error.missing)
response -> company -> users -> 0 -> role -> created_at
  field required (type=value_error.missing)
response -> company -> users -> 0 -> role -> updated_at
  field required (type=value_error.missing)
response -> company -> users -> 1 -> role -> order_read
  field required (type=value_error.missing)
response -> company -> users -> 1 -> role -> item_write
  field required (type=value_error.missing)
response -> company -> users -> 1 -> role -> is_admin
  field required (type=value_error.missing)
response -> company -> users -> 1 -> role -> permission_name
  field required (type=value_error.missing)
response -> company -> users -> 1 -> role -> created_at
  field required (type=value_error.missing)
response -> company -> users -> 1 -> role -> updated_at
  field required (type=value_error.missing)
response -> company -> users -> 2 -> role -> order_read
  field required (type=value_error.missing)
response -> company -> users -> 2 -> role -> item_write
  field required (type=value_error.missing)
response -> company -> users -> 2 -> role -> is_admin
  field required (type=value_error.missing)
response -> company -> users -> 2 -> role -> permission_name
  field required (type=value_error.missing)
response -> company -> users -> 2 -> role -> created_at
  field required (type=value_error.missing)
response -> company -> users -> 2 -> role -> updated_at
  field required (type=value_error.missing)

It is a very weird staff, because. Without UserPermissions model scheme it works ok and can show me uuid of permission if i would like. It is just dont parse it. Can you explain me why it is show me that error, if I would like to parse the UserPermissions


Solution

  • Well, I solved this issue... I am just used role label of the Permission scheme. But have to use permissions