Не удается заставить SQLAlchemy-ImageAttach работать с Pydanti c: какие-нибудь примеры? - PullRequest
2 голосов
/ 02 августа 2020

Я пытаюсь использовать SQLAlchemy-ImageAttach с Pydanti c и FastAPI , но без особого успеха.

Я никогда раньше не использовал SQLAlchemy-ImageAttach и уверен, что использую его неправильно. Кажется, я не могу сохранить какие-либо изображения, но могу заставить работать все аспекты, не связанные с изображением. (Я успешно интегрировал SQLAlchemy + Pydanti c + FastAPI, и есть также отличные примеры , чтобы помочь.)

Я пытаюсь создать веб-сайт на базе БД, где пользователи могут создавать вопросы викторины и вставлять изображения вместе с вопросами. В приведенном ниже коде выделены части, относящиеся к вопросам викторины + изображения.

My Pydanti c модели / схемы:

from typing import List, Optional

from pydantic import BaseModel


class QuestionPictureBase(BaseModel):
    pass


class QuestionPicture(QuestionPictureBase):
    id: int
    question_id: int

    class Config:
        orm_mode = True


class QuestionBase(BaseModel):
    header: str
    details: str


class QuestionCreate(QuestionBase):
    pass


class Question(QuestionBase):
    id: int
    creator_id: int
    pictures: List[QuestionPicture] = []

    class Config:
        orm_mode = True


Модели SQLAlchemy:


from sqlalchemy import create_engine, Boolean, Column, ForeignKey, Integer, String, Text
from sqlalchemy.orm import relationship, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy_imageattach.entity import Image, image_attachment

SQLALCHEMY_DATABASE_URL = "sqlite:///sqlalch.db"

engine = create_engine(
    SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

Base = declarative_base()


class Question(Base):
    __tablename__ = "questions"

    id = Column(Integer, primary_key=True, index=True)
    header = Column(String, index=True)
    details = Column(String, index=True)
    creator_id = Column(Integer, ForeignKey("users.id"))
*** pictures = image_attachment("QuestionPicture", uselist=True) ***
    creator = relationship("User", back_populates="questions")


class QuestionPicture(Base, Image):
    """Model for pictures associated with the question."""

    __tablename__ = "question_pictures"

    id = Column(Integer, primary_key=True)
    # Not sure if the question ID should also be a unique identifier
    # question_id = Column(Integer, ForeignKey("questions.id"), primary_key=True)
    question_id = Column(Integer, ForeignKey("questions.id"))
    question = relationship("Question", back_populates="pictures")

Выделенная строка

*** pictures = image_attachment("QuestionPicture", uselist=True) ***

- это место, где я думаю, что делаю что-то неправильно. Но я не совсем уверен, что мне следует делать.

Я просто не понимаю, как следует использовать вызов функции image_attachment. Кажется, что это работает «автоматически» в документации SQLAlchemy-ImageAttach, и я этого не понимаю.

Есть ли у кого-нибудь рабочие примеры с использованием SQLAlchemy-ImageAttach + Pydanti c (+ FastAPI). Меня больше всего смущает взаимодействие с Pydanti c.

Обновление

Был запрос на более подробную информацию, и просто слишком много, чтобы задать вопрос. Поэтому вместо этого я создал ветку git, содержащую весь бэкэнд, но только бэкэнд, названный temp, а поместил его в publi c репозиторий GitHub .

Решение

@r-m-n Решение, приведенное ниже, помогло мне проделать большую часть пути, но моя основная проблема заключалась в том, что мне было непонятно, что должна содержать моя pictures база данных.

Посмотрев некоторые сообщения об ошибках и прочитав исходный код, я нашел необходимую структуру здесь и скорректировал свой код alembi c (управление версиями db) следующим образом:

def upgrade():
    op.create_table(
        "question_pictures",
        sa.Column("id", sa.Integer, primary_key=True, index=True),
        sa.Column(
            "question_id", sa.Integer, sa.ForeignKey("questions.id"), nullable=False
        ),
        sa.Column("width", sa.Integer, nullable=False),
        sa.Column("height", sa.Integer, nullable=False),
        #: (:class:`str`) The mimetype of the image
        #: e.g. ``'image/jpeg'``, ``'image/png'``.
        sa.Column("mimetype", sa.String(255), nullable=False),
        sa.Column("original", sa.Boolean, nullable=False, default=False),
        sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
    )

В приведенном выше списке отсутствовали width, height, original, mimetype и created_at, которые, как я не знал, мне нужно добавить.

(sa выше - это сокращение от sqlalchemy, а op - от alembic.op.)

1 Ответ

1 голос
/ 07 августа 2020

SQLAlchemy-ImageAttach по умолчанию использует параметр lazy=dynamic при создании отношения: https://github.com/dahlia/sqlalchemy-imageattach/blob/master/sqlalchemy_imageattach/entity.py#L148. Итак, question.pictures возвращает объект Query вместо списка, и вам нужно вызвать question.pictures.all(), чтобы получить список изображений.

Вы можете установить lazy=select или lazy=joined. Подробнее о lazy param здесь .

pictures = image_attachment("QuestionPicture", uselist=True, lazy='select')
...