Skip to content

Commit 344fd7d

Browse files
committed
first commit
1 parent 7b22e2d commit 344fd7d

19 files changed

Lines changed: 418 additions & 697 deletions

File tree

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
from .base import Base, BaseDbModel
22
from .db import *
3-
from .db_temp import *
3+
from .db_editor import *
44

5-
6-
__all__ = ["Base", "BaseDbModel", "FinesData", "Evacuations", "EvacuationRoute", "TrafficLight", "FinesDataTemp", "EvacuationsTemp", "EvacuationRouteTemp", "TrafficLightTemp", "User"]
5+
__all__ = [
6+
"Base", "BaseDbModel", "FinesData", "Evacuations", "EvacuationRoute",
7+
"TrafficLight", "User", "Template", "StatsDBRegistry", "Document",
8+
]

backend/my_app_api/models/base.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
from __future__ import annotations
22

33
import re
4+
import pandas as pd
5+
from typing import List, Dict, Any
46

5-
from sqlalchemy import not_
7+
from sqlalchemy import not_, inspect
68
from sqlalchemy.exc import NoResultFound
79
from sqlalchemy.orm import Query, Session, as_declarative, declared_attr
810

@@ -14,7 +16,7 @@ class Base:
1416
"""Base class for all database entities"""
1517

1618
@declared_attr
17-
def __tablename__(cls) -> str: # pylint: disable=no-self-argument
19+
def __tablename__(cls) -> str:
1820
"""Generate database table name automatically.
1921
Convert CamelCase class name to snake_case db table name.
2022
"""
@@ -26,6 +28,19 @@ def __repr__(self):
2628
attrs.append(f"{c.name}={getattr(self, c.name)}")
2729
return "{}({})".format(c.__class__.__name__, ', '.join(attrs))
2830

31+
@classmethod
32+
def get_column_names(cls) -> List[str]:
33+
"""Get all column names for the model"""
34+
return [column.name for column in cls.__table__.columns]
35+
36+
@classmethod
37+
def from_csv_row(cls, row: Dict[str, Any]) -> Dict[str, Any]:
38+
"""Convert CSV row to model-compatible dictionary"""
39+
result = {}
40+
for column in cls.__table__.columns:
41+
if column.name in row:
42+
result[column.name] = row[column.name]
43+
return result
2944

3045
class BaseDbModel(Base):
3146
__abstract__ = True
@@ -37,6 +52,7 @@ def create(cls, *, session: Session, **kwargs) -> BaseDbModel:
3752
session.flush()
3853
return obj
3954

55+
4056
@classmethod
4157
def query(cls, *, with_deleted: bool = False, session: Session) -> Query:
4258
"""Get all objects with soft deletes"""

backend/my_app_api/models/db.py

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
from __future__ import annotations
22

3+
import uuid
34
import datetime
45
from enum import Enum
6+
from typing import List
57

6-
from sqlalchemy import Boolean, Date, Integer, String, Text, Numeric, Enum, DateTime
8+
from sqlalchemy import Boolean, Date, Integer, String, Text, Numeric, Enum as SQLEnum, DateTime, UUID, ARRAY, ForeignKey
79
from sqlalchemy.orm import Mapped, mapped_column, relationship
810

911
from .base import BaseDbModel
12+
from .db_editor import Document
1013

1114

1215

1316
class Role(str, Enum):
14-
USER: str = "user"
1517
EDITOR: str = "editor"
1618
ADMIN: str = "admin"
1719

@@ -20,12 +22,15 @@ class User(BaseDbModel):
2022
__tablename__ = 'user'
2123

2224
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
23-
first_name: Mapped[str] = mapped_column(String, nullable=False)
24-
last_name: Mapped[str] = mapped_column(String, nullable=False)
25-
middle_name: Mapped[str] = mapped_column(String, nullable=True)
26-
created_at: Mapped[datetime.datetime] = mapped_column(DateTime, default=datetime.now)
27-
28-
rule: Mapped[User] = mapped_column(Enum(Role, native_enum=False), nullable=False)
25+
first_name: Mapped[str] = mapped_column(String(100), nullable=False) # Добавлена длина
26+
last_name: Mapped[str] = mapped_column(String(100), nullable=False)
27+
middle_name: Mapped[str] = mapped_column(String(100), nullable=True) # Добавлена длина
28+
user_login: Mapped[str] = mapped_column(String(50), nullable=False, unique=True)
29+
password_hashed: Mapped[str] = mapped_column(String(255), nullable=False)
30+
is_active: Mapped[bool] = mapped_column(Boolean, default=True)
31+
role: Mapped[Role] = mapped_column(SQLEnum(Role, native_enum=False), nullable=False)
32+
33+
documents: Mapped[List["Document"]] = relationship("Document", back_populates="uploaded_by")
2934

3035

3136
class FinesData(BaseDbModel):
@@ -42,34 +47,32 @@ class FinesData(BaseDbModel):
4247
fines_collected: Mapped[float] = mapped_column(Numeric(15, 2), nullable=False)
4348

4449

45-
class Evacuations(BaseDbModel):
46-
__tablename__ = 'evacuations_data'
50+
class EvacuationRoute(BaseDbModel):
51+
__tablename__ = 'evacuation_routes'
4752

4853
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
49-
date: Mapped[datetime.date] = mapped_column(Date, nullable=False, index=True)
5054
year: Mapped[int] = mapped_column(Integer, nullable=False, index=True)
5155
month: Mapped[int] = mapped_column(Integer, nullable=False)
56+
route_path: Mapped[str] = mapped_column(Text)
5257

53-
tow_trucks_online: Mapped[int] = mapped_column(Integer, nullable=False)
54-
dispatches_count: Mapped[int] = mapped_column(Integer, nullable=False)
55-
evacuations_count: Mapped[int] = mapped_column(Integer, nullable=False)
56-
parking_receipts: Mapped[float] = mapped_column(Numeric(15, 2), nullable=False)
57-
58+
evacuations: Mapped[List["Evacuations"]] = relationship("Evacuations", back_populates="route")
5859

59-
class EvacuationRoute(BaseDbModel):
60-
__tablename__ = 'evacuation_routes'
60+
class Evacuations(BaseDbModel):
61+
__tablename__ = 'evacuations'
6162

6263
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
64+
date: Mapped[datetime.date] = mapped_column(Date, nullable=False, index=True)
6365
year: Mapped[int] = mapped_column(Integer, nullable=False, index=True)
6466
month: Mapped[int] = mapped_column(Integer, nullable=False)
6567

66-
route_description: Mapped[str] = mapped_column(Text, nullable=False)
67-
route_path: Mapped[str] = mapped_column(Text)
68+
route_id: Mapped[int] = mapped_column(ForeignKey('evacuation_routes.id'), nullable=True)
6869

70+
evacuators_count: Mapped[int] = mapped_column(Integer, nullable=False)
71+
call_count: Mapped[int] = mapped_column(Integer, nullable=False)
72+
evacuations_count: Mapped[int] = mapped_column(Integer, nullable=False)
73+
collected_sum: Mapped[float] = mapped_column(Numeric(15, 2), nullable=False)
6974

70-
evacuations = relationship("EvacuationsData",
71-
primaryjoin="and_(EvacuationsData.year == EvacuationRoute.year, "
72-
"EvacuationsData.month == EvacuationRoute.month)")
75+
route: Mapped[EvacuationRoute] = relationship("EvacuationRoute", back_populates="evacuations")
7376

7477

7578
class TrafficLight(BaseDbModel):
@@ -81,4 +84,3 @@ class TrafficLight(BaseDbModel):
8184
installation_year: Mapped[int] = mapped_column(Integer, nullable=False)
8285
worked: Mapped[bool] = mapped_column(Boolean, nullable=True)
8386

84-
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
from __future__ import annotations
2+
3+
import datetime
4+
from enum import Enum
5+
from typing import Dict, Any
6+
7+
from sqlalchemy import Integer, String, DateTime, Enum as SQLEnum, ForeignKey, JSON
8+
from sqlalchemy.orm import Mapped, mapped_column, relationship
9+
10+
from .base import BaseDbModel
11+
from .db import User
12+
13+
14+
class FileType(str, Enum):
15+
PDF: str = 'pdf'
16+
DOC: str = 'doc'
17+
DOCX: str = 'docx'
18+
19+
20+
class AdminFileType(str, Enum):
21+
PDF: str = 'pdf'
22+
DOC: str = 'doc'
23+
DOCX: str = 'docx'
24+
CSV: str = 'csv'
25+
XLSX: str = 'xlsx'
26+
XLS: str = 'xls'
27+
28+
29+
class Document(BaseDbModel):
30+
__tablename__ = 'documents'
31+
32+
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
33+
original_filename: Mapped[str] = mapped_column(String(255), nullable=False)
34+
filename: Mapped[str] = mapped_column(String(255), nullable=False)
35+
file_size: Mapped[int] = mapped_column(Integer, nullable=False)
36+
uploaded_at: Mapped[datetime.datetime] = mapped_column(DateTime, default=datetime.datetime.now)
37+
uploaded_by_id: Mapped[int] = mapped_column(ForeignKey('user.id'), nullable=False)
38+
path: Mapped[str] = mapped_column(String, nullable=False)
39+
description: Mapped[str] = mapped_column(String(500), nullable=True)
40+
41+
uploaded_by: Mapped[User] = relationship("User", back_populates="documents")
42+
43+
class EditorDocument(Document):
44+
__tablename__ = 'editor_documents'
45+
46+
id: Mapped[int] = mapped_column(ForeignKey('base_documents.id'), primary_key=True)
47+
file_type: Mapped[FileType] = mapped_column(SQLEnum(FileType, native_enum=False), nullable=False)
48+
49+
50+
class AdminDocument(Document):
51+
__tablename__ = 'admin_documents'
52+
53+
id: Mapped[int] = mapped_column(ForeignKey('base_documents.id'), primary_key=True)
54+
file_type: Mapped[AdminFileType] = mapped_column(SQLEnum(AdminFileType, native_enum=False), nullable=False)
55+
56+
57+
class Sections(BaseDbModel):
58+
__tablename__ = 'sections'
59+
60+
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
61+
name: Mapped[str] = mapped_column(String(100), nullable=False)
62+
section_type: Mapped[str] = mapped_column(String(50), nullable=True)
63+
64+
65+
class Posts(BaseDbModel):
66+
__tablename__ = 'posts'
67+
68+
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
69+
name: Mapped[str] = mapped_column(String(200), nullable=False)
70+
section_id: Mapped[int] = mapped_column(ForeignKey('sections.id'), nullable=True)
71+
contents: Mapped[Dict[str, Any]] = mapped_column(JSON, default=dict)
72+
uploaded_by_id: Mapped[int] = mapped_column(ForeignKey('user.id'), nullable=False)
73+
74+
uploaded_by: Mapped["User"] = relationship("User")
75+
section: Mapped[Sections] = relationship("Sections", back_populates="posts")

backend/my_app_api/models/db_temp.py

Lines changed: 0 additions & 85 deletions
This file was deleted.
Lines changed: 3 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,5 @@
1-
import logging
1+
from . import exc_handlers
2+
from .base import app
23

3-
from fastapi import FastAPI, Request
4-
from fastapi.middleware.cors import CORSMiddleware
5-
from fastapi.responses import RedirectResponse
6-
from fastapi_sqlalchemy import DBSessionMiddleware
7-
from my_app_api import __version__
8-
from my_app_api.settings import get_settings
9-
from starlette.datastructures import URL
104

11-
from .touch import router as touch_router
12-
13-
settings = get_settings()
14-
logger = logging.getLogger(__name__)
15-
app = FastAPI(
16-
title="Мое приложение",
17-
description="Бэкэнд приложения-примера",
18-
version=__version__,
19-
# Отключаем нелокальную документацию
20-
root_path=settings.ROOT_PATH if __version__ != "dev" else "",
21-
docs_url="/swagger",
22-
redoc_url=None,
23-
)
24-
25-
app.add_middleware(
26-
DBSessionMiddleware,
27-
db_url=str(settings.DB_DSN),
28-
engine_args={"pool_pre_ping": True, "isolation_level": "AUTOCOMMIT"},
29-
)
30-
31-
app.add_middleware(
32-
CORSMiddleware,
33-
allow_origins=settings.CORS_ALLOW_ORIGINS,
34-
allow_credentials=settings.CORS_ALLOW_CREDENTIALS,
35-
allow_methods=settings.CORS_ALLOW_METHODS,
36-
allow_headers=settings.CORS_ALLOW_HEADERS,
37-
)
38-
39-
40-
@app.get("/")
41-
def redirect(request: Request):
42-
url = URL(
43-
path="/ui/",
44-
query=request.url.components.query,
45-
fragment=request.url.components.fragment,
46-
)
47-
return RedirectResponse(url)
48-
49-
50-
app.include_router(touch_router)
5+
__all__ = ["app", "exc_handlers"]

backend/my_app_api/routes/admin/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)