fix: Only fetch recipes with a household id (#6773)

This commit is contained in:
Michael Genson
2025-12-23 16:48:27 -06:00
committed by GitHub
parent 64d8786d8f
commit d02023e12c
5 changed files with 35 additions and 141 deletions

View File

@@ -9,6 +9,7 @@ from typing import Any
from fastapi import HTTPException
from pydantic import UUID4, BaseModel
from sqlalchemy import ColumnElement, Select, case, delete, func, nulls_first, nulls_last, select
from sqlalchemy.ext.associationproxy import AssociationProxyInstance
from sqlalchemy.orm import InstrumentedAttribute
from sqlalchemy.orm.session import Session
from sqlalchemy.sql import sqltypes
@@ -77,6 +78,13 @@ class RepositoryGeneric[Schema: MealieModel, Model: SqlAlchemyBase]:
def _query(self, override_schema: type[MealieModel] | None = None, with_options=True):
q = select(self.model)
try:
if isinstance(self.model.household_id, AssociationProxyInstance):
q.filter(self.model.household_id.is_not(None))
except (AttributeError, NotImplementedError):
pass
if with_options:
schema = override_schema or self.schema
return q.options(*schema.loader_options())
@@ -87,6 +95,7 @@ class RepositoryGeneric[Schema: MealieModel, Model: SqlAlchemyBase]:
dct = {}
if self.group_id:
dct["group_id"] = self.group_id
if self.household_id:
dct["household_id"] = self.household_id

View File

@@ -21,7 +21,7 @@ from mealie.db.models.users.user_to_recipe import UserToRecipe
from mealie.db.models.users.users import User
from mealie.schema.cookbook.cookbook import ReadCookBook
from mealie.schema.recipe import Recipe
from mealie.schema.recipe.recipe import RecipeCategory, RecipePagination, RecipeSummary, create_recipe_slug
from mealie.schema.recipe.recipe import RecipePagination, RecipeSummary, create_recipe_slug
from mealie.schema.recipe.recipe_ingredient import IngredientFood
from mealie.schema.recipe.recipe_suggestion import RecipeSuggestionQuery, RecipeSuggestionResponseItem
from mealie.schema.recipe.recipe_tool import RecipeToolOut
@@ -214,7 +214,7 @@ class RepositoryRecipes(HouseholdRepositoryGeneric[Recipe, RecipeModel]):
) -> RecipePagination:
# Copy this, because calling methods (e.g. tests) might rely on it not getting mutated
pagination_result = pagination.model_copy()
q = sa.select(self.model)
q = sa.select(self.model).filter(self.model.household_id.is_not(None))
fltr = self._filter_builder()
q = q.filter_by(**fltr)
@@ -271,24 +271,6 @@ class RepositoryRecipes(HouseholdRepositoryGeneric[Recipe, RecipeModel]):
items=items,
)
def get_by_categories(self, categories: list[RecipeCategory]) -> list[RecipeSummary]:
"""
get_by_categories returns all the Recipes that contain every category provided in the list
"""
ids = [x.id for x in categories]
stmt = (
sa.select(RecipeModel)
.join(RecipeModel.recipe_category)
.filter(RecipeModel.recipe_category.any(Category.id.in_(ids)))
)
if self.group_id:
stmt = stmt.filter(RecipeModel.group_id == self.group_id)
if self.household_id:
stmt = stmt.filter(RecipeModel.household_id == self.household_id)
return [RecipeSummary.model_validate(x) for x in self.session.execute(stmt).unique().scalars().all()]
def _build_recipe_filter(
self,
categories: list[UUID4] | None = None,
@@ -334,7 +316,9 @@ class RepositoryRecipes(HouseholdRepositoryGeneric[Recipe, RecipeModel]):
return fltr
def get_random(self, limit=1) -> list[Recipe]:
stmt = sa.select(RecipeModel).order_by(sa.func.random()).limit(limit) # Postgres and SQLite specific
stmt = (
sa.select(RecipeModel).filter(RecipeModel.household_id.is_not(None)).order_by(sa.func.random()).limit(limit)
) # Postgres and SQLite specific
if self.group_id:
stmt = stmt.filter(RecipeModel.group_id == self.group_id)
if self.household_id:
@@ -405,7 +389,7 @@ class RepositoryRecipes(HouseholdRepositoryGeneric[Recipe, RecipeModel]):
ingredients_alias = orm.aliased(RecipeIngredientModel)
tools_alias = orm.aliased(Tool)
q = sa.select(self.model)
q = sa.select(self.model).filter(self.model.household_id.is_not(None))
fltr = self._filter_builder()
q = q.filter_by(**fltr)

View File

@@ -3,6 +3,7 @@ from functools import cached_property
from fastapi import APIRouter, Depends
from pydantic import UUID4, BaseModel, ConfigDict
from mealie.repos.all_repositories import get_repositories
from mealie.routes._base import BaseCrudController, controller
from mealie.routes._base.mixins import HttpRepo
from mealie.schema import mapper
@@ -123,9 +124,15 @@ class RecipeCategoryController(BaseCrudController):
def get_one_by_slug(self, category_slug: str):
"""Returns a category object with the associated recieps relating to the category"""
category: RecipeCategory = self.mixins.get_one(category_slug, "slug")
group_recipes = get_repositories(self.repos.session, group_id=self.group_id, household_id=None).recipes
recipe_data = group_recipes.page_all(
PaginationQuery(per_page=-1, query_filter=f'recipe_category.id IN ["{category.id}"]')
)
return RecipeCategoryResponse.model_construct(
id=category.id,
slug=category.slug,
name=category.name,
recipes=self.repos.recipes.get_by_categories([category]),
recipes=recipe_data.items,
)