Ukladani letu, query na seznam letist

This commit is contained in:
Michal Kváček
2023-06-06 07:34:45 +02:00
parent 014a999055
commit 69d30c8654
12 changed files with 301 additions and 64 deletions
@@ -0,0 +1,32 @@
"""flight edit
Revision ID: 66e39f31b1d2
Revises: 431adcd37681
Create Date: 2023-06-06 04:16:07.568446
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision = '66e39f31b1d2'
down_revision = '431adcd37681'
branch_labels = None
depends_on = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('flight', sa.Column('takeoff_datetime', sa.DateTime(), nullable=False))
op.add_column('flight', sa.Column('landing_datetime', sa.DateTime(), nullable=False))
op.drop_column('flight', 'duration_total')
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('flight', sa.Column('duration_total', mysql.INTEGER(display_width=11), autoincrement=False, nullable=False))
op.drop_column('flight', 'landing_datetime')
op.drop_column('flight', 'takeoff_datetime')
# ### end Alembic commands ###
@@ -0,0 +1,32 @@
"""flight edit
Revision ID: 5781b1432475
Revises: 66e39f31b1d2
Create Date: 2023-06-06 04:35:10.408586
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '5781b1432475'
down_revision = '66e39f31b1d2'
branch_labels = None
depends_on = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('flight', sa.Column('solo', sa.Boolean(), nullable=False))
op.add_column('flight', sa.Column('with_instructor', sa.Boolean(), nullable=False))
op.add_column('flight', sa.Column('landings', sa.Integer(), nullable=False))
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('flight', 'landings')
op.drop_column('flight', 'with_instructor')
op.drop_column('flight', 'solo')
# ### end Alembic commands ###
@@ -0,0 +1,34 @@
"""add soft delete
Revision ID: fd5fc5c1e2f6
Revises: 5781b1432475
Create Date: 2023-06-06 05:00:23.250817
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'fd5fc5c1e2f6'
down_revision = '5781b1432475'
branch_labels = None
depends_on = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('copilot', sa.Column('deleted', sa.Boolean(), server_default='0', nullable=False))
op.add_column('flight', sa.Column('deleted', sa.Boolean(), server_default='0', nullable=False))
op.add_column('metar', sa.Column('deleted', sa.Boolean(), server_default='0', nullable=False))
op.add_column('organization', sa.Column('deleted', sa.Boolean(), server_default='0', nullable=False))
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('organization', 'deleted')
op.drop_column('metar', 'deleted')
op.drop_column('flight', 'deleted')
op.drop_column('copilot', 'deleted')
# ### end Alembic commands ###
@@ -0,0 +1,32 @@
"""add soft delete
Revision ID: 559795b043f3
Revises: fd5fc5c1e2f6
Create Date: 2023-06-06 05:00:51.512887
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '559795b043f3'
down_revision = 'fd5fc5c1e2f6'
branch_labels = None
depends_on = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('airport', sa.Column('deleted', sa.Boolean(), server_default='0', nullable=False))
op.add_column('point_of_interest', sa.Column('deleted', sa.Boolean(), server_default='0', nullable=False))
op.add_column('point_of_interest_type', sa.Column('deleted', sa.Boolean(), server_default='0', nullable=False))
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('point_of_interest_type', 'deleted')
op.drop_column('point_of_interest', 'deleted')
op.drop_column('airport', 'deleted')
# ### end Alembic commands ###
+27 -4
View File
@@ -1,3 +1,4 @@
from __future__ import annotations
import datetime import datetime
from typing import Set from typing import Set
from sqlalchemy import String, DateTime, ForeignKey, Text, Integer, func, Table, Column, Boolean, select from sqlalchemy import String, DateTime, ForeignKey, Text, Integer, func, Table, Column, Boolean, select
@@ -17,6 +18,10 @@ class BaseModel:
if c.name not in self.excluded_columns_in_dict if c.name not in self.excluded_columns_in_dict
} }
@classmethod
async def get_one(cls, db_session: AsyncSession, id: int):
return (await db_session.scalars(select(cls).filter_by(id=id))).one()
@classmethod @classmethod
async def create(cls, db_session: AsyncSession, data: dict): async def create(cls, db_session: AsyncSession, data: dict):
model = cls(**data) model = cls(**data)
@@ -26,8 +31,12 @@ class BaseModel:
return model return model
@classmethod @classmethod
async def update(cls, db_session: AsyncSession, id: int, data: dict): async def update(cls, db_session: AsyncSession, data: dict, obj: BaseModel = None, id: int = None):
obj = (await db_session.scalars(select(cls).filter_by(id=id))).one() if not obj and not id:
raise ValueError("Provide either obj or id!")
if not obj:
obj = await cls.get_one(db_session, id)
for key, value in data.items(): for key, value in data.items():
if getattr(obj, key) != value: if getattr(obj, key) != value:
setattr(obj, key, value) setattr(obj, key, value)
@@ -56,6 +65,7 @@ class Airport(BaseModel):
gps_position: Mapped[Point] = mapped_column(Point, nullable=True) gps_position: Mapped[Point] = mapped_column(Point, nullable=True)
elevation: Mapped[int] = mapped_column(Integer, nullable=True) elevation: Mapped[int] = mapped_column(Integer, nullable=True)
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now()) created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
deleted: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default='0')
metars: Mapped['Metar'] = relationship(back_populates="airport") metars: Mapped['Metar'] = relationship(back_populates="airport")
@@ -68,6 +78,7 @@ class PointOfInterestType(BaseModel):
is_public: Mapped[bool] = mapped_column(Boolean, server_default='0') is_public: Mapped[bool] = mapped_column(Boolean, server_default='0')
created_by_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id')) created_by_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id'))
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now()) created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
deleted: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default='0')
created_by: Mapped['User'] = relationship() created_by: Mapped['User'] = relationship()
@@ -82,6 +93,7 @@ class PointOfInterest(BaseModel):
is_public: Mapped[bool] = mapped_column(Boolean, server_default='0') is_public: Mapped[bool] = mapped_column(Boolean, server_default='0')
created_by_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id')) created_by_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id'))
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now()) created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
deleted: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default='0')
type: Mapped[PointOfInterestType] = relationship() type: Mapped[PointOfInterestType] = relationship()
created_by: Mapped['User'] = relationship() created_by: Mapped['User'] = relationship()
@@ -145,6 +157,7 @@ class Organization(BaseModel):
name: Mapped[str] = mapped_column(String(128), nullable=False) name: Mapped[str] = mapped_column(String(128), nullable=False)
created_by_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id')) created_by_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id'))
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now()) created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
deleted: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default='0')
users: Mapped[Set['User']] = relationship(back_populates='organizations', secondary=user_is_in_organization) users: Mapped[Set['User']] = relationship(back_populates='organizations', secondary=user_is_in_organization)
created_by: Mapped['User'] = relationship() created_by: Mapped['User'] = relationship()
@@ -168,14 +181,21 @@ class Flight(BaseModel):
id: Mapped[int] = mapped_column(primary_key=True) id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column(String(128), nullable=False) name: Mapped[str] = mapped_column(String(128), nullable=False)
description: Mapped[str] = mapped_column(Text, nullable=False) description: Mapped[str] = mapped_column(Text, nullable=False)
takeoff_datetime: Mapped[datetime] = mapped_column(DateTime, nullable=False)
landing_datetime: Mapped[datetime] = mapped_column(DateTime, nullable=False)
duration_pic: Mapped[int] = mapped_column(Integer, nullable=False)
takeoff_airport_id: Mapped[int] = mapped_column(Integer, ForeignKey("airport.id"), nullable=True) takeoff_airport_id: Mapped[int] = mapped_column(Integer, ForeignKey("airport.id"), nullable=True)
landing_airport_id: Mapped[int] = mapped_column(Integer, ForeignKey("airport.id"), nullable=True) landing_airport_id: Mapped[int] = mapped_column(Integer, ForeignKey("airport.id"), nullable=True)
aircraft_id: Mapped[int] = mapped_column(Integer, ForeignKey('aircraft.id')) aircraft_id: Mapped[int] = mapped_column(Integer, ForeignKey('aircraft.id'))
copilot_id: Mapped[int] = mapped_column(Integer, ForeignKey('copilot.id'), nullable=True) copilot_id: Mapped[int] = mapped_column(Integer, ForeignKey('copilot.id'), nullable=True)
solo: Mapped[bool] = mapped_column(Boolean, default=True)
with_instructor: Mapped[bool] = mapped_column(Boolean, default=False)
landings: Mapped[int] = mapped_column(Integer, default=1)
created_by_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id')) created_by_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id'))
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now()) created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
duration_total: Mapped[int] = mapped_column(Integer, nullable=False) deleted: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default='0')
duration_pic: Mapped[int] = mapped_column(Integer, nullable=False)
takeoff_airport: Mapped['Airport'] = relationship(foreign_keys=[takeoff_airport_id]) takeoff_airport: Mapped['Airport'] = relationship(foreign_keys=[takeoff_airport_id])
landing_airport: Mapped['Airport'] = relationship(foreign_keys=[landing_airport_id]) landing_airport: Mapped['Airport'] = relationship(foreign_keys=[landing_airport_id])
@@ -184,6 +204,7 @@ class Flight(BaseModel):
photos: Mapped[Set['Photo']] = relationship() photos: Mapped[Set['Photo']] = relationship()
user: Mapped['User'] = relationship(back_populates="flights") user: Mapped['User'] = relationship(back_populates="flights")
created_by: Mapped['User'] = relationship() created_by: Mapped['User'] = relationship()
# flight_track: Mapped[List['PointOfInterest']] = relationship(secondary=FlightTrack) # flight_track: Mapped[List['PointOfInterest']] = relationship(secondary=FlightTrack)
@@ -194,6 +215,7 @@ class Copilot(BaseModel):
name: Mapped[str] = mapped_column(String(128), nullable=False) name: Mapped[str] = mapped_column(String(128), nullable=False)
created_by_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id')) created_by_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id'))
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now()) created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
deleted: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default='0')
flights: Mapped[Set['Flight']] = relationship(back_populates="copilot") flights: Mapped[Set['Flight']] = relationship(back_populates="copilot")
created_by: Mapped['User'] = relationship() created_by: Mapped['User'] = relationship()
@@ -206,6 +228,7 @@ class Metar(BaseModel):
airport_id: Mapped[int] = mapped_column(Integer, ForeignKey('airport.id')) airport_id: Mapped[int] = mapped_column(Integer, ForeignKey('airport.id'))
metar: Mapped[str] = mapped_column(Text, nullable=False) metar: Mapped[str] = mapped_column(Text, nullable=False)
issued_at: Mapped[datetime] = mapped_column(DateTime) issued_at: Mapped[datetime] = mapped_column(DateTime)
deleted: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default='0')
airport: Mapped['Airport'] = relationship(back_populates="metars") airport: Mapped['Airport'] = relationship(back_populates="metars")
+16
View File
@@ -0,0 +1,16 @@
from typing import List
from sqlalchemy import select
from strawberry.dataloader import DataLoader
from database import async_session
from database.models import Airport
async def load(ids: List[int]):
async with async_session() as session:
models = (await session.scalars(select(Airport).filter(Airport.id.in_(ids)))).all()
models_by_id = {model.id: model for model in models}
return [models_by_id.get(id_) for id_ in ids]
airport_dataloader = DataLoader(load_fn=load)
+17 -37
View File
@@ -1,4 +1,3 @@
import os
import uuid import uuid
from typing import List, Optional from typing import List, Optional
import strawberry import strawberry
@@ -6,6 +5,9 @@ from strawberry.file_uploads import Upload
from sqlalchemy import select from sqlalchemy import select
from database import models from database import models
from graphql_schema.sqlalchemy_to_strawberry_type import strawberry_sqlalchemy_type, strawberry_sqlalchemy_input from graphql_schema.sqlalchemy_to_strawberry_type import strawberry_sqlalchemy_type, strawberry_sqlalchemy_input
from upload_utils import handle_img_upload, delete_file
AIRCRAFT_UPLOAD_DEST_PATH = "/app/uploads/aircrafts/"
@strawberry_sqlalchemy_type(models.Aircraft) @strawberry_sqlalchemy_type(models.Aircraft)
@@ -44,20 +46,6 @@ class AircraftQueries:
return (await info.context.db.scalars(query)).one() return (await info.context.db.scalars(query)).one()
def check_directories(path: str):
if not os.path.isdir(path):
os.makedirs(path)
async def handle_img_upload(file: Upload, path: str, filename: str):
check_directories(path)
content = await file.read()
image = open(path + "/" + filename, "wb")
image.write(content)
image.close()
@strawberry.type @strawberry.type
class CreateAircraftMutation: class CreateAircraftMutation:
@strawberry_sqlalchemy_input(models.Aircraft, exclude_fields=['id', 'photo_filename']) @strawberry_sqlalchemy_input(models.Aircraft, exclude_fields=['id', 'photo_filename'])
@@ -68,21 +56,14 @@ class CreateAircraftMutation:
async def create_aircraft(root, info, input: CreateAircraftInput) -> Aircraft: async def create_aircraft(root, info, input: CreateAircraftInput) -> Aircraft:
# TODO: kontrola organizace # TODO: kontrola organizace
filename = None input_data = input.to_dict()
if input.photo: if input.photo:
dest_path = "/app/uploads/aircrafts/" input_data['photo_filename'] = await handle_img_upload(input.photo, AIRCRAFT_UPLOAD_DEST_PATH)
filename = f"{uuid.uuid4()}-{input.photo.filename}"
await handle_img_upload(input.photo, dest_path, filename=filename)
return await models.Aircraft.create( return await models.Aircraft.create(
info.context.db, info.context.db,
data=dict( data=dict(
name=input.name, **input_data,
description=input.description,
model=input.model,
manufacturer=input.manufacturer,
photo_filename=filename,
organization_id=input.organization_id,
created_by_id=info.context.user_id, created_by_id=info.context.user_id,
) )
) )
@@ -98,17 +79,16 @@ class EditAircraftMutation:
async def edit_aircraft(root, info, id: int, input: EditAircraftInput) -> Aircraft: async def edit_aircraft(root, info, id: int, input: EditAircraftInput) -> Aircraft:
# TODO: kontrola organizace # TODO: kontrola organizace
# TODO: kontrola opravneni na akci # TODO: kontrola opravneni na akci
return await models.Aircraft.update(
info.context.db, update_data = input.to_dict()
id, aircraft = await models.Aircraft.get_one(info.context.db, id)
data=dict(
name=input.name, if input.photo:
description=input.description, if aircraft.photo_filename:
model=input.model, delete_file(AIRCRAFT_UPLOAD_DEST_PATH + "/" + aircraft.photo_filename, silent=True)
manufacturer=input.manufacturer, update_data['photo_filename'] = await handle_img_upload(input.photo, AIRCRAFT_UPLOAD_DEST_PATH)
organization_id=input.organization_id,
) return await models.Aircraft.update(info.context.db, obj=aircraft, data=update_data)
)
@strawberry.type @strawberry.type
@@ -118,4 +98,4 @@ class DeleteAircraftMutation:
async def delete_aircraft(self, info, id: int) -> Aircraft: async def delete_aircraft(self, info, id: int) -> Aircraft:
# TODO: kontrola opravneni na akci # TODO: kontrola opravneni na akci
return await models.Aircraft.update(info.context.db, id, data=dict(deleted=True)) return await models.Aircraft.update(info.context.db, id=id, data=dict(deleted=True))
+38
View File
@@ -0,0 +1,38 @@
from typing import List
import strawberry
from sqlalchemy import select
from database import models
from graphql_schema.sqlalchemy_to_strawberry_type import strawberry_sqlalchemy_type
@strawberry_sqlalchemy_type(models.Airport)
class Airport:
pass
def get_base_query(user_id: int):
return (
select(models.Airport)
.filter(models.Airport.deleted.is_(False))
)
@strawberry.type
class AirportQueries:
@strawberry.field
async def airports(root, info) -> List[Airport]:
query = (
get_base_query(info.context.user_id)
.order_by(models.Airport.id.desc())
)
return (await info.context.db.scalars(query)).all()
@strawberry.field
async def airport(root, info, id: int) -> Airport:
query = (
get_base_query(info.context.user_id)
.filter(models.Airport.id == id)
)
return (await info.context.db.scalars(query)).one()
+31 -16
View File
@@ -1,10 +1,14 @@
from typing import List, Optional from typing import List, Optional
import strawberry import strawberry
from sqlalchemy import select from sqlalchemy import select
from strawberry.file_uploads import Upload
from database import models from database import models
from graphql_schema.dataloaders import copilots_dataloader from graphql_schema.dataloaders import copilots_dataloader
from graphql_schema.dataloaders.aircraft import aircraft_dataloader from graphql_schema.dataloaders.aircraft import aircraft_dataloader
from graphql_schema.dataloaders.airport import airport_dataloader
from graphql_schema.entities.aircraft import Aircraft from graphql_schema.entities.aircraft import Aircraft
from graphql_schema.entities.airport import Airport
from graphql_schema.entities.copilot import CopilotType from graphql_schema.entities.copilot import CopilotType
from graphql_schema.sqlalchemy_to_strawberry_type import strawberry_sqlalchemy_type, strawberry_sqlalchemy_input from graphql_schema.sqlalchemy_to_strawberry_type import strawberry_sqlalchemy_type, strawberry_sqlalchemy_input
@@ -13,6 +17,11 @@ from graphql_schema.sqlalchemy_to_strawberry_type import strawberry_sqlalchemy_t
@strawberry_sqlalchemy_type(models.Flight) @strawberry_sqlalchemy_type(models.Flight)
class Flight: class Flight:
async def load_takeoff_airport(root):
return await airport_dataloader.load(root.takeoff_airport_id)
async def load_landing_airport(root):
return await airport_dataloader.load(root.landing_airport_id)
async def load_aircraft(root): async def load_aircraft(root):
return await aircraft_dataloader.load(root.aircraft_id) return await aircraft_dataloader.load(root.aircraft_id)
@@ -22,6 +31,17 @@ class Flight:
copilot: Optional[CopilotType] = strawberry.field(resolver=load_copilot) copilot: Optional[CopilotType] = strawberry.field(resolver=load_copilot)
aircraft: Aircraft = strawberry.field(resolver=load_aircraft) aircraft: Aircraft = strawberry.field(resolver=load_aircraft)
takeoff_airport: Airport = strawberry.field(resolver=load_takeoff_airport)
landing_airport: Airport = strawberry.field(resolver=load_landing_airport)
# take_off_airport = Airport
def get_base_query(user_id: int):
return (
select(models.Flight)
.filter(models.Flight.created_by_id == user_id)
.order_by(models.Flight.id.desc())
)
@strawberry.type @strawberry.type
@@ -32,36 +52,31 @@ class FlightQueries:
@strawberry.field @strawberry.field
async def flights(root, info, filters: Optional[FlightFilters] = None) -> List[Flight]: async def flights(root, info, filters: Optional[FlightFilters] = None) -> List[Flight]:
query = ( query = get_base_query(info.context.user_id).order_by(models.Flight.id.desc())
select(models.Flight)
.filter(models.Flight.created_by_id == info.context.user_id)
.order_by(models.Flight.id) # TODO: desc
)
return (await info.context.db.scalars(query)).all() return (await info.context.db.scalars(query)).all()
@strawberry.field @strawberry.field
async def flight(root, info, id: int) -> Flight: async def flight(root, info, id: int) -> Flight:
query = ( query = (
select(models.Flight) get_base_query(info.context.user_id)
.filter(models.Flight.id == id) .filter(models.Flight.id == id)
.filter(models.Flight.created_by_id == info.context.user_id)
) )
return (await info.context.db.scalars(query)).fetch_one() return (await info.context.db.scalars(query)).fetch_one()
@strawberry.type @strawberry.type
class CreateFlightMutation: class CreateFlightMutation:
@strawberry_sqlalchemy_input(models.Flight, all_optional=True) @strawberry_sqlalchemy_input(models.Flight, exclude_fields=["id"])
class FlightInput: class CreateFlightInput:
# photos: Optional[List[Upload]]
pass pass
@strawberry.mutation @strawberry.mutation
async def create_flight(self, info, input_: FlightInput) -> Flight: async def create_flight(self, info, input: CreateFlightInput) -> Flight:
model = models.Flight(name=input_.name) input_data = input.to_dict()
db = info.context.db return await models.Flight.create(info.context.db, data={
db.add(model) **input_data,
await db.commit() "created_by_id": info.context.user_id
})
return Flight(model)
+2
View File
@@ -1,5 +1,6 @@
from strawberry.tools import merge_types from strawberry.tools import merge_types
from .entities.aircraft import AircraftQueries from .entities.aircraft import AircraftQueries
from .entities.airport import AirportQueries
from .entities.copilot import CopilotQueries from .entities.copilot import CopilotQueries
from .entities.flight import FlightQueries from .entities.flight import FlightQueries
from .entities.user import UserQueries from .entities.user import UserQueries
@@ -9,6 +10,7 @@ from .entities.user import UserQueries
Query = merge_types('Query', ( Query = merge_types('Query', (
AircraftQueries, AircraftQueries,
AirportQueries,
FlightQueries, FlightQueries,
CopilotQueries, CopilotQueries,
UserQueries UserQueries
@@ -1,20 +1,26 @@
import typing import typing
from typing import List, Optional from typing import List, Optional
import strawberry import strawberry
from sqlalchemy import inspect import sqlalchemy
from sqlalchemy import Column
from database.models import BaseModel from database.models import BaseModel
def get_columns_from_model(model: BaseModel, exclude_fields: List[str]) -> List[typing.Tuple[str, Column]]:
return [(name, column) for name, column in sqlalchemy.inspect(model).columns.items() if name not in exclude_fields]
def get_annotations_for_scalars(model: BaseModel, exclude_fields=None, force_optional: bool = False): def get_annotations_for_scalars(model: BaseModel, exclude_fields=None, force_optional: bool = False):
if exclude_fields is None: if exclude_fields is None:
exclude_fields = [] exclude_fields = []
annotations_ = {} annotations_ = {}
for name, column in inspect(model).columns.items(): for name, column in get_columns_from_model(model, exclude_fields):
is_optional = column.nullable or force_optional is_optional = column.nullable or force_optional
if name in exclude_fields: try:
continue
annotations_[name] = column.type.python_type if not is_optional else typing.Optional[column.type.python_type] annotations_[name] = column.type.python_type if not is_optional else typing.Optional[column.type.python_type]
except NotImplementedError as e:
print(f"Neimplementovano: {e}, {name=}")
return annotations_ return annotations_
@@ -41,14 +47,18 @@ def strawberry_sqlalchemy_input(
if exclude_fields is None: if exclude_fields is None:
exclude_fields = [] exclude_fields = []
ignored_fields = ["created_at", "created_by_id", "updated_by_id", "updated_at", "deleted"] ignored_fields = exclude_fields + ["created_at", "created_by_id", "updated_by_id", "updated_at", "deleted"]
def to_dict(self):
return {name: getattr(self, name) for name, _ in get_columns_from_model(model, ignored_fields)}
def wrapper(cls): def wrapper(cls):
cls.__annotations__.update(get_annotations_for_scalars( cls.__annotations__.update(get_annotations_for_scalars(
model, model,
exclude_fields=exclude_fields + ignored_fields, exclude_fields=ignored_fields,
force_optional=all_optional force_optional=all_optional
)) ))
cls.to_dict = to_dict
return strawberry.input(cls) return strawberry.input(cls)
return wrapper return wrapper
+23
View File
@@ -0,0 +1,23 @@
import os
import uuid
from strawberry.file_uploads import Upload
def check_directories(path: str):
if not os.path.isdir(path):
os.makedirs(path)
async def handle_img_upload(file: Upload, path: str):
check_directories(path)
filename = f"{uuid.uuid4()}-{file.filename}"
content = await file.read()
image = open(path + "/" + filename, "wb")
image.write(content)
image.close()
def delete_file(path: str, silent: bool = False):
os.remove(path)