From ce0086540e9cd3741cd16ed51f875777f40e8bec Mon Sep 17 00:00:00 2001 From: urec56 Date: Sun, 17 Mar 2024 22:07:10 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20?= =?UTF-8?q?=D1=82=D0=B8=D0=BF=D0=BE=D0=B2=20=D0=BE=D1=82=D0=B2=D0=B5=D1=82?= =?UTF-8?q?=D1=8B=20=D0=BD=D0=B0=20=D1=81=D0=BE=D0=BE=D0=B1=D1=89=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../b516ed56b44b_добавил_таблицу_ответов.py | 36 +++++++++++++++++++ app/users/chat/dao.py | 20 ++++++----- app/users/chat/models.py | 18 ++++++++-- app/users/chat/shemas.py | 4 +++ app/users/dao.py | 1 + app/users/models.py | 6 ++-- app/users/router.py | 2 +- 7 files changed, 71 insertions(+), 16 deletions(-) create mode 100644 app/migrations/versions/b516ed56b44b_добавил_таблицу_ответов.py diff --git a/app/migrations/versions/b516ed56b44b_добавил_таблицу_ответов.py b/app/migrations/versions/b516ed56b44b_добавил_таблицу_ответов.py new file mode 100644 index 0000000..f1611c9 --- /dev/null +++ b/app/migrations/versions/b516ed56b44b_добавил_таблицу_ответов.py @@ -0,0 +1,36 @@ +"""Добавил таблицу ответов + +Revision ID: b516ed56b44b +Revises: 6df47399c087 +Create Date: 2024-03-17 19:40:43.587035 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision: str = 'b516ed56b44b' +down_revision: Union[str, None] = '6df47399c087' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('answers', + sa.Column('answer_id', sa.Integer(), nullable=False), + sa.Column('message_id', sa.Integer(), nullable=False), + sa.ForeignKeyConstraint(['answer_id'], ['messages.id'], ), + sa.ForeignKeyConstraint(['message_id'], ['messages.id'], ), + sa.PrimaryKeyConstraint('answer_id') + ) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('answers') + # ### end Alembic commands ### diff --git a/app/users/chat/dao.py b/app/users/chat/dao.py index b56ab35..730dd26 100644 --- a/app/users/chat/dao.py +++ b/app/users/chat/dao.py @@ -4,7 +4,7 @@ from app.dao.base import BaseDAO from app.database import async_session_maker, engine from app.exceptions import UserAlreadyInChatException, UserAlreadyPinnedChatException from app.users.models import Users -from app.users.chat.models import Chats, Messages, UsersXChats, PinnedChats, PinnedMessages +from app.users.chat.models import Chats, Messages, UsersXChats, PinnedChats, PinnedMessages, Answers class ChatDAO(BaseDAO): @@ -43,9 +43,11 @@ class ChatDAO(BaseDAO): @staticmethod async def get_message_by_id(message_id: int): - query = (select(Messages.message, Messages.image_url, Messages.chat_id, Messages.user_id, - Messages.created_at, Users.avatar_image, Users.username, Users.avatar_hex).select_from(Messages) + query = (select(Messages.id, Messages.message, Messages.image_url, Messages.chat_id, Messages.user_id, + Messages.created_at, Users.avatar_image, Users.username, Users.avatar_hex, + Answers.answer_id, Answers.message_id).select_from(Messages) .join(Users, Users.id == Messages.user_id) + .join(Answers, Answers.answer_id == Messages.id, isouter=True) .where( and_( Messages.id == message_id, @@ -82,14 +84,16 @@ class ChatDAO(BaseDAO): LIMIT 15 OFFSET 0; """ messages_with_users = ( - select(Messages.__table__.columns, Users.__table__.columns) + select(Messages.__table__.columns, Users.__table__.columns, Answers.__table__.columns) .select_from(Messages) - .join(Users, Messages.user_id == Users.id)).cte('messages_with_users') + .join(Users, Messages.user_id == Users.id) + .join(Answers, Answers.answer_id == Messages.id, isouter=True)).cte('messages_with_users') - messages = (select(messages_with_users.c.message, messages_with_users.c.image_url, + messages = (select(messages_with_users.c.id, messages_with_users.c.message, messages_with_users.c.image_url, messages_with_users.c.chat_id, messages_with_users.c.user_id, messages_with_users.c.created_at, messages_with_users.c.avatar_image, - messages_with_users.c.username, messages_with_users.c.avatar_hex + messages_with_users.c.username, messages_with_users.c.avatar_hex, + messages_with_users.c.answer_id, messages_with_users.c.message_id, ) .where( and_( @@ -213,7 +217,7 @@ class ChatDAO(BaseDAO): @staticmethod async def get_pinned_messages(chat_id: int) -> list[dict]: - query = (select(Messages.message, Messages.image_url, + query = (select(Messages.id, Messages.message, Messages.image_url, Messages.chat_id, Messages.user_id, Messages.created_at, Users.avatar_image, Users.username).select_from(PinnedMessages) diff --git a/app/users/chat/models.py b/app/users/chat/models.py index de02d9d..90ae5e5 100644 --- a/app/users/chat/models.py +++ b/app/users/chat/models.py @@ -1,8 +1,8 @@ from datetime import datetime -from typing import Optional from sqlalchemy import func, ForeignKey, DateTime from sqlalchemy.orm import mapped_column, Mapped, relationship +from sqlalchemy.ext.associationproxy import association_proxy from app.database import Base @@ -33,19 +33,31 @@ class Messages(Base): id: Mapped[int] = mapped_column(primary_key=True) chat_id = mapped_column(ForeignKey("chats.id")) user_id = mapped_column(ForeignKey("users.id")) - message: Mapped[Optional[str]] - image_url: Mapped[Optional[str]] + message: Mapped[str | None] + image_url: Mapped[str | None] created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) visibility: Mapped[bool] = mapped_column(server_default='true') chat = relationship("Chats", back_populates="message") user = relationship("Users", back_populates="message") pinned_messages = relationship("PinnedMessages", back_populates="message") + answer_id = relationship("Answers", primaryjoin='Messages.id == Answers.answer_id', back_populates="message") + message_id = relationship("Answers", primaryjoin='Messages.id == Answers.message_id', back_populates="message") def __str__(self): return f"#{self.id} {self.message} от {self.user_id}. Написано {self.created_at}" +class Answers(Base): + __tablename__ = "answers" + + answer_id: Mapped[int] = mapped_column(ForeignKey('messages.id'), primary_key=True) + message_id: Mapped[int] = mapped_column(ForeignKey('messages.id')) + + answer_message = relationship("Messages", primaryjoin="Answers.answer_id == Messages.id", back_populates="answer_id") + message = relationship("Messages", primaryjoin="Answers.message_id == Messages.id", back_populates="message_id") + + class UsersXChats(Base): __tablename__ = "usersxchats" diff --git a/app/users/chat/shemas.py b/app/users/chat/shemas.py index eae4603..255fc81 100644 --- a/app/users/chat/shemas.py +++ b/app/users/chat/shemas.py @@ -4,6 +4,7 @@ from pydantic import BaseModel, ConfigDict class SMessage(BaseModel): model_config = ConfigDict(from_attributes=True) + id: int message: str | None = None image_url: str | None = None chat_id: int @@ -12,6 +13,9 @@ class SMessage(BaseModel): created_at: str avatar_image: str avatar_hex: str + answer_id: int | None + message_id: int | None + class SLastMessages: diff --git a/app/users/dao.py b/app/users/dao.py index c8a6c65..63de6e7 100644 --- a/app/users/dao.py +++ b/app/users/dao.py @@ -84,6 +84,7 @@ class UserDAO(BaseDAO): chats_with_avatars.c.id == user_id, chats_with_avatars.c.visibility == True ))) + async with async_session_maker() as session: result = await session.execute(query) result = result.mappings().all() diff --git a/app/users/models.py b/app/users/models.py index fe71402..15c1323 100644 --- a/app/users/models.py +++ b/app/users/models.py @@ -1,8 +1,8 @@ from datetime import date, datetime -from typing import Optional from sqlalchemy import func, ForeignKey, DateTime from sqlalchemy.orm import mapped_column, Mapped, relationship +from sqlalchemy.ext.associationproxy import association_proxy from app.database import Base @@ -16,9 +16,7 @@ class Users(Base): hashed_password: Mapped[str] role: Mapped[int] = mapped_column(server_default='0') black_phoenix: Mapped[bool] = mapped_column(server_default='false') - avatar_image: Mapped[str | None] = mapped_column( - server_default='https://images.black-phoenix.ru/static/images/%D1%82%D1%8B%20%D1%83%D0%B6%D0%B5%20%D0%BF%D0%B5%D1%88%D0%BA%D0%B0%20BP.png' - ) + avatar_image: Mapped[str | None] = mapped_column(server_default='https://images.black-phoenix.ru/static/images/%D1%82%D1%8B%20%D1%83%D0%B6%D0%B5%20%D0%BF%D0%B5%D1%88%D0%BA%D0%B0%20BP.png') avatar_hex: Mapped[str | None] = mapped_column(server_default='#30293f') date_of_birth: Mapped[date] date_of_registration: Mapped[date] = mapped_column(server_default=func.now()) diff --git a/app/users/router.py b/app/users/router.py index c475658..2a87849 100644 --- a/app/users/router.py +++ b/app/users/router.py @@ -1,4 +1,4 @@ -from fastapi import APIRouter, Response, Depends, status +from fastapi import APIRouter, Response, Depends, status, Request from fastapi.responses import RedirectResponse from app.config import settings