mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-07-31 14:34:42 -04:00
refactor(backend): ♻️ Refactor to make SessionLocal a globally accessible object
This commit is contained in:
parent
a1aad078da
commit
234db39cc7
1
mealie/db/data_access_layer/__init__.py
Normal file
1
mealie/db/data_access_layer/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
from .db_access import DatabaseAccessLayer
|
@ -1,7 +1,7 @@
|
|||||||
from typing import Union
|
from typing import Callable, Union
|
||||||
|
|
||||||
from mealie.core.root_logger import get_logger
|
from mealie.core.root_logger import get_logger
|
||||||
from mealie.db.models.model_base import SqlAlchemyBase
|
from mealie.db.models._model_base import SqlAlchemyBase
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from sqlalchemy import func
|
from sqlalchemy import func
|
||||||
from sqlalchemy.orm import load_only
|
from sqlalchemy.orm import load_only
|
||||||
@ -10,16 +10,25 @@ from sqlalchemy.orm.session import Session
|
|||||||
logger = get_logger()
|
logger = get_logger()
|
||||||
|
|
||||||
|
|
||||||
class BaseDocument:
|
class BaseAccessModel:
|
||||||
def __init__(self) -> None:
|
def __init__(self, primary_key, sql_model, schema) -> None:
|
||||||
self.primary_key: str
|
self.primary_key: str = primary_key
|
||||||
self.store: str
|
self.sql_model: SqlAlchemyBase = sql_model
|
||||||
self.sql_model: SqlAlchemyBase
|
self.schema: BaseModel = schema
|
||||||
self.schema: BaseModel
|
|
||||||
self.observers: list = None
|
self.observers: list = []
|
||||||
|
|
||||||
|
def subscribe(self, func: Callable) -> None:
|
||||||
|
self.observers.append(func)
|
||||||
|
|
||||||
|
# TODO: Run Observer in Async Background Task
|
||||||
|
def update_observers(self) -> None:
|
||||||
|
if self.observers:
|
||||||
|
for observer in self.observers:
|
||||||
|
observer()
|
||||||
|
|
||||||
def get_all(
|
def get_all(
|
||||||
self, session: Session, limit: int = None, order_by: str = None, start=0, end=9999, override_schema=None
|
self, session: Session, limit: int = None, order_by: str = None, start=0, override_schema=None
|
||||||
) -> list[dict]:
|
) -> list[dict]:
|
||||||
eff_schema = override_schema or self.schema
|
eff_schema = override_schema or self.schema
|
||||||
|
|
||||||
@ -130,7 +139,7 @@ class BaseDocument:
|
|||||||
session.add(new_document)
|
session.add(new_document)
|
||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
if hasattr(self, "update_observers"):
|
if self.observers:
|
||||||
self.update_observers()
|
self.update_observers()
|
||||||
|
|
||||||
return self.schema.from_orm(new_document)
|
return self.schema.from_orm(new_document)
|
||||||
@ -150,7 +159,7 @@ class BaseDocument:
|
|||||||
entry = self._query_one(session=session, match_value=match_value)
|
entry = self._query_one(session=session, match_value=match_value)
|
||||||
entry.update(session=session, **new_data)
|
entry.update(session=session, **new_data)
|
||||||
|
|
||||||
if hasattr(self, "update_observers"):
|
if self.observers:
|
||||||
self.update_observers()
|
self.update_observers()
|
||||||
|
|
||||||
session.commit()
|
session.commit()
|
||||||
@ -176,7 +185,7 @@ class BaseDocument:
|
|||||||
session.delete(result)
|
session.delete(result)
|
||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
if hasattr(self, "update_observers"):
|
if self.observers:
|
||||||
self.update_observers()
|
self.update_observers()
|
||||||
|
|
||||||
return results_as_model
|
return results_as_model
|
||||||
@ -185,7 +194,7 @@ class BaseDocument:
|
|||||||
session.query(self.sql_model).delete()
|
session.query(self.sql_model).delete()
|
||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
if hasattr(self, "update_observers"):
|
if self.observers:
|
||||||
self.update_observers()
|
self.update_observers()
|
||||||
|
|
||||||
def count_all(self, session: Session, match_key=None, match_value=None) -> int:
|
def count_all(self, session: Session, match_key=None, match_value=None) -> int:
|
86
mealie/db/data_access_layer/db_access.py
Normal file
86
mealie/db/data_access_layer/db_access.py
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
from logging import getLogger
|
||||||
|
|
||||||
|
from mealie.db.data_access_layer.group_access_model import GroupDataAccessModel
|
||||||
|
from mealie.db.models.event import Event, EventNotification
|
||||||
|
from mealie.db.models.group import Group
|
||||||
|
from mealie.db.models.mealplan import MealPlan
|
||||||
|
from mealie.db.models.recipe.comment import RecipeComment
|
||||||
|
from mealie.db.models.recipe.ingredient import IngredientFoodModel, IngredientUnitModel
|
||||||
|
from mealie.db.models.recipe.recipe import Category, RecipeModel, Tag
|
||||||
|
from mealie.db.models.settings import CustomPage, SiteSettings
|
||||||
|
from mealie.db.models.shopping_list import ShoppingList
|
||||||
|
from mealie.db.models.sign_up import SignUp
|
||||||
|
from mealie.db.models.theme import SiteThemeModel
|
||||||
|
from mealie.db.models.users import LongLiveToken, User
|
||||||
|
from mealie.schema.admin import CustomPageOut
|
||||||
|
from mealie.schema.admin import SiteSettings as SiteSettingsSchema
|
||||||
|
from mealie.schema.admin import SiteTheme
|
||||||
|
from mealie.schema.events import Event as EventSchema
|
||||||
|
from mealie.schema.events import EventNotificationIn
|
||||||
|
from mealie.schema.meal_plan import MealPlanOut, ShoppingListOut
|
||||||
|
from mealie.schema.recipe import (
|
||||||
|
CommentOut,
|
||||||
|
IngredientFood,
|
||||||
|
IngredientUnit,
|
||||||
|
Recipe,
|
||||||
|
RecipeCategoryResponse,
|
||||||
|
RecipeTagResponse,
|
||||||
|
)
|
||||||
|
from mealie.schema.user import GroupInDB, LongLiveTokenInDB, SignUpOut, UserInDB
|
||||||
|
from sqlalchemy.orm.session import Session
|
||||||
|
|
||||||
|
from ._base_access_model import BaseAccessModel
|
||||||
|
from .recipe_access_model import RecipeDataAccessModel
|
||||||
|
from .user_access_model import UserDataAccessModel
|
||||||
|
|
||||||
|
logger = getLogger()
|
||||||
|
|
||||||
|
|
||||||
|
DEFAULT_PK = "id"
|
||||||
|
|
||||||
|
|
||||||
|
class CategoryDataAccessModel(BaseAccessModel):
|
||||||
|
def get_empty(self, session: Session):
|
||||||
|
self.schema
|
||||||
|
return session.query(Category).filter(~Category.recipes.any()).all()
|
||||||
|
|
||||||
|
|
||||||
|
class TagsDataAccessModel(BaseAccessModel):
|
||||||
|
def get_empty(self, session: Session):
|
||||||
|
return session.query(Tag).filter(~Tag.recipes.any()).all()
|
||||||
|
|
||||||
|
|
||||||
|
class DatabaseAccessLayer:
|
||||||
|
"""
|
||||||
|
`DatabaseAccessLayer` class is the data access layer for all database actions within
|
||||||
|
Mealie. Database uses composition from classes derived from BaseAccessModel. These
|
||||||
|
can be substantiated from the BaseAccessModel class or through inheritance when
|
||||||
|
additional methods are required.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
|
||||||
|
# Recipes
|
||||||
|
self.recipes = RecipeDataAccessModel("slug", RecipeModel, Recipe)
|
||||||
|
self.ingredient_foods = BaseAccessModel(DEFAULT_PK, IngredientFoodModel, IngredientFood)
|
||||||
|
self.ingredient_units = BaseAccessModel(DEFAULT_PK, IngredientUnitModel, IngredientUnit)
|
||||||
|
self.comments = BaseAccessModel(DEFAULT_PK, RecipeComment, CommentOut)
|
||||||
|
|
||||||
|
# Tags and Categories
|
||||||
|
self.categories = CategoryDataAccessModel("slug", Category, RecipeCategoryResponse)
|
||||||
|
self.tags = TagsDataAccessModel("slug", Tag, RecipeTagResponse)
|
||||||
|
|
||||||
|
# Site
|
||||||
|
self.settings = BaseAccessModel(DEFAULT_PK, SiteSettings, SiteSettingsSchema)
|
||||||
|
self.themes = BaseAccessModel(DEFAULT_PK, SiteThemeModel, SiteTheme)
|
||||||
|
self.sign_ups = BaseAccessModel("token", SignUp, SignUpOut)
|
||||||
|
self.custom_pages = BaseAccessModel(DEFAULT_PK, CustomPage, CustomPageOut)
|
||||||
|
self.event_notifications = BaseAccessModel(DEFAULT_PK, EventNotification, EventNotificationIn)
|
||||||
|
self.events = BaseAccessModel(DEFAULT_PK, Event, EventSchema)
|
||||||
|
|
||||||
|
# Users / Groups
|
||||||
|
self.users = UserDataAccessModel(DEFAULT_PK, User, UserInDB)
|
||||||
|
self.api_tokens = BaseAccessModel(DEFAULT_PK, LongLiveToken, LongLiveTokenInDB)
|
||||||
|
self.groups = GroupDataAccessModel(DEFAULT_PK, Group, GroupInDB)
|
||||||
|
self.meals = BaseAccessModel("uid", MealPlan, MealPlanOut)
|
||||||
|
self.shopping_lists = BaseAccessModel(DEFAULT_PK, ShoppingList, ShoppingListOut)
|
22
mealie/db/data_access_layer/group_access_model.py
Normal file
22
mealie/db/data_access_layer/group_access_model.py
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
from mealie.schema.meal_plan.meal import MealPlanOut
|
||||||
|
from mealie.schema.user.user import GroupInDB
|
||||||
|
from sqlalchemy.orm.session import Session
|
||||||
|
|
||||||
|
from ._base_access_model import BaseAccessModel
|
||||||
|
|
||||||
|
|
||||||
|
class GroupDataAccessModel(BaseAccessModel):
|
||||||
|
def get_meals(self, session: Session, match_value: str, match_key: str = "name") -> list[MealPlanOut]:
|
||||||
|
"""A Helper function to get the group from the database and return a sorted list of
|
||||||
|
|
||||||
|
Args:
|
||||||
|
session (Session): SqlAlchemy Session
|
||||||
|
match_value (str): Match Value
|
||||||
|
match_key (str, optional): Match Key. Defaults to "name".
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list[MealPlanOut]: [description]
|
||||||
|
"""
|
||||||
|
group: GroupInDB = session.query(self.sql_model).filter_by(**{match_key: match_value}).one_or_none()
|
||||||
|
|
||||||
|
return group.mealplans
|
57
mealie/db/data_access_layer/recipe_access_model.py
Normal file
57
mealie/db/data_access_layer/recipe_access_model.py
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
from random import randint
|
||||||
|
|
||||||
|
from mealie.db.models.recipe.recipe import RecipeModel
|
||||||
|
from mealie.db.models.recipe.settings import RecipeSettings
|
||||||
|
from sqlalchemy.orm.session import Session
|
||||||
|
|
||||||
|
from ._base_access_model import BaseAccessModel
|
||||||
|
|
||||||
|
|
||||||
|
class RecipeDataAccessModel(BaseAccessModel):
|
||||||
|
def get_all_public(self, session: Session, limit: int = None, order_by: str = None, start=0, override_schema=None):
|
||||||
|
eff_schema = override_schema or self.schema
|
||||||
|
|
||||||
|
if order_by:
|
||||||
|
order_attr = getattr(self.sql_model, str(order_by))
|
||||||
|
|
||||||
|
return [
|
||||||
|
eff_schema.from_orm(x)
|
||||||
|
for x in session.query(self.sql_model)
|
||||||
|
.join(RecipeSettings)
|
||||||
|
.filter(RecipeSettings.public == True) # noqa: 711
|
||||||
|
.order_by(order_attr.desc())
|
||||||
|
.offset(start)
|
||||||
|
.limit(limit)
|
||||||
|
.all()
|
||||||
|
]
|
||||||
|
|
||||||
|
return [
|
||||||
|
eff_schema.from_orm(x)
|
||||||
|
for x in session.query(self.sql_model)
|
||||||
|
.join(RecipeSettings)
|
||||||
|
.filter(RecipeSettings.public == True) # noqa: 711
|
||||||
|
.offset(start)
|
||||||
|
.limit(limit)
|
||||||
|
.all()
|
||||||
|
]
|
||||||
|
|
||||||
|
def update_image(self, session: Session, slug: str, _: str = None) -> str:
|
||||||
|
entry: RecipeModel = self._query_one(session, match_value=slug)
|
||||||
|
entry.image = randint(0, 255)
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
return entry.image
|
||||||
|
|
||||||
|
def count_uncategorized(self, session: Session, count=True, override_schema=None) -> int:
|
||||||
|
return self._count_attribute(
|
||||||
|
session,
|
||||||
|
attribute_name=RecipeModel.recipe_category,
|
||||||
|
attr_match=None,
|
||||||
|
count=count,
|
||||||
|
override_schema=override_schema,
|
||||||
|
)
|
||||||
|
|
||||||
|
def count_untagged(self, session: Session, count=True, override_schema=None) -> int:
|
||||||
|
return self._count_attribute(
|
||||||
|
session, attribute_name=RecipeModel.tags, attr_match=None, count=count, override_schema=override_schema
|
||||||
|
)
|
10
mealie/db/data_access_layer/user_access_model.py
Normal file
10
mealie/db/data_access_layer/user_access_model.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
from ._base_access_model import BaseAccessModel
|
||||||
|
|
||||||
|
|
||||||
|
class UserDataAccessModel(BaseAccessModel):
|
||||||
|
def update_password(self, session, id, password: str):
|
||||||
|
entry = self._query_one(session=session, match_value=id)
|
||||||
|
entry.update_password(password)
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
return self.schema.from_orm(entry)
|
@ -1,4 +1,4 @@
|
|||||||
from mealie.schema.recipe.recipe import IngredientUnit
|
from mealie.schema.recipe.units_and_foods import CreateIngredientUnit
|
||||||
from sqlalchemy.orm.session import Session
|
from sqlalchemy.orm.session import Session
|
||||||
|
|
||||||
from ..data_access_layer import DatabaseAccessLayer
|
from ..data_access_layer import DatabaseAccessLayer
|
||||||
@ -7,21 +7,21 @@ from ..data_access_layer import DatabaseAccessLayer
|
|||||||
def get_default_units():
|
def get_default_units():
|
||||||
return [
|
return [
|
||||||
# Volume
|
# Volume
|
||||||
IngredientUnit(name="teaspoon", abbreviation="tsp"),
|
CreateIngredientUnit(name="teaspoon", abbreviation="tsp"),
|
||||||
IngredientUnit(name="tablespoon", abbreviation="tbsp"),
|
CreateIngredientUnit(name="tablespoon", abbreviation="tbsp"),
|
||||||
IngredientUnit(name="fluid ounce", abbreviation="fl oz"),
|
CreateIngredientUnit(name="fluid ounce", abbreviation="fl oz"),
|
||||||
IngredientUnit(name="cup", abbreviation="cup"),
|
CreateIngredientUnit(name="cup", abbreviation="cup"),
|
||||||
IngredientUnit(name="pint", abbreviation="pt"),
|
CreateIngredientUnit(name="pint", abbreviation="pt"),
|
||||||
IngredientUnit(name="quart", abbreviation="qt"),
|
CreateIngredientUnit(name="quart", abbreviation="qt"),
|
||||||
IngredientUnit(name="gallon", abbreviation="gal"),
|
CreateIngredientUnit(name="gallon", abbreviation="gal"),
|
||||||
IngredientUnit(name="milliliter", abbreviation="ml"),
|
CreateIngredientUnit(name="milliliter", abbreviation="ml"),
|
||||||
IngredientUnit(name="liter", abbreviation="l"),
|
CreateIngredientUnit(name="liter", abbreviation="l"),
|
||||||
# Mass Weight
|
# Mass Weight
|
||||||
IngredientUnit(name="pound", abbreviation="lb"),
|
CreateIngredientUnit(name="pound", abbreviation="lb"),
|
||||||
IngredientUnit(name="ounce", abbreviation="oz"),
|
CreateIngredientUnit(name="ounce", abbreviation="oz"),
|
||||||
IngredientUnit(name="gram", abbreviation="g"),
|
CreateIngredientUnit(name="gram", abbreviation="g"),
|
||||||
IngredientUnit(name="kilogram", abbreviation="kg"),
|
CreateIngredientUnit(name="kilogram", abbreviation="kg"),
|
||||||
IngredientUnit(name="milligram", abbreviation="mg"),
|
CreateIngredientUnit(name="milligram", abbreviation="mg"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,268 +1,3 @@
|
|||||||
from logging import getLogger
|
from .data_access_layer import DatabaseAccessLayer
|
||||||
from random import randint
|
|
||||||
from typing import Callable
|
|
||||||
|
|
||||||
from mealie.db.db_base import BaseDocument
|
db = DatabaseAccessLayer()
|
||||||
from mealie.db.models.event import Event, EventNotification
|
|
||||||
from mealie.db.models.group import Group
|
|
||||||
from mealie.db.models.mealplan import MealPlan
|
|
||||||
from mealie.db.models.recipe.comment import RecipeComment
|
|
||||||
from mealie.db.models.recipe.ingredient import IngredientFood, IngredientUnit
|
|
||||||
from mealie.db.models.recipe.recipe import Category, RecipeModel, Tag
|
|
||||||
from mealie.db.models.recipe.settings import RecipeSettings
|
|
||||||
from mealie.db.models.settings import CustomPage, SiteSettings
|
|
||||||
from mealie.db.models.shopping_list import ShoppingList
|
|
||||||
from mealie.db.models.sign_up import SignUp
|
|
||||||
from mealie.db.models.theme import SiteThemeModel
|
|
||||||
from mealie.db.models.users import LongLiveToken, User
|
|
||||||
from mealie.schema.admin import CustomPageOut
|
|
||||||
from mealie.schema.admin import SiteSettings as SiteSettingsSchema
|
|
||||||
from mealie.schema.admin import SiteTheme
|
|
||||||
from mealie.schema.events import Event as EventSchema
|
|
||||||
from mealie.schema.events import EventNotificationIn
|
|
||||||
from mealie.schema.meal_plan import MealPlanOut, ShoppingListOut
|
|
||||||
from mealie.schema.recipe import (
|
|
||||||
CommentOut,
|
|
||||||
Recipe,
|
|
||||||
RecipeCategoryResponse,
|
|
||||||
RecipeIngredientFood,
|
|
||||||
RecipeIngredientUnit,
|
|
||||||
RecipeTagResponse,
|
|
||||||
)
|
|
||||||
from mealie.schema.user import GroupInDB, LongLiveTokenInDB, SignUpOut, UserInDB
|
|
||||||
from sqlalchemy.orm.session import Session
|
|
||||||
|
|
||||||
logger = getLogger()
|
|
||||||
|
|
||||||
|
|
||||||
class _Recipes(BaseDocument):
|
|
||||||
def __init__(self) -> None:
|
|
||||||
self.primary_key = "slug"
|
|
||||||
self.sql_model: RecipeModel = RecipeModel
|
|
||||||
self.schema: Recipe = Recipe
|
|
||||||
|
|
||||||
self.observers = []
|
|
||||||
|
|
||||||
def get_all_public(self, session: Session, limit: int = None, order_by: str = None, start=0, override_schema=None):
|
|
||||||
eff_schema = override_schema or self.schema
|
|
||||||
|
|
||||||
if order_by:
|
|
||||||
order_attr = getattr(self.sql_model, str(order_by))
|
|
||||||
|
|
||||||
return [
|
|
||||||
eff_schema.from_orm(x)
|
|
||||||
for x in session.query(self.sql_model)
|
|
||||||
.join(RecipeSettings)
|
|
||||||
.filter(RecipeSettings.public == True) # noqa: 711
|
|
||||||
.order_by(order_attr.desc())
|
|
||||||
.offset(start)
|
|
||||||
.limit(limit)
|
|
||||||
.all()
|
|
||||||
]
|
|
||||||
|
|
||||||
return [
|
|
||||||
eff_schema.from_orm(x)
|
|
||||||
for x in session.query(self.sql_model)
|
|
||||||
.join(RecipeSettings)
|
|
||||||
.filter(RecipeSettings.public == True) # noqa: 711
|
|
||||||
.offset(start)
|
|
||||||
.limit(limit)
|
|
||||||
.all()
|
|
||||||
]
|
|
||||||
|
|
||||||
def update_image(self, session: Session, slug: str, _: str = None) -> str:
|
|
||||||
entry: RecipeModel = self._query_one(session, match_value=slug)
|
|
||||||
entry.image = randint(0, 255)
|
|
||||||
session.commit()
|
|
||||||
|
|
||||||
return entry.image
|
|
||||||
|
|
||||||
def count_uncategorized(self, session: Session, count=True, override_schema=None) -> int:
|
|
||||||
return self._count_attribute(
|
|
||||||
session,
|
|
||||||
attribute_name=RecipeModel.recipe_category,
|
|
||||||
attr_match=None,
|
|
||||||
count=count,
|
|
||||||
override_schema=override_schema,
|
|
||||||
)
|
|
||||||
|
|
||||||
def count_untagged(self, session: Session, count=True, override_schema=None) -> int:
|
|
||||||
return self._count_attribute(
|
|
||||||
session, attribute_name=RecipeModel.tags, attr_match=None, count=count, override_schema=override_schema
|
|
||||||
)
|
|
||||||
|
|
||||||
def subscribe(self, func: Callable) -> None:
|
|
||||||
self.observers.append(func)
|
|
||||||
|
|
||||||
def update_observers(self) -> None:
|
|
||||||
for observer in self.observers:
|
|
||||||
observer()
|
|
||||||
|
|
||||||
|
|
||||||
class _IngredientFoods(BaseDocument):
|
|
||||||
def __init__(self) -> None:
|
|
||||||
self.primary_key = "id"
|
|
||||||
self.sql_model = IngredientFood
|
|
||||||
self.schema = RecipeIngredientFood
|
|
||||||
|
|
||||||
|
|
||||||
class _IngredientUnits(BaseDocument):
|
|
||||||
def __init__(self) -> None:
|
|
||||||
self.primary_key = "id"
|
|
||||||
self.sql_model = IngredientUnit
|
|
||||||
self.schema = RecipeIngredientUnit
|
|
||||||
|
|
||||||
|
|
||||||
class _Categories(BaseDocument):
|
|
||||||
def __init__(self) -> None:
|
|
||||||
self.primary_key = "slug"
|
|
||||||
self.sql_model = Category
|
|
||||||
self.schema = RecipeCategoryResponse
|
|
||||||
|
|
||||||
def get_empty(self, session: Session):
|
|
||||||
return session.query(Category).filter(~Category.recipes.any()).all()
|
|
||||||
|
|
||||||
|
|
||||||
class _Tags(BaseDocument):
|
|
||||||
def __init__(self) -> None:
|
|
||||||
self.primary_key = "slug"
|
|
||||||
self.sql_model = Tag
|
|
||||||
self.schema = RecipeTagResponse
|
|
||||||
|
|
||||||
def get_empty(self, session: Session):
|
|
||||||
return session.query(Tag).filter(~Tag.recipes.any()).all()
|
|
||||||
|
|
||||||
|
|
||||||
class _Meals(BaseDocument):
|
|
||||||
def __init__(self) -> None:
|
|
||||||
self.primary_key = "uid"
|
|
||||||
self.sql_model = MealPlan
|
|
||||||
self.schema = MealPlanOut
|
|
||||||
|
|
||||||
|
|
||||||
class _Settings(BaseDocument):
|
|
||||||
def __init__(self) -> None:
|
|
||||||
self.primary_key = "id"
|
|
||||||
self.sql_model = SiteSettings
|
|
||||||
self.schema = SiteSettingsSchema
|
|
||||||
|
|
||||||
|
|
||||||
class _Themes(BaseDocument):
|
|
||||||
def __init__(self) -> None:
|
|
||||||
self.primary_key = "id"
|
|
||||||
self.sql_model = SiteThemeModel
|
|
||||||
self.schema = SiteTheme
|
|
||||||
|
|
||||||
|
|
||||||
class _Users(BaseDocument):
|
|
||||||
def __init__(self) -> None:
|
|
||||||
self.primary_key = "id"
|
|
||||||
self.sql_model = User
|
|
||||||
self.schema = UserInDB
|
|
||||||
|
|
||||||
def update_password(self, session, id, password: str):
|
|
||||||
entry = self._query_one(session=session, match_value=id)
|
|
||||||
entry.update_password(password)
|
|
||||||
session.commit()
|
|
||||||
|
|
||||||
return self.schema.from_orm(entry)
|
|
||||||
|
|
||||||
|
|
||||||
class _Comments(BaseDocument):
|
|
||||||
def __init__(self) -> None:
|
|
||||||
self.primary_key = "id"
|
|
||||||
self.sql_model = RecipeComment
|
|
||||||
self.schema = CommentOut
|
|
||||||
|
|
||||||
|
|
||||||
class _LongLiveToken(BaseDocument):
|
|
||||||
def __init__(self) -> None:
|
|
||||||
self.primary_key = "id"
|
|
||||||
self.sql_model = LongLiveToken
|
|
||||||
self.schema = LongLiveTokenInDB
|
|
||||||
|
|
||||||
|
|
||||||
class _Groups(BaseDocument):
|
|
||||||
def __init__(self) -> None:
|
|
||||||
self.primary_key = "id"
|
|
||||||
self.sql_model = Group
|
|
||||||
self.schema = GroupInDB
|
|
||||||
|
|
||||||
def get_meals(self, session: Session, match_value: str, match_key: str = "name") -> list[MealPlanOut]:
|
|
||||||
"""A Helper function to get the group from the database and return a sorted list of
|
|
||||||
|
|
||||||
Args:
|
|
||||||
session (Session): SqlAlchemy Session
|
|
||||||
match_value (str): Match Value
|
|
||||||
match_key (str, optional): Match Key. Defaults to "name".
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
list[MealPlanOut]: [description]
|
|
||||||
"""
|
|
||||||
group: GroupInDB = session.query(self.sql_model).filter_by(**{match_key: match_value}).one_or_none()
|
|
||||||
|
|
||||||
return group.mealplans
|
|
||||||
|
|
||||||
|
|
||||||
class _ShoppingList(BaseDocument):
|
|
||||||
def __init__(self) -> None:
|
|
||||||
self.primary_key = "id"
|
|
||||||
self.sql_model = ShoppingList
|
|
||||||
self.schema = ShoppingListOut
|
|
||||||
|
|
||||||
|
|
||||||
class _SignUps(BaseDocument):
|
|
||||||
def __init__(self) -> None:
|
|
||||||
self.primary_key = "token"
|
|
||||||
self.sql_model = SignUp
|
|
||||||
self.schema = SignUpOut
|
|
||||||
|
|
||||||
|
|
||||||
class _CustomPages(BaseDocument):
|
|
||||||
def __init__(self) -> None:
|
|
||||||
self.primary_key = "id"
|
|
||||||
self.sql_model = CustomPage
|
|
||||||
self.schema = CustomPageOut
|
|
||||||
|
|
||||||
|
|
||||||
class _Events(BaseDocument):
|
|
||||||
def __init__(self) -> None:
|
|
||||||
self.primary_key = "id"
|
|
||||||
self.sql_model = Event
|
|
||||||
self.schema = EventSchema
|
|
||||||
|
|
||||||
|
|
||||||
class _EventNotification(BaseDocument):
|
|
||||||
def __init__(self) -> None:
|
|
||||||
self.primary_key = "id"
|
|
||||||
self.sql_model = EventNotification
|
|
||||||
self.schema = EventNotificationIn
|
|
||||||
|
|
||||||
|
|
||||||
class Database:
|
|
||||||
def __init__(self) -> None:
|
|
||||||
# Recipes
|
|
||||||
self.recipes = _Recipes()
|
|
||||||
self.ingredient_foods = _IngredientUnits()
|
|
||||||
self.ingredient_units = _IngredientFoods()
|
|
||||||
self.categories = _Categories()
|
|
||||||
self.tags = _Tags()
|
|
||||||
self.comments = _Comments()
|
|
||||||
|
|
||||||
# Site
|
|
||||||
self.settings = _Settings()
|
|
||||||
self.themes = _Themes()
|
|
||||||
self.sign_ups = _SignUps()
|
|
||||||
self.custom_pages = _CustomPages()
|
|
||||||
self.event_notifications = _EventNotification()
|
|
||||||
self.events = _Events()
|
|
||||||
|
|
||||||
# Users / Groups
|
|
||||||
self.users = _Users()
|
|
||||||
self.api_tokens = _LongLiveToken()
|
|
||||||
self.groups = _Groups()
|
|
||||||
self.meals = _Meals()
|
|
||||||
self.shopping_lists = _ShoppingList()
|
|
||||||
|
|
||||||
|
|
||||||
db = Database()
|
|
||||||
|
@ -1,8 +1,22 @@
|
|||||||
|
import sqlalchemy as sa
|
||||||
from mealie.core.config import settings
|
from mealie.core.config import settings
|
||||||
from mealie.db.models.db_session import sql_global_init
|
from sqlalchemy.orm import sessionmaker
|
||||||
from sqlalchemy.orm.session import Session
|
from sqlalchemy.orm.session import Session
|
||||||
|
|
||||||
SessionLocal = sql_global_init(settings.DB_URL)
|
|
||||||
|
def sql_global_init(db_url: str):
|
||||||
|
connect_args = {}
|
||||||
|
if "sqlite" in db_url:
|
||||||
|
connect_args["check_same_thread"] = False
|
||||||
|
|
||||||
|
engine = sa.create_engine(db_url, echo=False, connect_args=connect_args)
|
||||||
|
|
||||||
|
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||||
|
|
||||||
|
return SessionLocal, engine
|
||||||
|
|
||||||
|
|
||||||
|
SessionLocal, engine = sql_global_init(settings.DB_URL)
|
||||||
|
|
||||||
|
|
||||||
def create_session() -> Session:
|
def create_session() -> Session:
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
from mealie.core import root_logger
|
from mealie.core import root_logger
|
||||||
from mealie.core.config import settings
|
from mealie.core.config import settings
|
||||||
from mealie.core.security import get_password_hash
|
from mealie.core.security import get_password_hash
|
||||||
|
from mealie.db.data_initialization.init_units_foods import default_recipe_unit_init
|
||||||
from mealie.db.database import db
|
from mealie.db.database import db
|
||||||
from mealie.db.db_setup import create_session
|
from mealie.db.db_setup import create_session, engine
|
||||||
|
from mealie.db.models._model_base import SqlAlchemyBase
|
||||||
from mealie.schema.admin import SiteSettings, SiteTheme
|
from mealie.schema.admin import SiteSettings, SiteTheme
|
||||||
from mealie.services.events import create_general_event
|
from mealie.services.events import create_general_event
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
@ -10,16 +12,26 @@ from sqlalchemy.orm import Session
|
|||||||
logger = root_logger.get_logger("init_db")
|
logger = root_logger.get_logger("init_db")
|
||||||
|
|
||||||
|
|
||||||
def init_db(db: Session = None) -> None:
|
def create_all_models():
|
||||||
if not db:
|
import mealie.db.models._all_models # noqa: F401
|
||||||
db = create_session()
|
|
||||||
|
|
||||||
default_group_init(db)
|
SqlAlchemyBase.metadata.create_all(engine)
|
||||||
default_settings_init(db)
|
|
||||||
default_theme_init(db)
|
|
||||||
default_user_init(db)
|
|
||||||
|
|
||||||
db.close()
|
|
||||||
|
def init_db(session: Session = None) -> None:
|
||||||
|
create_all_models()
|
||||||
|
|
||||||
|
if not session:
|
||||||
|
session = create_session()
|
||||||
|
|
||||||
|
default_group_init(session)
|
||||||
|
default_settings_init(session)
|
||||||
|
default_theme_init(session)
|
||||||
|
default_user_init(session)
|
||||||
|
|
||||||
|
default_recipe_unit_init(db, session)
|
||||||
|
|
||||||
|
session.close()
|
||||||
|
|
||||||
|
|
||||||
def default_theme_init(session: Session):
|
def default_theme_init(session: Session):
|
||||||
@ -67,8 +79,12 @@ def default_user_init(session: Session):
|
|||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
session = create_session()
|
try:
|
||||||
init_user = db.users.get(session, "1", "id")
|
session = create_session()
|
||||||
|
init_user = db.users.get(session, "1", "id")
|
||||||
|
except Exception:
|
||||||
|
init_db()
|
||||||
|
return
|
||||||
if init_user:
|
if init_user:
|
||||||
logger.info("Database Exists")
|
logger.info("Database Exists")
|
||||||
else:
|
else:
|
||||||
|
52
mealie/db/models/_model_base.py
Normal file
52
mealie/db/models/_model_base.py
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import uuid
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from mealie.db.db_setup import SessionLocal
|
||||||
|
from sqlalchemy import Column, DateTime, Integer
|
||||||
|
from sqlalchemy.ext.declarative import as_declarative
|
||||||
|
from sqlalchemy.orm import declarative_base
|
||||||
|
|
||||||
|
|
||||||
|
def get_uuid_as_hex() -> str:
|
||||||
|
"""
|
||||||
|
Generate a UUID as a hex string.
|
||||||
|
:return: UUID as a hex string.
|
||||||
|
"""
|
||||||
|
return uuid.uuid4().hex
|
||||||
|
|
||||||
|
|
||||||
|
@as_declarative()
|
||||||
|
class Base:
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
created_at = Column(DateTime, default=datetime.now())
|
||||||
|
|
||||||
|
# @declared_attr
|
||||||
|
# def __tablename__(cls):
|
||||||
|
# return cls.__name__.lower()
|
||||||
|
|
||||||
|
|
||||||
|
class BaseMixins:
|
||||||
|
"""
|
||||||
|
`self.update` method which directly passing arugments to the `__init__`
|
||||||
|
`cls.get_ref` method which will return the object from the database or none. Useful for many-to-many relationships.
|
||||||
|
"""
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
get_attr = "id"
|
||||||
|
|
||||||
|
def update(self, *args, **kwarg):
|
||||||
|
self.__init__(*args, **kwarg)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_ref(cls, match_value: str, match_attr: str = None):
|
||||||
|
match_attr = match_attr = cls.Config.get_attr
|
||||||
|
|
||||||
|
if match_value is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
with SessionLocal() as session:
|
||||||
|
eff_ref = getattr(cls, match_attr)
|
||||||
|
return session.query(cls).filter(eff_ref == match_value).one_or_none()
|
||||||
|
|
||||||
|
|
||||||
|
SqlAlchemyBase = declarative_base(cls=Base, constructor=None)
|
@ -1,19 +0,0 @@
|
|||||||
import sqlalchemy as sa
|
|
||||||
from mealie.db.models.model_base import SqlAlchemyBase
|
|
||||||
from sqlalchemy.orm import sessionmaker
|
|
||||||
|
|
||||||
|
|
||||||
def sql_global_init(db_url: str):
|
|
||||||
connect_args = {}
|
|
||||||
if "sqlite" in db_url:
|
|
||||||
connect_args["check_same_thread"] = False
|
|
||||||
|
|
||||||
engine = sa.create_engine(db_url, echo=False, connect_args=connect_args)
|
|
||||||
|
|
||||||
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
|
||||||
|
|
||||||
import mealie.db.models._all_models # noqa: F401
|
|
||||||
|
|
||||||
SqlAlchemyBase.metadata.create_all(engine)
|
|
||||||
|
|
||||||
return SessionLocal
|
|
@ -1,4 +1,4 @@
|
|||||||
from mealie.db.models.model_base import BaseMixins, SqlAlchemyBase
|
from mealie.db.models._model_base import BaseMixins, SqlAlchemyBase
|
||||||
from sqlalchemy import Boolean, Column, DateTime, Integer, String
|
from sqlalchemy import Boolean, Column, DateTime, Integer, String
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
import sqlalchemy.orm as orm
|
import sqlalchemy.orm as orm
|
||||||
from mealie.core.config import settings
|
from mealie.core.config import settings
|
||||||
from mealie.db.models.model_base import BaseMixins, SqlAlchemyBase
|
from mealie.db.models._model_base import BaseMixins, SqlAlchemyBase
|
||||||
from mealie.db.models.recipe.category import Category, group2categories
|
from mealie.db.models.recipe.category import Category, group2categories
|
||||||
from sqlalchemy.orm.session import Session
|
from sqlalchemy.orm.session import Session
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import sqlalchemy.orm as orm
|
import sqlalchemy.orm as orm
|
||||||
from mealie.db.models.group import Group
|
from mealie.db.models.group import Group
|
||||||
from mealie.db.models.model_base import BaseMixins, SqlAlchemyBase
|
from mealie.db.models._model_base import BaseMixins, SqlAlchemyBase
|
||||||
from mealie.db.models.recipe.recipe import RecipeModel
|
from mealie.db.models.recipe.recipe import RecipeModel
|
||||||
from mealie.db.models.shopping_list import ShoppingList
|
from mealie.db.models.shopping_list import ShoppingList
|
||||||
from sqlalchemy import Column, Date, ForeignKey, Integer, String
|
from sqlalchemy import Column, Date, ForeignKey, Integer, String
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
import sqlalchemy.ext.declarative as dec
|
|
||||||
from requests import Session
|
|
||||||
|
|
||||||
SqlAlchemyBase = dec.declarative_base()
|
|
||||||
|
|
||||||
|
|
||||||
class BaseMixins:
|
|
||||||
def update(self, *args, **kwarg):
|
|
||||||
self.__init__(*args, **kwarg)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_ref(cls_type, session: Session, match_value: str, match_attr: str = "id"):
|
|
||||||
eff_ref = getattr(cls_type, match_attr)
|
|
||||||
return session.query(cls_type).filter(eff_ref == match_value).one_or_none()
|
|
@ -1,5 +1,5 @@
|
|||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
from mealie.db.models.model_base import SqlAlchemyBase
|
from mealie.db.models._model_base import SqlAlchemyBase
|
||||||
|
|
||||||
|
|
||||||
class ApiExtras(SqlAlchemyBase):
|
class ApiExtras(SqlAlchemyBase):
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
from mealie.db.models.model_base import SqlAlchemyBase
|
from mealie.db.models._model_base import SqlAlchemyBase
|
||||||
|
|
||||||
|
|
||||||
class RecipeAsset(SqlAlchemyBase):
|
class RecipeAsset(SqlAlchemyBase):
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
import sqlalchemy.orm as orm
|
import sqlalchemy.orm as orm
|
||||||
from mealie.core import root_logger
|
from mealie.core import root_logger
|
||||||
from mealie.db.models.model_base import SqlAlchemyBase
|
from mealie.db.models._model_base import BaseMixins, SqlAlchemyBase
|
||||||
from slugify import slugify
|
from slugify import slugify
|
||||||
from sqlalchemy.orm import validates
|
from sqlalchemy.orm import validates
|
||||||
|
|
||||||
@ -36,29 +36,25 @@ custom_pages2categories = sa.Table(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class Category(SqlAlchemyBase):
|
class Category(SqlAlchemyBase, BaseMixins):
|
||||||
__tablename__ = "categories"
|
__tablename__ = "categories"
|
||||||
id = sa.Column(sa.Integer, primary_key=True)
|
id = sa.Column(sa.Integer, primary_key=True)
|
||||||
name = sa.Column(sa.String, index=True, nullable=False)
|
name = sa.Column(sa.String, index=True, nullable=False)
|
||||||
slug = sa.Column(sa.String, index=True, unique=True, nullable=False)
|
slug = sa.Column(sa.String, index=True, unique=True, nullable=False)
|
||||||
recipes = orm.relationship("RecipeModel", secondary=recipes2categories, back_populates="recipe_category")
|
recipes = orm.relationship("RecipeModel", secondary=recipes2categories, back_populates="recipe_category")
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
get_attr = "slug"
|
||||||
|
|
||||||
@validates("name")
|
@validates("name")
|
||||||
def validate_name(self, key, name):
|
def validate_name(self, key, name):
|
||||||
assert name != ""
|
assert name != ""
|
||||||
return name
|
return name
|
||||||
|
|
||||||
def __init__(self, name, session=None) -> None:
|
def __init__(self, name, **_) -> None:
|
||||||
self.name = name.strip()
|
self.name = name.strip()
|
||||||
self.slug = slugify(name)
|
self.slug = slugify(name)
|
||||||
|
|
||||||
def update(self, name, session=None) -> None:
|
|
||||||
self.__init__(name, session)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_ref(session, slug: str):
|
|
||||||
return session.query(Category).filter(Category.slug == slug).one()
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create_if_not_exist(session, name: str = None):
|
def create_if_not_exist(session, name: str = None):
|
||||||
test_slug = slugify(name)
|
test_slug = slugify(name)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
|
||||||
from mealie.db.models.model_base import BaseMixins, SqlAlchemyBase
|
from mealie.db.models._model_base import BaseMixins, SqlAlchemyBase
|
||||||
from mealie.db.models.recipe.recipe import RecipeModel
|
from mealie.db.models.recipe.recipe import RecipeModel
|
||||||
from mealie.db.models.users import User
|
from mealie.db.models.users import User
|
||||||
from sqlalchemy import Column, DateTime, ForeignKey, Integer, String, orm
|
from sqlalchemy import Column, DateTime, ForeignKey, Integer, String, orm
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from mealie.db.models.model_base import BaseMixins, SqlAlchemyBase
|
from mealie.db.models._model_base import BaseMixins, SqlAlchemyBase
|
||||||
from requests import Session
|
from requests import Session
|
||||||
from sqlalchemy import Column, ForeignKey, Integer, String, Table, orm
|
from sqlalchemy import Column, ForeignKey, Integer, String, Table, orm
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ class IngredientFoodModel(SqlAlchemyBase, BaseMixins):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class RecipeIngredient(SqlAlchemyBase):
|
class RecipeIngredient(SqlAlchemyBase, BaseMixins):
|
||||||
__tablename__ = "recipes_ingredients"
|
__tablename__ = "recipes_ingredients"
|
||||||
id = Column(Integer, primary_key=True)
|
id = Column(Integer, primary_key=True)
|
||||||
position = Column(Integer)
|
position = Column(Integer)
|
||||||
@ -63,6 +63,10 @@ class RecipeIngredient(SqlAlchemyBase):
|
|||||||
def __init__(self, title: str, note: str, unit: dict, food: dict, quantity: int, session: Session, **_) -> None:
|
def __init__(self, title: str, note: str, unit: dict, food: dict, quantity: int, session: Session, **_) -> None:
|
||||||
self.title = title
|
self.title = title
|
||||||
self.note = note
|
self.note = note
|
||||||
self.unit = IngredientUnitModel.get_ref_or_create(session, unit)
|
|
||||||
self.food = IngredientFoodModel.get_ref_or_create(session, food)
|
|
||||||
self.quantity = quantity
|
self.quantity = quantity
|
||||||
|
|
||||||
|
if unit:
|
||||||
|
self.unit = IngredientUnitModel.get_ref(unit.get("id"))
|
||||||
|
|
||||||
|
if food:
|
||||||
|
self.food = IngredientFoodModel.get_ref(unit.get("id"))
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from mealie.db.models.model_base import SqlAlchemyBase
|
from mealie.db.models._model_base import SqlAlchemyBase
|
||||||
from sqlalchemy import Column, ForeignKey, Integer, String
|
from sqlalchemy import Column, ForeignKey, Integer, String
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
from mealie.db.models.model_base import SqlAlchemyBase
|
from mealie.db.models._model_base import SqlAlchemyBase
|
||||||
|
|
||||||
|
|
||||||
class Note(SqlAlchemyBase):
|
class Note(SqlAlchemyBase):
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
from mealie.db.models.model_base import SqlAlchemyBase
|
from mealie.db.models._model_base import SqlAlchemyBase
|
||||||
|
|
||||||
|
|
||||||
class Nutrition(SqlAlchemyBase):
|
class Nutrition(SqlAlchemyBase):
|
||||||
|
@ -3,26 +3,24 @@ from datetime import date
|
|||||||
|
|
||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
import sqlalchemy.orm as orm
|
import sqlalchemy.orm as orm
|
||||||
from mealie.db.models.model_base import BaseMixins, SqlAlchemyBase
|
|
||||||
from mealie.db.models.recipe.api_extras import ApiExtras
|
|
||||||
from mealie.db.models.recipe.assets import RecipeAsset
|
|
||||||
from mealie.db.models.recipe.category import Category, recipes2categories
|
|
||||||
from mealie.db.models.recipe.ingredient import RecipeIngredient
|
|
||||||
from mealie.db.models.recipe.instruction import RecipeInstruction
|
|
||||||
from mealie.db.models.recipe.note import Note
|
|
||||||
from mealie.db.models.recipe.nutrition import Nutrition
|
|
||||||
from mealie.db.models.recipe.settings import RecipeSettings
|
|
||||||
from mealie.db.models.recipe.tag import Tag, recipes2tags
|
|
||||||
from mealie.db.models.recipe.tool import Tool
|
|
||||||
from sqlalchemy.ext.orderinglist import ordering_list
|
from sqlalchemy.ext.orderinglist import ordering_list
|
||||||
from sqlalchemy.orm import validates
|
from sqlalchemy.orm import validates
|
||||||
|
|
||||||
|
from .._model_base import BaseMixins, SqlAlchemyBase
|
||||||
|
from .api_extras import ApiExtras
|
||||||
|
from .assets import RecipeAsset
|
||||||
|
from .category import Category, recipes2categories
|
||||||
|
from .ingredient import RecipeIngredient
|
||||||
|
from .instruction import RecipeInstruction
|
||||||
|
from .note import Note
|
||||||
|
from .nutrition import Nutrition
|
||||||
|
from .settings import RecipeSettings
|
||||||
|
from .tag import Tag, recipes2tags
|
||||||
|
from .tool import Tool
|
||||||
|
|
||||||
|
|
||||||
class RecipeModel(SqlAlchemyBase, BaseMixins):
|
class RecipeModel(SqlAlchemyBase, BaseMixins):
|
||||||
__tablename__ = "recipes"
|
__tablename__ = "recipes"
|
||||||
# Database Specific
|
|
||||||
id = sa.Column(sa.Integer, primary_key=True)
|
|
||||||
|
|
||||||
# General Recipe Properties
|
# General Recipe Properties
|
||||||
name = sa.Column(sa.String, nullable=False)
|
name = sa.Column(sa.String, nullable=False)
|
||||||
description = sa.Column(sa.String)
|
description = sa.Column(sa.String)
|
||||||
@ -128,11 +126,11 @@ class RecipeModel(SqlAlchemyBase, BaseMixins):
|
|||||||
self.perform_time = perform_time
|
self.perform_time = perform_time
|
||||||
self.cook_time = cook_time
|
self.cook_time = cook_time
|
||||||
|
|
||||||
self.recipe_category = [Category.create_if_not_exist(session=session, name=cat) for cat in recipe_category]
|
self.recipe_category = [x for x in [Category.get_ref(cat) for cat in recipe_category] if x]
|
||||||
|
|
||||||
# Mealie Specific
|
# Mealie Specific
|
||||||
self.settings = RecipeSettings(**settings) if settings else RecipeSettings()
|
self.settings = RecipeSettings(**settings) if settings else RecipeSettings()
|
||||||
self.tags = [Tag.create_if_not_exist(session=session, name=tag) for tag in tags]
|
self.tags = [x for x in [Tag.get_ref(tag) for tag in tags] if x]
|
||||||
self.slug = slug
|
self.slug = slug
|
||||||
self.notes = [Note(**note) for note in notes]
|
self.notes = [Note(**note) for note in notes]
|
||||||
self.rating = rating
|
self.rating = rating
|
||||||
@ -142,7 +140,3 @@ class RecipeModel(SqlAlchemyBase, BaseMixins):
|
|||||||
# Time Stampes
|
# Time Stampes
|
||||||
self.date_added = date_added
|
self.date_added = date_added
|
||||||
self.date_updated = datetime.datetime.now()
|
self.date_updated = datetime.datetime.now()
|
||||||
|
|
||||||
def update(self, **_):
|
|
||||||
"""Updated a database entry by removing nested rows and rebuilds the row through the __init__ functions"""
|
|
||||||
self.__init__(**_)
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
from mealie.db.models.model_base import SqlAlchemyBase
|
from mealie.db.models._model_base import SqlAlchemyBase
|
||||||
|
|
||||||
|
|
||||||
class RecipeSettings(SqlAlchemyBase):
|
class RecipeSettings(SqlAlchemyBase):
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
import sqlalchemy.orm as orm
|
import sqlalchemy.orm as orm
|
||||||
from mealie.core import root_logger
|
from mealie.core import root_logger
|
||||||
from mealie.db.models.model_base import SqlAlchemyBase
|
from mealie.db.models._model_base import BaseMixins, SqlAlchemyBase
|
||||||
from slugify import slugify
|
from slugify import slugify
|
||||||
from sqlalchemy.orm import validates
|
from sqlalchemy.orm import validates
|
||||||
|
|
||||||
@ -15,13 +15,16 @@ recipes2tags = sa.Table(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class Tag(SqlAlchemyBase):
|
class Tag(SqlAlchemyBase, BaseMixins):
|
||||||
__tablename__ = "tags"
|
__tablename__ = "tags"
|
||||||
id = sa.Column(sa.Integer, primary_key=True)
|
id = sa.Column(sa.Integer, primary_key=True)
|
||||||
name = sa.Column(sa.String, index=True, nullable=False)
|
name = sa.Column(sa.String, index=True, nullable=False)
|
||||||
slug = sa.Column(sa.String, index=True, unique=True, nullable=False)
|
slug = sa.Column(sa.String, index=True, unique=True, nullable=False)
|
||||||
recipes = orm.relationship("RecipeModel", secondary=recipes2tags, back_populates="tags")
|
recipes = orm.relationship("RecipeModel", secondary=recipes2tags, back_populates="tags")
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
get_attr = "slug"
|
||||||
|
|
||||||
@validates("name")
|
@validates("name")
|
||||||
def validate_name(self, key, name):
|
def validate_name(self, key, name):
|
||||||
assert name != ""
|
assert name != ""
|
||||||
@ -31,9 +34,6 @@ class Tag(SqlAlchemyBase):
|
|||||||
self.name = name.strip()
|
self.name = name.strip()
|
||||||
self.slug = slugify(self.name)
|
self.slug = slugify(self.name)
|
||||||
|
|
||||||
def update(self, name, session=None) -> None:
|
|
||||||
self.__init__(name, session)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create_if_not_exist(session, name: str = None):
|
def create_if_not_exist(session, name: str = None):
|
||||||
test_slug = slugify(name)
|
test_slug = slugify(name)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
from mealie.db.models.model_base import SqlAlchemyBase
|
from mealie.db.models._model_base import SqlAlchemyBase
|
||||||
|
|
||||||
|
|
||||||
class Tool(SqlAlchemyBase):
|
class Tool(SqlAlchemyBase):
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
import sqlalchemy.orm as orm
|
import sqlalchemy.orm as orm
|
||||||
from mealie.db.models.model_base import BaseMixins, SqlAlchemyBase
|
from mealie.db.models._model_base import BaseMixins, SqlAlchemyBase
|
||||||
from mealie.db.models.recipe.category import Category, custom_pages2categories, site_settings2categories
|
from mealie.db.models.recipe.category import Category, custom_pages2categories, site_settings2categories
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import sqlalchemy.orm as orm
|
import sqlalchemy.orm as orm
|
||||||
from mealie.db.models.group import Group
|
from mealie.db.models.group import Group
|
||||||
from mealie.db.models.model_base import BaseMixins, SqlAlchemyBase
|
from mealie.db.models._model_base import BaseMixins, SqlAlchemyBase
|
||||||
from requests import Session
|
from requests import Session
|
||||||
from sqlalchemy import Boolean, Column, ForeignKey, Integer, String
|
from sqlalchemy import Boolean, Column, ForeignKey, Integer, String
|
||||||
from sqlalchemy.ext.orderinglist import ordering_list
|
from sqlalchemy.ext.orderinglist import ordering_list
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from mealie.db.models.model_base import BaseMixins, SqlAlchemyBase
|
from mealie.db.models._model_base import BaseMixins, SqlAlchemyBase
|
||||||
from sqlalchemy import Boolean, Column, Integer, String
|
from sqlalchemy import Boolean, Column, Integer, String
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import sqlalchemy.orm as orm
|
import sqlalchemy.orm as orm
|
||||||
from mealie.db.models.model_base import BaseMixins, SqlAlchemyBase
|
from mealie.db.models._model_base import BaseMixins, SqlAlchemyBase
|
||||||
from sqlalchemy import Column, ForeignKey, Integer, String
|
from sqlalchemy import Column, ForeignKey, Integer, String
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from mealie.core.config import settings
|
from mealie.core.config import settings
|
||||||
from mealie.db.models.group import Group
|
from mealie.db.models.group import Group
|
||||||
from mealie.db.models.model_base import BaseMixins, SqlAlchemyBase
|
from mealie.db.models._model_base import BaseMixins, SqlAlchemyBase
|
||||||
from mealie.db.models.recipe.recipe import RecipeModel
|
from mealie.db.models.recipe.recipe import RecipeModel
|
||||||
from sqlalchemy import Boolean, Column, ForeignKey, Integer, String, orm
|
from sqlalchemy import Boolean, Column, ForeignKey, Integer, String, orm
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user