Старт
This commit is contained in:
187
backend/app/models.py
Normal file
187
backend/app/models.py
Normal file
@@ -0,0 +1,187 @@
|
||||
from sqlalchemy import Column, Integer, String, DateTime, Boolean, Text, ForeignKey, Numeric, JSON
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.sql import func
|
||||
from .database import Base
|
||||
|
||||
class User(Base):
|
||||
__tablename__ = "users"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
email = Column(String(255), unique=True, index=True, nullable=False)
|
||||
hashed_password = Column(String(255), nullable=False)
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
is_active = Column(Boolean, default=True)
|
||||
is_developer = Column(Boolean, default=False)
|
||||
|
||||
favorite_courses = relationship("FavoriteCourse", back_populates="user", cascade="all, delete-orphan")
|
||||
progress = relationship("Progress", back_populates="user", cascade="all, delete-orphan")
|
||||
|
||||
class Course(Base):
|
||||
__tablename__ = "courses"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
title = Column(String(255), nullable=False)
|
||||
description = Column(Text, nullable=False)
|
||||
level = Column(String(50), nullable=False)
|
||||
duration = Column(Integer, default=0, nullable=False)
|
||||
content = Column(Text)
|
||||
author_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
|
||||
status = Column(String(20), default='draft', nullable=False)
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|
||||
|
||||
author = relationship("User")
|
||||
modules = relationship("CourseModule", back_populates="course", cascade="all, delete-orphan")
|
||||
favorites = relationship("FavoriteCourse", back_populates="course", cascade="all, delete-orphan")
|
||||
progress_records = relationship("Progress", back_populates="course", cascade="all, delete-orphan")
|
||||
|
||||
|
||||
class CourseModule(Base):
|
||||
__tablename__ = "course_modules"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
course_id = Column(Integer, ForeignKey("courses.id", ondelete="CASCADE"), nullable=False)
|
||||
title = Column(String(255), nullable=False)
|
||||
description = Column(Text)
|
||||
duration = Column(String(100)) # e.g., "2 weeks", "10 hours"
|
||||
order_index = Column(Integer, default=0, nullable=False)
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|
||||
|
||||
course = relationship("Course", back_populates="modules")
|
||||
lessons = relationship("Lesson", back_populates="module", cascade="all, delete-orphan")
|
||||
|
||||
|
||||
class Lesson(Base):
|
||||
__tablename__ = "lessons"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
module_id = Column(Integer, ForeignKey("course_modules.id", ondelete="CASCADE"), nullable=False)
|
||||
title = Column(String(255), nullable=False)
|
||||
description = Column(Text)
|
||||
order_index = Column(Integer, default=0, nullable=False)
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|
||||
|
||||
module = relationship("CourseModule", back_populates="lessons")
|
||||
steps = relationship("LessonStep", back_populates="lesson", cascade="all, delete-orphan")
|
||||
|
||||
|
||||
class LessonStep(Base):
|
||||
__tablename__ = "lesson_steps"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
lesson_id = Column(Integer, ForeignKey("lessons.id", ondelete="CASCADE"), nullable=False)
|
||||
step_type = Column(String(50), nullable=False)
|
||||
title = Column(String(255))
|
||||
content = Column(Text)
|
||||
content_html = Column(Text)
|
||||
file_url = Column(String(500))
|
||||
test_settings = Column(JSON) # {passing_score, max_attempts, time_limit, show_answers}
|
||||
order_index = Column(Integer, default=0, nullable=False)
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|
||||
|
||||
lesson = relationship("Lesson", back_populates="steps")
|
||||
test_questions = relationship("TestQuestion", back_populates="step", cascade="all, delete-orphan")
|
||||
test_attempts = relationship("TestAttempt", back_populates="step", cascade="all, delete-orphan")
|
||||
|
||||
|
||||
class FavoriteCourse(Base):
|
||||
__tablename__ = "favorite_courses"
|
||||
|
||||
user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), primary_key=True)
|
||||
course_id = Column(Integer, ForeignKey("courses.id", ondelete="CASCADE"), primary_key=True)
|
||||
added_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
user = relationship("User", back_populates="favorite_courses")
|
||||
course = relationship("Course", back_populates="favorites")
|
||||
|
||||
|
||||
class Progress(Base):
|
||||
__tablename__ = "progress"
|
||||
|
||||
user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), primary_key=True)
|
||||
course_id = Column(Integer, ForeignKey("courses.id", ondelete="CASCADE"), primary_key=True)
|
||||
completed_lessons = Column(Integer, default=0, nullable=False)
|
||||
total_lessons = Column(Integer, default=0, nullable=False)
|
||||
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|
||||
|
||||
user = relationship("User", back_populates="progress")
|
||||
course = relationship("Course")
|
||||
|
||||
|
||||
class CourseDraft(Base):
|
||||
__tablename__ = "course_drafts"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
|
||||
title = Column(String(255), nullable=False)
|
||||
description = Column(Text)
|
||||
level = Column(String(50), nullable=False)
|
||||
content = Column(Text, nullable=False)
|
||||
structure = Column(Text) # JSON строка для структуры модулей
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|
||||
|
||||
user = relationship("User")
|
||||
|
||||
|
||||
class TestQuestion(Base):
|
||||
__tablename__ = "test_questions"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
step_id = Column(Integer, ForeignKey("lesson_steps.id", ondelete="CASCADE"), nullable=False)
|
||||
question_text = Column(Text, nullable=False)
|
||||
question_type = Column(String(50), nullable=False) # single_choice, multiple_choice, text_answer, match
|
||||
points = Column(Integer, default=1)
|
||||
order_index = Column(Integer, default=0)
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|
||||
|
||||
step = relationship("LessonStep", back_populates="test_questions")
|
||||
answers = relationship("TestAnswer", back_populates="question", cascade="all, delete-orphan")
|
||||
match_items = relationship("TestMatchItem", back_populates="question", cascade="all, delete-orphan")
|
||||
|
||||
|
||||
class TestAnswer(Base):
|
||||
__tablename__ = "test_answers"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
question_id = Column(Integer, ForeignKey("test_questions.id", ondelete="CASCADE"), nullable=False)
|
||||
answer_text = Column(Text, nullable=False)
|
||||
is_correct = Column(Boolean, default=False)
|
||||
order_index = Column(Integer, default=0)
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
question = relationship("TestQuestion", back_populates="answers")
|
||||
|
||||
|
||||
class TestMatchItem(Base):
|
||||
__tablename__ = "test_match_items"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
question_id = Column(Integer, ForeignKey("test_questions.id", ondelete="CASCADE"), nullable=False)
|
||||
left_text = Column(Text, nullable=False)
|
||||
right_text = Column(Text, nullable=False)
|
||||
order_index = Column(Integer, default=0)
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
question = relationship("TestQuestion", back_populates="match_items")
|
||||
|
||||
|
||||
class TestAttempt(Base):
|
||||
__tablename__ = "test_attempts"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
|
||||
step_id = Column(Integer, ForeignKey("lesson_steps.id", ondelete="CASCADE"), nullable=False)
|
||||
score = Column(Numeric(5, 2))
|
||||
max_score = Column(Numeric(5, 2))
|
||||
passed = Column(Boolean, default=False)
|
||||
answers = Column(JSON) # {question_id: answer_id или [answer_ids] или text или {left_id: right_id}}
|
||||
started_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
completed_at = Column(DateTime(timezone=True))
|
||||
|
||||
user = relationship("User")
|
||||
step = relationship("LessonStep", back_populates="test_attempts")
|
||||
Reference in New Issue
Block a user