from __future__ import annotations
from datetime import datetime
from typing import List, Optional
from uuid import UUID, uuid4
from pydantic import EmailStr
from sqlmodel import Field, Relationship, SQLModel
from sqlalchemy.orm import Mapped, mapped_column
# ---------------------------
# 用户模型
# ---------------------------
class UserBase(SQLModel):
email: EmailStr = Field(unique=True, index=True, max_length=255)
is_active: bool = True
is_superuser: bool = False
full_name: Optional[str] = Field(default=None, max_length=255)
class UserCreate(UserBase):
password: str = Field(min_length=8, max_length=40)
class UserRegister(SQLModel):
email: EmailStr = Field(max_length=255)
password: str = Field(min_length=8, max_length=40)
full_name: Optional[str] = Field(default=None, max_length=255)
class UserUpdate(SQLModel):
email: Optional[EmailStr] = Field(default=None, max_length=255)
full_name: Optional[str] = Field(default=None, max_length=255)
password: Optional[str] = Field(default=None, min_length=8, max_length=40)
class UserUpdateMe(SQLModel):
email: Optional[EmailStr] = Field(default=None, max_length=255)
full_name: Optional[str] = Field(default=None, max_length=255)
class UpdatePassword(SQLModel):
current_password: str = Field(min_length=8, max_length=40)
new_password: str = Field(min_length=8, max_length=40)
class UserBarFollow(SQLModel, table=True):
__tablename__ = "user_bar_follow"
user_id: UUID = Field(foreign_key="user.id", primary_key=True)
bar_id: UUID = Field(foreign_key="bar.bar_id", primary_key=True)
created_at: datetime = Field(default_factory=datetime.utcnow)
class User(UserBase, table=True):
id: UUID = Field(default_factory=uuid4, primary_key=True)
hashed_password: str = Field(nullable=False)
created_posts: List["Post"] = Relationship(back_populates="author")
created_replies: List["Reply"] = Relationship(back_populates="author")
created_bars: List["Bar"] = Relationship(back_populates="creator")
followed_bars: List["Bar"] = Relationship(back_populates="followers", link_model=UserBarFollow)
class UserPublic(UserBase):
id: UUID
class UsersPublic(SQLModel):
data: List[UserPublic]
count: int
# ---------------------------
# 吧模型
# ---------------------------
class BarBase(SQLModel):
name: str = Field(..., min_length=1, max_length=50)
description: str = Field(..., min_length=1, max_length=500)
follower_count: int = Field(default=0, ge=0)
post_count: int = Field(default=0, ge=0)
creator_id: UUID
is_official: bool = Field(default=False)
class BarCreate(BarBase):
pass
class BarUpdate(SQLModel):
name: Optional[str] = Field(None, min_length=1, max_length=255)
description: Optional[str] = Field(None, min_length=1, max_length=255)
follower_count: Optional[int] = Field(None, ge=0)
class Bar(SQLModel, table=True):
bar_id: UUID = Field(default_factory=uuid4, primary_key=True)
name: str = Field(..., min_length=1, max_length=50)
description: str = Field(..., min_length=1, max_length=500)
follower_count: int = Field(default=0, ge=0)
post_count: int = Field(default=0, ge=0)
creator_id: UUID = Field(foreign_key="user.id")
is_official: bool = Field(default=False)
created_at: datetime = Field(default_factory=datetime.utcnow)
creator: "User" = Relationship(back_populates="created_bars")
posts: List["Post"] = Relationship(back_populates="bar")
followers: List["User"] = Relationship(back_populates="followed_bars", link_model=UserBarFollow)
class BarPublic(BarBase):
bar_id: UUID
# ---------------------------
# 帖子模型
# ---------------------------
class PostBase(SQLModel):
title: str = Field(..., max_length=100)
content: str = Field(..., max_length=5000)
is_top: bool = Field(default=False)
like_count: int = Field(default=0, ge=0)
reply_count: int = Field(default=0, ge=0)
view_count: int = Field(default=0, ge=0)
class PostCreate(PostBase):
pass
class PostUpdate(SQLModel):
title: Optional[str] = Field(None, max_length=100)
content: Optional[str] = Field(None, max_length=5000)
is_top: Optional[bool] = None
class Post(SQLModel, table=True):
post_id: UUID = Field(default_factory=uuid4, primary_key=True)
bar_id: UUID = Field(foreign_key="bar.bar_id")
author_id: UUID = Field(foreign_key="user.id")
title: str = Field(..., max_length=100)
content: str = Field(..., max_length=5000)
created_at: datetime = Field(default_factory=datetime.utcnow)
updated_at: datetime = Field(default_factory=datetime.utcnow)
bar: "Bar" = Relationship(back_populates="posts")
author: "User" = Relationship(back_populates="created_posts")
class PostPublic(PostBase):
post_id: UUID
bar_id: UUID
author_id: UUID
created_at: datetime
updated_at: datetime
# ---------------------------
# 回复模型
# ---------------------------
class ReplyBase(SQLModel):
content: str = Field(..., max_length=2000)
class ReplyCreate(ReplyBase):
pass
class ReplyUpdate(SQLModel):
content: Optional[str] = Field(None, max_length=2000)
class Reply(SQLModel, table=True):
reply_id: UUID = Field(default_factory=uuid4, primary_key=True)
post_id: UUID = Field(foreign_key="post.post_id")
author_id: UUID = Field(foreign_key="user.id")
content: str = Field(..., max_length=2000)
created_at: datetime = Field(default_factory=datetime.utcnow)
post: "Post" = Relationship(back_populates="replies")
author: "User" = Relationship(back_populates="created_replies")
class ReplyPublic(ReplyBase):
reply_id: UUID
post_id: UUID
author_id: UUID
created_at: datetime
# ---------------------------
# 其他模型
# ---------------------------
class Message(SQLModel):
message: str
class Token(SQLModel):
access_token: str
token_type: str = "bearer"
class TokenPayload(SQLModel):
sub: Optional[str] = None
class NewPassword(SQLModel):
token: str
new_password: str = Field(min_length=8, max_length=40)
报错PS C:\Users\林林子\Desktop\full-stack-fastapi-template-0.8.0\backend> docker logs full-stack-fastapi-template-080-prestart-1
+ python app/backend_pre_start.py
/app/app/core/config.py:105: UserWarning: The value of SECRET_KEY is "changethis", for security, please change it, at least for deployments.
warnings.warn(message, stacklevel=1)
/app/app/core/config.py:105: UserWarning: The value of POSTGRES_PASSWORD is "changethis", for security, please change it, at least for deployments.
warnings.warn(message, stacklevel=1)
/app/app/core/config.py:105: UserWarning: The value of FIRST_SUPERUSER_PASSWORD is "changethis", for security, please change it, at least for deployments.
warnings.warn(message, stacklevel=1)
INFO:__main__:Initializing service
INFO:__main__:Starting call to '__main__.init', this is the 1st time calling it.
INFO:__main__:Service finished initializing
+ alembic upgrade head
/app/app/core/config.py:105: UserWarning: The value of SECRET_KEY is "changethis", for security, please change it, at least for deployments.
warnings.warn(message, stacklevel=1)
/app/app/core/config.py:105: UserWarning: The value of POSTGRES_PASSWORD is "changethis", for security, please change it, at least for deployments.
warnings.warn(message, stacklevel=1)
/app/app/core/config.py:105: UserWarning: The value of FIRST_SUPERUSER_PASSWORD is "changethis", for security, please change it, at least for deployments.
warnings.warn(message, stacklevel=1)
INFO [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO [alembic.runtime.migration] Will assume transactional DDL.
+ python app/initial_data.py
/app/app/core/config.py:105: UserWarning: The value of SECRET_KEY is "changethis", for security, please change it, at least for deployments.
warnings.warn(message, stacklevel=1)
/app/app/core/config.py:105: UserWarning: The value of POSTGRES_PASSWORD is "changethis", for security, please change it, at least for deployments.
warnings.warn(message, stacklevel=1)
/app/app/core/config.py:105: UserWarning: The value of FIRST_SUPERUSER_PASSWORD is "changethis", for security, please change it, at least for deployments.
warnings.warn(message, stacklevel=1)
INFO:__main__:Creating initial data
Traceback (most recent call last):
File "/app/.venv/lib/python3.10/site-packages/sqlalchemy/orm/clsregistry.py", line 516, in _resolve_name
rval = d[token]
File "/app/.venv/lib/python3.10/site-packages/sqlalchemy/util/_collections.py", line 345, in __missing__
self[key] = val = self.creator(key)
File "/app/.venv/lib/python3.10/site-packages/sqlalchemy/orm/clsregistry.py", line 484, in _access_cls
return self.fallback[key]
KeyError: "List['Post']"
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/app/app/initial_data.py", line 23, in <module>
main()
File "/app/app/initial_data.py", line 18, in main
init()
File "/app/app/initial_data.py", line 13, in init
init_db(session)
File "/app/app/core/db.py", line 24, in init_db
user = session.exec(
File "/app/.venv/lib/python3.10/site-packages/sqlmodel/orm/session.py", line 66, in exec
results = super().execute(
File "/app/.venv/lib/python3.10/site-packages/sqlalchemy/orm/session.py", line 2362, in execute
return self._execute_internal(
File "/app/.venv/lib/python3.10/site-packages/sqlalchemy/orm/session.py", line 2247, in _execute_internal
result: Result[Any] = compile_state_cls.orm_execute_statement(
File "/app/.venv/lib/python3.10/site-packages/sqlalchemy/orm/context.py", line 305, in orm_execute_statement
result = conn.execute(
File "/app/.venv/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 1418, in execute
return meth(
File "/app/.venv/lib/python3.10/site-packages/sqlalchemy/sql/elements.py", line 515, in _execute_on_connection
return connection._execute_clauseelement(
File "/app/.venv/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 1632, in _execute_clauseelement
compiled_sql, extracted_params, cache_hit = elem._compile_w_cache(
File "/app/.venv/lib/python3.10/site-packages/sqlalchemy/sql/elements.py", line 703, in _compile_w_cache
compiled_sql = self._compiler(
File "/app/.venv/lib/python3.10/site-packages/sqlalchemy/sql/elements.py", line 316, in _compiler
return dialect.statement_compiler(dialect, self, **kw)
File "/app/.venv/lib/python3.10/site-packages/sqlalchemy/sql/compiler.py", line 1429, in __init__
Compiled.__init__(self, dialect, statement, **kwargs)
File "/app/.venv/lib/python3.10/site-packages/sqlalchemy/sql/compiler.py", line 870, in __init__
self.string = self.process(self.statement, **compile_kwargs)
File "/app/.venv/lib/python3.10/site-packages/sqlalchemy/sql/compiler.py", line 915, in process
return obj._compiler_dispatch(self, **kwargs)
File "/app/.venv/lib/python3.10/site-packages/sqlalchemy/sql/visitors.py", line 141, in _compiler_dispatch
return meth(self, **kw) # type: ignore # noqa: E501
File "/app/.venv/lib/python3.10/site-packages/sqlalchemy/sql/compiler.py", line 4679, in visit_select
compile_state = select_stmt._compile_state_factory(
File "/app/.venv/lib/python3.10/site-packages/sqlalchemy/sql/base.py", line 683, in create_for_statement
return klass.create_for_statement(statement, compiler, **kw)
File "/app/.venv/lib/python3.10/site-packages/sqlalchemy/orm/context.py", line 1110, in create_for_statement
_QueryEntity.to_compile_state(
File "/app/.venv/lib/python3.10/site-packages/sqlalchemy/orm/context.py", line 2565, in to_compile_state
_MapperEntity(
File "/app/.venv/lib/python3.10/site-packages/sqlalchemy/orm/context.py", line 2645, in __init__
entity._post_inspect
File "/app/.venv/lib/python3.10/site-packages/sqlalchemy/util/langhelpers.py", line 1253, in __get__
obj.__dict__[self.__name__] = result = self.fget(obj)
File "/app/.venv/lib/python3.10/site-packages/sqlalchemy/orm/mapper.py", line 2711, in _post_inspect
self._check_configure()
File "/app/.venv/lib/python3.10/site-packages/sqlalchemy/orm/mapper.py", line 2388, in _check_configure
_configure_registries({self.registry}, cascade=True)
File "/app/.venv/lib/python3.10/site-packages/sqlalchemy/orm/mapper.py", line 4204, in _configure_registries
_do_configure_registries(registries, cascade)
File "/app/.venv/lib/python3.10/site-packages/sqlalchemy/orm/mapper.py", line 4245, in _do_configure_registries
mapper._post_configure_properties()
File "/app/.venv/lib/python3.10/site-packages/sqlalchemy/orm/mapper.py", line 2405, in _post_configure_properties
prop.init()
File "/app/.venv/lib/python3.10/site-packages/sqlalchemy/orm/interfaces.py", line 584, in init
self.do_init()
File "/app/.venv/lib/python3.10/site-packages/sqlalchemy/orm/relationships.py", line 1642, in do_init
self._setup_entity()
File "/app/.venv/lib/python3.10/site-packages/sqlalchemy/orm/relationships.py", line 1854, in _setup_entity
self._clsregistry_resolve_name(argument)(),
File "/app/.venv/lib/python3.10/site-packages/sqlalchemy/orm/clsregistry.py", line 520, in _resolve_name
self._raise_for_name(name, err)
File "/app/.venv/lib/python3.10/site-packages/sqlalchemy/orm/clsregistry.py", line 491, in _raise_for_name
raise exc.InvalidRequestError(
sqlalchemy.exc.InvalidRequestError: When initializing mapper Mapper[User(user)], expression "relationship("List['Post']")" seems to be using a generic class as the argument to relationship(); please state the generic argument using an annotation, e.g. "created_posts: Mapped[List['Post']] = relationship()"
最新发布