mirror of
https://github.com/EDeev/web-dev.git
synced 2026-06-15 19:11:12 +03:00
125 lines
4.5 KiB
Python
125 lines
4.5 KiB
Python
import os
|
||
from typing import Optional, Union, List
|
||
from datetime import datetime
|
||
import sqlalchemy as sa
|
||
from werkzeug.security import check_password_hash, generate_password_hash
|
||
from flask_login import UserMixin
|
||
from flask import url_for
|
||
from flask_sqlalchemy import SQLAlchemy
|
||
from sqlalchemy.orm import DeclarativeBase
|
||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||
from sqlalchemy import String, ForeignKey, DateTime, Text, Integer, MetaData
|
||
|
||
|
||
class Base(DeclarativeBase):
|
||
metadata = MetaData(naming_convention={
|
||
"ix": 'ix_%(column_0_label)s',
|
||
"uq": "uq_%(table_name)s_%(column_0_name)s",
|
||
"ck": "ck_%(table_name)s_%(constraint_name)s",
|
||
"fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
|
||
"pk": "pk_%(table_name)s"
|
||
})
|
||
|
||
db = SQLAlchemy(model_class=Base)
|
||
|
||
class Category(Base):
|
||
__tablename__ = 'categories'
|
||
|
||
id = mapped_column(Integer, primary_key=True)
|
||
name: Mapped[str] = mapped_column(String(100))
|
||
parent_id: Mapped[Optional[int]] = mapped_column(ForeignKey("categories.id"))
|
||
|
||
def __repr__(self):
|
||
return '<Category %r>' % self.name
|
||
|
||
|
||
class User(Base, UserMixin):
|
||
__tablename__ = 'users'
|
||
|
||
id: Mapped[int] = mapped_column(primary_key=True)
|
||
first_name: Mapped[str] = mapped_column(String(100))
|
||
last_name: Mapped[str] = mapped_column(String(100))
|
||
middle_name: Mapped[Optional[str]] = mapped_column(String(100))
|
||
login: Mapped[str] = mapped_column(String(100), unique=True)
|
||
password_hash: Mapped[str] = mapped_column(String(200))
|
||
created_at: Mapped[datetime] = mapped_column(default=datetime.now)
|
||
|
||
def set_password(self, password):
|
||
self.password_hash = generate_password_hash(password)
|
||
|
||
def check_password(self, password):
|
||
return check_password_hash(self.password_hash, password)
|
||
|
||
@property
|
||
def full_name(self):
|
||
return ' '.join([self.last_name, self.first_name, self.middle_name or ''])
|
||
|
||
def __repr__(self):
|
||
return '<User %r>' % self.login
|
||
|
||
class Course(Base):
|
||
__tablename__ = 'courses'
|
||
|
||
id: Mapped[int] = mapped_column(primary_key=True)
|
||
name: Mapped[str] = mapped_column(String(100))
|
||
short_desc: Mapped[str] = mapped_column(Text)
|
||
full_desc: Mapped[str] = mapped_column(Text)
|
||
rating_sum: Mapped[int] = mapped_column(default=0)
|
||
rating_num: Mapped[int] = mapped_column(default=0)
|
||
category_id: Mapped[int] = mapped_column(ForeignKey("categories.id"))
|
||
author_id: Mapped[int] = mapped_column(ForeignKey("users.id"))
|
||
background_image_id: Mapped[str] = mapped_column(ForeignKey("images.id"))
|
||
created_at: Mapped[datetime] = mapped_column(default=datetime.now)
|
||
|
||
author: Mapped["User"] = relationship()
|
||
category: Mapped["Category"] = relationship(lazy=False)
|
||
bg_image: Mapped["Image"] = relationship()
|
||
# Связь с отзывами
|
||
reviews: Mapped[List["Review"]] = relationship(back_populates='course')
|
||
|
||
def __repr__(self):
|
||
return '<Course %r>' % self.name
|
||
|
||
@property
|
||
def rating(self):
|
||
if self.rating_num > 0:
|
||
return self.rating_sum / self.rating_num
|
||
return 0
|
||
|
||
class Image(db.Model):
|
||
__tablename__ = 'images'
|
||
|
||
id: Mapped[str] = mapped_column(String(100), primary_key=True)
|
||
file_name: Mapped[str] = mapped_column(String(100))
|
||
mime_type: Mapped[str] = mapped_column(String(100))
|
||
md5_hash: Mapped[str] = mapped_column(String(100), unique=True)
|
||
object_id: Mapped[Optional[int]]
|
||
object_type: Mapped[Optional[str]] = mapped_column(String(100))
|
||
created_at: Mapped[datetime] = mapped_column(default=datetime.now)
|
||
|
||
def __repr__(self):
|
||
return '<Image %r>' % self.file_name
|
||
|
||
@property
|
||
def storage_filename(self):
|
||
_, ext = os.path.splitext(self.file_name)
|
||
return self.id + ext
|
||
|
||
@property
|
||
def url(self):
|
||
return url_for('image', image_id=self.id)
|
||
|
||
# Модель отзыва
|
||
class Review(Base):
|
||
__tablename__ = 'reviews'
|
||
|
||
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
||
rating: Mapped[int] = mapped_column(Integer, nullable=False)
|
||
text: Mapped[str] = mapped_column(Text, nullable=False)
|
||
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.now)
|
||
course_id: Mapped[int] = mapped_column(ForeignKey('courses.id'))
|
||
user_id: Mapped[int] = mapped_column(ForeignKey('users.id'))
|
||
|
||
# Связи с курсом и пользователем
|
||
course: Mapped['Course'] = relationship(back_populates='reviews')
|
||
user: Mapped['User'] = relationship()
|