mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-12-27 20:55:12 -05:00
@@ -1,7 +1,7 @@
|
||||
from functools import wraps
|
||||
from uuid import UUID
|
||||
|
||||
from pydantic import BaseModel, Field, NoneStr
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.orm import MANYTOMANY, MANYTOONE, ONETOMANY, Session
|
||||
from sqlalchemy.orm.mapper import Mapper
|
||||
@@ -21,7 +21,7 @@ class AutoInitConfig(BaseModel):
|
||||
Config class for `auto_init` decorator.
|
||||
"""
|
||||
|
||||
get_attr: NoneStr = None
|
||||
get_attr: str | None = None
|
||||
exclude: set = Field(default_factory=_default_exclusion)
|
||||
# auto_create: bool = False
|
||||
|
||||
@@ -31,16 +31,16 @@ def _get_config(relation_cls: type[SqlAlchemyBase]) -> AutoInitConfig:
|
||||
Returns the config for the given class.
|
||||
"""
|
||||
cfg = AutoInitConfig()
|
||||
cfgKeys = cfg.dict().keys()
|
||||
cfgKeys = cfg.model_dump().keys()
|
||||
# Get the config for the class
|
||||
try:
|
||||
class_config: AutoInitConfig = relation_cls.Config
|
||||
class_config: ConfigDict = relation_cls.model_config
|
||||
except AttributeError:
|
||||
return cfg
|
||||
# Map all matching attributes in Config to all AutoInitConfig attributes
|
||||
for attr in dir(class_config):
|
||||
for attr in class_config:
|
||||
if attr in cfgKeys:
|
||||
setattr(cfg, attr, getattr(class_config, attr))
|
||||
setattr(cfg, attr, class_config[attr])
|
||||
|
||||
return cfg
|
||||
|
||||
@@ -97,7 +97,7 @@ def handle_one_to_many_list(
|
||||
|
||||
updated_elems.append(existing_elem)
|
||||
|
||||
new_elems = [safe_call(relation_cls, elem, session=session) for elem in elems_to_create]
|
||||
new_elems = [safe_call(relation_cls, elem.copy(), session=session) for elem in elems_to_create]
|
||||
return new_elems + updated_elems
|
||||
|
||||
|
||||
@@ -164,7 +164,7 @@ def auto_init(): # sourcery no-metrics
|
||||
setattr(self, key, instances)
|
||||
|
||||
elif relation_dir == ONETOMANY:
|
||||
instance = safe_call(relation_cls, val, session=session)
|
||||
instance = safe_call(relation_cls, val.copy() if val else None, session=session)
|
||||
setattr(self, key, instance)
|
||||
|
||||
elif relation_dir == MANYTOONE and not use_list:
|
||||
|
||||
@@ -29,12 +29,15 @@ def get_valid_call(func: Callable, args_dict) -> dict:
|
||||
return {k: v for k, v in args_dict.items() if k in valid_args}
|
||||
|
||||
|
||||
def safe_call(func, dict_args: dict, **kwargs) -> Any:
|
||||
def safe_call(func, dict_args: dict | None, **kwargs) -> Any:
|
||||
"""
|
||||
Safely calls the supplied function with the supplied dictionary of arguments.
|
||||
by removing any invalid arguments.
|
||||
"""
|
||||
|
||||
if dict_args is None:
|
||||
dict_args = {}
|
||||
|
||||
if kwargs:
|
||||
dict_args.update(kwargs)
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ from typing import TYPE_CHECKING, Optional
|
||||
|
||||
import sqlalchemy as sa
|
||||
import sqlalchemy.orm as orm
|
||||
from pydantic import ConfigDict
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
from sqlalchemy.orm.session import Session
|
||||
@@ -79,9 +80,8 @@ class Group(SqlAlchemyBase, BaseMixins):
|
||||
ingredient_foods: Mapped[list["IngredientFoodModel"]] = orm.relationship("IngredientFoodModel", **common_args)
|
||||
tools: Mapped[list["Tool"]] = orm.relationship("Tool", **common_args)
|
||||
tags: Mapped[list["Tag"]] = orm.relationship("Tag", **common_args)
|
||||
|
||||
class Config:
|
||||
exclude = {
|
||||
model_config = ConfigDict(
|
||||
exclude={
|
||||
"users",
|
||||
"webhooks",
|
||||
"shopping_lists",
|
||||
@@ -91,6 +91,7 @@ class Group(SqlAlchemyBase, BaseMixins):
|
||||
"mealplans",
|
||||
"data_exports",
|
||||
}
|
||||
)
|
||||
|
||||
@auto_init()
|
||||
def __init__(self, **_) -> None:
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from datetime import datetime
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from pydantic import ConfigDict
|
||||
from sqlalchemy import ForeignKey, orm
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
from sqlalchemy.sql.sqltypes import Boolean, DateTime, String
|
||||
@@ -47,9 +48,7 @@ class ReportModel(SqlAlchemyBase, BaseMixins):
|
||||
# Relationships
|
||||
group_id: Mapped[GUID] = mapped_column(GUID, ForeignKey("groups.id"), nullable=False, index=True)
|
||||
group: Mapped["Group"] = orm.relationship("Group", back_populates="group_reports", single_parent=True)
|
||||
|
||||
class Config:
|
||||
exclude = ["entries"]
|
||||
model_config = ConfigDict(exclude=["entries"])
|
||||
|
||||
@auto_init()
|
||||
def __init__(self, **_) -> None:
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
from pydantic import ConfigDict
|
||||
from sqlalchemy import Boolean, Float, ForeignKey, Integer, String, UniqueConstraint, orm
|
||||
from sqlalchemy.ext.orderinglist import ordering_list
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
@@ -69,9 +70,7 @@ class ShoppingListItem(SqlAlchemyBase, BaseMixins):
|
||||
recipe_references: Mapped[list[ShoppingListItemRecipeReference]] = orm.relationship(
|
||||
ShoppingListItemRecipeReference, cascade="all, delete, delete-orphan"
|
||||
)
|
||||
|
||||
class Config:
|
||||
exclude = {"id", "label", "food", "unit"}
|
||||
model_config = ConfigDict(exclude={"id", "label", "food", "unit"})
|
||||
|
||||
@api_extras
|
||||
@auto_init()
|
||||
@@ -91,9 +90,7 @@ class ShoppingListRecipeReference(BaseMixins, SqlAlchemyBase):
|
||||
)
|
||||
|
||||
recipe_quantity: Mapped[float] = mapped_column(Float, nullable=False)
|
||||
|
||||
class Config:
|
||||
exclude = {"id", "recipe"}
|
||||
model_config = ConfigDict(exclude={"id", "recipe"})
|
||||
|
||||
@auto_init()
|
||||
def __init__(self, **_) -> None:
|
||||
@@ -112,9 +109,7 @@ class ShoppingListMultiPurposeLabel(SqlAlchemyBase, BaseMixins):
|
||||
"MultiPurposeLabel", back_populates="shopping_lists_label_settings"
|
||||
)
|
||||
position: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
||||
|
||||
class Config:
|
||||
exclude = {"label"}
|
||||
model_config = ConfigDict(exclude={"label"})
|
||||
|
||||
@auto_init()
|
||||
def __init__(self, **_) -> None:
|
||||
@@ -146,9 +141,7 @@ class ShoppingList(SqlAlchemyBase, BaseMixins):
|
||||
collection_class=ordering_list("position"),
|
||||
)
|
||||
extras: Mapped[list[ShoppingListExtras]] = orm.relationship("ShoppingListExtras", cascade="all, delete-orphan")
|
||||
|
||||
class Config:
|
||||
exclude = {"id", "list_items"}
|
||||
model_config = ConfigDict(exclude={"id", "list_items"})
|
||||
|
||||
@api_extras
|
||||
@auto_init()
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from pydantic import ConfigDict
|
||||
from sqlalchemy import ForeignKey, Integer, String, orm
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
@@ -28,12 +29,12 @@ class RecipeInstruction(SqlAlchemyBase):
|
||||
ingredient_references: Mapped[list[RecipeIngredientRefLink]] = orm.relationship(
|
||||
RecipeIngredientRefLink, cascade="all, delete-orphan"
|
||||
)
|
||||
|
||||
class Config:
|
||||
exclude = {
|
||||
model_config = ConfigDict(
|
||||
exclude={
|
||||
"id",
|
||||
"ingredient_references",
|
||||
}
|
||||
)
|
||||
|
||||
@auto_init()
|
||||
def __init__(self, ingredient_references, session, **_) -> None:
|
||||
|
||||
@@ -3,6 +3,7 @@ from typing import TYPE_CHECKING
|
||||
|
||||
import sqlalchemy as sa
|
||||
import sqlalchemy.orm as orm
|
||||
from pydantic import ConfigDict
|
||||
from sqlalchemy import event
|
||||
from sqlalchemy.ext.orderinglist import ordering_list
|
||||
from sqlalchemy.orm import Mapped, mapped_column, validates
|
||||
@@ -134,10 +135,9 @@ class RecipeModel(SqlAlchemyBase, BaseMixins):
|
||||
# Automatically updated by sqlalchemy event, do not write to this manually
|
||||
name_normalized: Mapped[str] = mapped_column(sa.String, nullable=False, index=True)
|
||||
description_normalized: Mapped[str | None] = mapped_column(sa.String, index=True)
|
||||
|
||||
class Config:
|
||||
get_attr = "slug"
|
||||
exclude = {
|
||||
model_config = ConfigDict(
|
||||
get_attr="slug",
|
||||
exclude={
|
||||
"assets",
|
||||
"notes",
|
||||
"nutrition",
|
||||
@@ -146,7 +146,8 @@ class RecipeModel(SqlAlchemyBase, BaseMixins):
|
||||
"settings",
|
||||
"comments",
|
||||
"timeline_events",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
@validates("name")
|
||||
def validate_name(self, _, name):
|
||||
|
||||
@@ -2,6 +2,7 @@ import enum
|
||||
from datetime import datetime
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
from pydantic import ConfigDict
|
||||
from sqlalchemy import Boolean, DateTime, Enum, ForeignKey, Integer, String, orm
|
||||
from sqlalchemy.ext.hybrid import hybrid_property
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
@@ -84,9 +85,8 @@ class User(SqlAlchemyBase, BaseMixins):
|
||||
favorite_recipes: Mapped[list["RecipeModel"]] = orm.relationship(
|
||||
"RecipeModel", secondary=users_to_favorites, back_populates="favorited_by"
|
||||
)
|
||||
|
||||
class Config:
|
||||
exclude = {
|
||||
model_config = ConfigDict(
|
||||
exclude={
|
||||
"password",
|
||||
"admin",
|
||||
"can_manage",
|
||||
@@ -94,6 +94,7 @@ class User(SqlAlchemyBase, BaseMixins):
|
||||
"can_organize",
|
||||
"group",
|
||||
}
|
||||
)
|
||||
|
||||
@hybrid_property
|
||||
def group_slug(self) -> str:
|
||||
|
||||
Reference in New Issue
Block a user