fc684e7c7d
- Миграция 005: user_id в test_attempts (дефолт 1 = Гость) - GET /api/attempts с фильтрами по тесту, дате и пагинацией - Страница /tracker: таблица попыток, фильтры, пагинация - Ссылка «Трекер» в шапке приложения Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
51 lines
2.1 KiB
Python
51 lines
2.1 KiB
Python
from datetime import datetime
|
||
|
||
from sqlalchemy import Boolean, DateTime, Float, ForeignKey, Integer, String
|
||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||
from sqlalchemy.sql import func
|
||
|
||
from app.database import Base
|
||
|
||
|
||
class TestAttempt(Base):
|
||
__tablename__ = "test_attempts"
|
||
|
||
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
||
test_id: Mapped[int] = mapped_column(Integer, ForeignKey("tests.id"), nullable=False)
|
||
user_id: Mapped[int] = mapped_column(Integer, nullable=False, default=1, server_default="1")
|
||
started_at: Mapped[datetime] = mapped_column(
|
||
DateTime(timezone=True), server_default=func.now()
|
||
)
|
||
finished_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||
score: Mapped[float | None] = mapped_column(Float, nullable=True) # процент 0–100
|
||
passed: Mapped[bool | None] = mapped_column(Boolean, nullable=True)
|
||
correct_count: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
||
total_count: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
||
# in_progress | finished
|
||
status: Mapped[str] = mapped_column(String(20), default="in_progress", nullable=False)
|
||
|
||
test: Mapped["Test"] = relationship("Test") # type: ignore[name-defined]
|
||
answers: Mapped[list["AttemptAnswer"]] = relationship(
|
||
"AttemptAnswer", back_populates="attempt", cascade="all, delete-orphan"
|
||
)
|
||
|
||
|
||
class AttemptAnswer(Base):
|
||
"""Одна запись = один выбранный вариант ответа сотрудника."""
|
||
|
||
__tablename__ = "attempt_answers"
|
||
|
||
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
||
attempt_id: Mapped[int] = mapped_column(
|
||
Integer, ForeignKey("test_attempts.id"), nullable=False
|
||
)
|
||
question_id: Mapped[int] = mapped_column(
|
||
Integer, ForeignKey("questions.id"), nullable=False
|
||
)
|
||
answer_id: Mapped[int] = mapped_column(
|
||
Integer, ForeignKey("answers.id"), nullable=False
|
||
)
|
||
|
||
attempt: Mapped["TestAttempt"] = relationship("TestAttempt", back_populates="answers")
|
||
answer: Mapped["Answer"] = relationship("Answer") # type: ignore[name-defined]
|