added models

parent 1881bdb8
FROM python:3.10-slim-buster
RUN pip3 install --upgrade pip && pip3 install poetry
WORKDIR /app
COPY pyproject.toml poetry.lock /app/
RUN poetry config virtualenvs.create false \
&& poetry install --no-interaction --no-ansi
COPY . .
version: '3'
services:
core:
build:
context: .
dockerfile: Dockerfile
image: task_treker:1.0
restart: always
ports:
- "8000:8000"
environment:
- database_url=postgres://postgres:postgres@db:5432/postgres
networks:
- tasktrekernetwork
volumes:
- .:/app
command: bash -c "poetry run python3 src/app/main.py"
depends_on:
- db
db:
image: postgres:14-alpine
environment:
- POSTGRES_PASSWORD=postgres
ports:
- "5436:5432"
volumes:
- ./data/postgres:/var/lib/postgresql/data/
networks:
- tasktrekernetwork
networks:
tasktrekernetwork:
driver: bridge
This diff is collapsed.
......@@ -9,8 +9,16 @@ readme = "README.md"
python = "^3.10"
fastapi = "^0.104.1"
uvicorn = "^0.24.0.post1"
tortoise-orm = {extras = ["asyncodbc"], version = "^0.20.0"}
aerich = "^0.7.2"
asyncpg = "^0.29.0"
[tool.aerich]
tortoise_orm = "src.app.db.conf.TORTOISE_ORM"
location = "src/migrations"
src_folder = "./."
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
from exceptions import common as common_exc, http as http_exc
class BaseController:
repo = None
async def get_list(self, **kwargs) -> list[dict]:
return await self.repo.get_list(**kwargs)
async def get(self, id: int) -> dict:
try:
return await self.repo.get(id)
except common_exc.NotFoundException as e:
raise http_exc.HTTPNotFoundException(detail=str(e))
async def create(self, **data) -> dict:
try:
return await self.repo.create(**data)
except common_exc.CreateException as e:
raise http_exc.HTTPBadRequestException(detail=str(e))
async def update(self, id: int, **kwargs) -> dict:
try:
return await self.repo.update(id, **kwargs)
except common_exc.NotFoundException as e:
raise http_exc.HTTPNotFoundException(detail=str(e))
except common_exc.UpdateException as e:
raise http_exc.HTTPBadRequestException(detail=str(e))
async def delete(self, id: int) -> None:
try:
return await self.repo.delete(id)
except common_exc.NotFoundException as e:
raise http_exc.HTTPNotFoundException(detail=str(e))
except common_exc.DeleteException as e:
raise http_exc.HTTPBadRequestException(detail=str(e))
from fastapi import APIRouter
# from .director.routes import router as director_route
# from .genre.routes import router as genre_route
# from .movie.routes import router as movie_route
router = APIRouter(prefix='/api')
# router.include_router(director_route)
# router.include_router(genre_route)
# router.include_router(movie_route)
from uuid import uuid4
from tortoise import fields, models
class IdMixin(models.Model):
id = fields.UUIDField(pk=True, default=uuid4)
class Meta:
abstract = True
class TimestampMixin(models.Model):
created_at = fields.DatetimeField(auto_now_add=True)
updated_at = fields.DatetimeField(auto_now=True)
class Meta:
abstract = True
class BaseModel(IdMixin, TimestampMixin):
class Meta:
ordering = ('-created_at', )
import os
from fastapi import FastAPI
from tortoise.contrib.fastapi import register_tortoise
TORTOISE_ORM = {
'connections': {'default': os.environ.get('database_url')},
'apps': {
'models': {
'models': ['src.app.db.models', 'aerich.models'],
'default_connection': 'default',
},
},
}
def init_db(app: FastAPI) -> None:
register_tortoise(
app,
db_url=os.environ.get('database_url'),
modules={"models": ["db.models"]},
generate_schemas=False,
add_exception_handlers=True,
)
from tortoise import fields
from .base import BaseModel
class Status(BaseModel):
name = fields.CharField(max_length=255)
def __str__(self):
return self.name
class Meta(BaseModel.Meta):
table = 'statuses'
class Type(BaseModel):
name = fields.CharField(max_length=255)
def __str__(self):
return self.name
class Meta(BaseModel.Meta):
table = 'types'
class Task(BaseModel):
title = fields.CharField(max_length=255)
description = fields.TextField()
status = fields.ForeignKeyField(
'models.Status', related_name='status_tasks',
on_delete=fields.OnDelete.CASCADE
)
types = fields.ManyToManyField(
'models.Type', related_name='type_tasks',
through='types_tasks'
)
def __str__(self):
return self.title
class Meta(BaseModel.Meta):
table = 'tasks'
class User(BaseModel):
username = fields.CharField(max_length=100, unique=True)
password = fields.CharField(max_length=255)
def __str__(self):
return self.username
class Meta:
table = 'users'
class Comment(BaseModel):
user = fields.ForeignKeyField(
'models.User', related_name='user_comments',
on_delete=fields.OnDelete.CASCADE
)
task = fields.ForeignKeyField(
'models.Task', related_name='task_comments',
on_delete=fields.OnDelete.CASCADE
)
text = fields.TextField()
class Meta:
table = 'comments'
import tortoise
from exceptions import common as common_exc
class BaseRepository:
model: tortoise.Model
async def get_list(self, **kwargs) -> list[tortoise.Model]:
return await self.model.filter(**kwargs)
async def get(self, id: int) -> tortoise.Model:
try:
return await self.model.get(id=id)
except tortoise.exceptions.DoesNotExist as e:
raise common_exc.NotFoundException(str(e))
async def create(self, **kwargs) -> tortoise.Model:
try:
return await self.model.create(**kwargs)
except tortoise.exceptions.IntegrityError as e:
raise common_exc.CreateException(str(e))
async def update(self, id: int, **kwargs) -> tortoise.Model:
try:
instance = await self.get(id=id)
await instance.update_from_dict(kwargs).save()
return instance
except tortoise.exceptions.IntegrityError as e:
raise common_exc.UpdateException(str(e))
async def delete(self, id: int) -> None:
try:
instance = await self.get(id=id)
await instance.delete()
except tortoise.exceptions.IntegrityError as e:
raise common_exc.DeleteException(str(e))
class DirectorRepository(BaseRepository):
model = movie.Director
class GenreRepository(BaseRepository):
model = movie.Genre
class MovieRepository(BaseRepository):
model = movie.Movie
class NotFoundException(Exception):
pass
class CreateException(Exception):
pass
class UpdateException(Exception):
pass
class DeleteException(Exception):
pass
import fastapi
import pydantic
from starlette import status
from fastapi.responses import JSONResponse
from .http import BaseHTTPException
async def query_params_exc_handler(
request: fastapi.Request, exc: pydantic.ValidationError,
) -> JSONResponse:
return JSONResponse(
{'detail': exc.errors()}, status.HTTP_422_UNPROCESSABLE_ENTITY,
)
async def request_exc_handler(
request: fastapi.Request, exc: BaseHTTPException,
) -> JSONResponse:
return JSONResponse(
{'detail': exc.detail}, exc.status_code,
)
async def internal_exc_handler(
request: fastapi.Request, exc: Exception,
) -> JSONResponse:
return JSONResponse(
{'detail': 'Internal Server Error'},
status.HTTP_500_INTERNAL_SERVER_ERROR,
)
from typing import Any, Dict
from fastapi.exceptions import HTTPException
from starlette import status
class BaseHTTPException(HTTPException):
pass
class HTTPBadRequestException(BaseHTTPException):
def __init__(
self, status_code: int = status.HTTP_400_BAD_REQUEST, detail: Any = None,
headers: Dict[str, str] | None = None
) -> None:
super().__init__(status_code, detail, headers)
class HTTPNotFoundException(BaseHTTPException):
def __init__(
self, status_code: int = status.HTTP_404_NOT_FOUND, detail: Any = None,
headers: Dict[str, str] | None = None
) -> None:
super().__init__(status_code, detail, headers)
import fastapi
import pydantic
from api.router import router
from exceptions import handlers as exc_handlers, http as http_exc
from db.conf import init_db
def setup():
app = fastapi.FastAPI()
app.include_router(router)
app.exception_handler(pydantic.ValidationError)(exc_handlers.query_params_exc_handler)
app.exception_handler(http_exc.BaseHTTPException)(exc_handlers.request_exc_handler)
app.exception_handler(500)(exc_handlers.internal_exc_handler)
return app
app = setup()
init_db(app)
if __name__ == '__main__':
import uvicorn
uvicorn.run('main:app', host='0.0.0.0', port=8000, reload=True)
import os
import pydantic
database_url = pydantic.PostgresDsn(os.getenv('database_url'))
from tortoise import BaseDBAsyncClient
async def upgrade(db: BaseDBAsyncClient) -> str:
return """
CREATE TABLE IF NOT EXISTS "basemodel" (
"id" UUID NOT NULL PRIMARY KEY,
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS "statuses" (
"id" UUID NOT NULL PRIMARY KEY,
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
"name" VARCHAR(255) NOT NULL
);
CREATE TABLE IF NOT EXISTS "tasks" (
"id" UUID NOT NULL PRIMARY KEY,
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
"title" VARCHAR(255) NOT NULL,
"description" TEXT NOT NULL,
"status_id" UUID NOT NULL REFERENCES "statuses" ("id") ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS "types" (
"id" UUID NOT NULL PRIMARY KEY,
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
"name" VARCHAR(255) NOT NULL
);
CREATE TABLE IF NOT EXISTS "aerich" (
"id" SERIAL NOT NULL PRIMARY KEY,
"version" VARCHAR(255) NOT NULL,
"app" VARCHAR(100) NOT NULL,
"content" JSONB NOT NULL
);
CREATE TABLE IF NOT EXISTS "types_tasks" (
"tasks_id" UUID NOT NULL REFERENCES "tasks" ("id") ON DELETE CASCADE,
"type_id" UUID NOT NULL REFERENCES "types" ("id") ON DELETE CASCADE
);"""
async def downgrade(db: BaseDBAsyncClient) -> str:
return """
"""
from tortoise import BaseDBAsyncClient
async def upgrade(db: BaseDBAsyncClient) -> str:
return """
CREATE TABLE IF NOT EXISTS "users" (
"id" UUID NOT NULL PRIMARY KEY,
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
"username" VARCHAR(100) NOT NULL UNIQUE,
"password" VARCHAR(255) NOT NULL
);"""
async def downgrade(db: BaseDBAsyncClient) -> str:
return """
DROP TABLE IF EXISTS "users";"""
from tortoise import BaseDBAsyncClient
async def upgrade(db: BaseDBAsyncClient) -> str:
return """
CREATE TABLE IF NOT EXISTS "comments" (
"id" UUID NOT NULL PRIMARY KEY,
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
"text" TEXT NOT NULL,
"task_id" UUID NOT NULL REFERENCES "tasks" ("id") ON DELETE CASCADE,
"user_id" UUID NOT NULL REFERENCES "users" ("id") ON DELETE CASCADE
);"""
async def downgrade(db: BaseDBAsyncClient) -> str:
return """
DROP TABLE IF EXISTS "comments";"""
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment