Uprava nahravani, zmeny v modelech

This commit is contained in:
Michal Kváček
2023-06-27 22:45:03 +02:00
parent 1cf1f84e92
commit ba5c3b6a49
9 changed files with 124 additions and 17 deletions
+7 -4
View File
@@ -1,6 +1,6 @@
from __future__ import annotations
import datetime
from typing import Set
from typing import Set, List
from sqlalchemy import String, DateTime, ForeignKey, Text, Integer, func, Table, Column, Boolean, select
from sqlalchemy.orm import Mapped, relationship, as_declarative, mapped_column
from database.custom_types import Point
@@ -9,6 +9,8 @@ from sqlalchemy.ext.asyncio import AsyncSession
@as_declarative()
class BaseModel:
# __mapper_args__ = {"eager_defaults": True}
excluded_columns_in_dict = tuple()
def as_dict(self):
@@ -26,7 +28,8 @@ class BaseModel:
async def create(cls, db_session: AsyncSession, data: dict):
model = cls(**data)
db_session.add(model)
await db_session.commit()
# await db_session.flush()
# await db_session.refresh(model)
return model
@@ -111,7 +114,7 @@ class Photo(BaseModel):
created_by_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id'))
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
flight: Mapped['Flight'] = relationship(back_populates="photos")
flight: Mapped['Flight'] = relationship()
created_by: Mapped['User'] = relationship()
@@ -202,7 +205,7 @@ class Flight(BaseModel):
landing_airport: Mapped['Airport'] = relationship(foreign_keys=[landing_airport_id])
copilot: Mapped['Copilot'] = relationship(back_populates="flights")
aircraft: Mapped['Aircraft'] = relationship(back_populates="flights")
photos: Mapped[Set['Photo']] = relationship()
photos: Mapped[List['Photo']] = relationship()
user: Mapped['User'] = relationship(back_populates="flights")
created_by: Mapped['User'] = relationship()
+1
View File
@@ -5,3 +5,4 @@ async def db_session():
async with async_session() as session:
async with session.begin():
yield session
await session.commit()
+4 -3
View File
@@ -5,7 +5,7 @@ from strawberry.file_uploads import Upload
from sqlalchemy import select
from database import models
from graphql_schema.sqlalchemy_to_strawberry_type import strawberry_sqlalchemy_type, strawberry_sqlalchemy_input
from upload_utils import handle_img_upload, delete_file
from upload_utils import handle_file_upload, delete_file
AIRCRAFT_UPLOAD_DEST_PATH = "/app/uploads/aircrafts/"
@@ -52,13 +52,14 @@ class CreateAircraftMutation:
class CreateAircraftInput:
photo: Optional[Upload]
@strawberry.mutation
async def create_aircraft(root, info, input: CreateAircraftInput) -> Aircraft:
# TODO: kontrola organizace
input_data = input.to_dict()
if input.photo:
input_data['photo_filename'] = await handle_img_upload(input.photo, AIRCRAFT_UPLOAD_DEST_PATH)
input_data['photo_filename'] = await handle_file_upload(input.photo, AIRCRAFT_UPLOAD_DEST_PATH)
return await models.Aircraft.create(
info.context.db,
@@ -86,7 +87,7 @@ class EditAircraftMutation:
if input.photo:
if aircraft.photo_filename:
delete_file(AIRCRAFT_UPLOAD_DEST_PATH + "/" + aircraft.photo_filename, silent=True)
update_data['photo_filename'] = await handle_img_upload(input.photo, AIRCRAFT_UPLOAD_DEST_PATH)
update_data['photo_filename'] = await handle_file_upload(input.photo, AIRCRAFT_UPLOAD_DEST_PATH)
return await models.Aircraft.update(info.context.db, obj=aircraft, data=update_data)
+32 -1
View File
@@ -12,6 +12,7 @@ from graphql_schema.entities.aircraft import Aircraft
from graphql_schema.entities.airport import Airport
from graphql_schema.entities.copilot import CopilotType
from graphql_schema.sqlalchemy_to_strawberry_type import strawberry_sqlalchemy_type, strawberry_sqlalchemy_input
from upload_utils import handle_file_upload
# Bude se hodit: https://strawberry.rocks/docs/types/lazy
@@ -88,7 +89,37 @@ class CreateFlightMutation:
async def create_flight(self, info, input: CreateFlightInput) -> Flight:
input_data = input.to_dict()
return await models.Flight.create(info.context.db, data={
flight = await models.Flight.create(info.context.db, data={
**input_data,
# "photos": [], # aby se nedelal select pri vytvareni fotek
"created_by_id": info.context.user_id
})
await info.context.db.flush()
#
# if input.photos:
# photos_dest = f"/app/uploads/photos/{flight.id}/"
# for photo in input.photos:
# filename = await handle_file_upload(photo, photos_dest)
# flight.photos.append(models.Photo(**{
# "name": "",
# "filename": filename,
# "description": "",
# "created_by_id": info.context.user_id,
# }))
return flight
@strawberry.type
class EditFlightMutation:
@strawberry_sqlalchemy_input(models.Flight, exclude_fields=["id"], all_optional=True)
class EditFlightInput:
pass
@strawberry.mutation
async def edit_flight(self, info, id: int, input: EditFlightInput) -> Flight:
input_data = input.to_dict()
return await models.Flight.update(info.context.db, id=id, data=input_data)
+52
View File
@@ -0,0 +1,52 @@
from typing import List, Optional
import strawberry
from sqlalchemy import select
from database import models
from graphql_schema.sqlalchemy_to_strawberry_type import strawberry_sqlalchemy_type, strawberry_sqlalchemy_input
@strawberry_sqlalchemy_type(models.Photo)
class Photo:
pass
def get_base_query(user_id: int):
return (
select(models.Photo)
.filter(models.Photo.created_by_id == user_id)
.order_by(models.Photo.id.desc())
)
@strawberry.type
class PhotoQueries:
@strawberry.field
async def photos(root, info) -> List[Photo]:
query = get_base_query(info.context.user_id)
return (await info.context.db.scalars(query)).all()
@strawberry.type
class DeletePhotoMutation:
@strawberry.input
class DeletePhotoInput:
id: int
@strawberry_sqlalchemy_input(models.Photo, exclude_fields=[], all_optional=True)
class UpdatePhotoInput:
pass
@strawberry.mutation
async def update_photo(self, info, input: UpdatePhotoInput) -> Photo:
query = get_base_query(info.context.user_id)
photo = info.context.db.scalars(query.filter(models.Photo.id == input.id))
update_data = input.to_dict()
photo.update(**update_data)
return photo
@strawberry.mutation
async def delete_photo(self, info, input: DeletePhotoInput) -> Photo:
pass
+2 -1
View File
@@ -1,10 +1,11 @@
from strawberry.tools import merge_types
from graphql_schema.entities.aircraft import CreateAircraftMutation, EditAircraftMutation, DeleteAircraftMutation
from graphql_schema.entities.flight import CreateFlightMutation
from graphql_schema.entities.flight import CreateFlightMutation, EditFlightMutation
Mutation = merge_types("Mutation", (
CreateAircraftMutation,
EditAircraftMutation,
DeleteAircraftMutation,
EditFlightMutation,
CreateFlightMutation,
))
@@ -18,7 +18,8 @@ def get_annotations_for_scalars(model: BaseModel, exclude_fields=None, force_opt
for name, column in get_columns_from_model(model, exclude_fields):
is_optional = column.nullable or force_optional
try:
annotations_[name] = column.type.python_type if not is_optional else typing.Optional[column.type.python_type]
type_ = typing.Optional[column.type.python_type] if is_optional else column.type.python_type
annotations_[name] = type_
except NotImplementedError as e:
print(f"Neimplementovano: {e}, {name=}")
@@ -50,15 +51,29 @@ def strawberry_sqlalchemy_input(
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)}
return {name: getattr(self, name) for name, _ in get_columns_from_model(model, ignored_fields) if getattr(self, name) is not None}
def wrapper(cls):
cls.__annotations__.update(get_annotations_for_scalars(
annotations = get_annotations_for_scalars(
model,
exclude_fields=ignored_fields,
force_optional=all_optional
))
)
cls.__annotations__.update(annotations)
cls.to_dict = to_dict
return strawberry.input(cls)
for col, col_type in annotations.items():
try:
print("AAAAAAAAAA", col_type)
if col_type._name == 'Optional': # noqa
setattr(cls, col, None)
print(" nastavuji")
except AttributeError:
pass
input_cls = strawberry.input(cls)
return input_cls
return wrapper
+1 -1
View File
@@ -53,7 +53,7 @@ class App:
if APP_DEBUG:
@self.api_router.get("/graphql/autologin")
async def autologin():
access_token = self.access_security.create_access_token(subject={"id": 8, "name": "Franta Vomacka"})
access_token = self.access_security.create_access_token(subject={"id": 18, "name": "Franta Vomacka"})
response = RedirectResponse(url="/graphql")
self.access_security.set_access_cookie(response, access_token)
+5 -2
View File
@@ -9,7 +9,7 @@ def check_directories(path: str):
os.makedirs(path)
async def handle_img_upload(file: Upload, path: str):
async def handle_file_upload(file: Upload, path: str):
check_directories(path)
filename = f"{uuid.uuid4()}-{file.filename}"
@@ -19,5 +19,8 @@ async def handle_img_upload(file: Upload, path: str):
image.write(content)
image.close()
return filename
def delete_file(path: str, silent: bool = False):
os.remove(path)
os.remove(path)