# Mealie！构建事无巨细的食谱管理系统

## 概述

想必各位都纠结过每天应该吃什么，使用家中现有的食材可以做出哪些之前未尝试制作过的美食。如果有一个食谱管理系统，可以在各个维度上对食谱进行检索，对检索结果提供所需的食材、制作过程等细节，那么无疑会方便许多。

Mealie 是一款非常详尽的食谱管理系统，提供了非常细致的记录和存放食谱的数据库。官网地址是[这个](https://mealie.io/)，Github 页面的地址是[这个](https://github.com/mealie-recipes/mealie)，主要功能如下：

- 「**食谱管理**」：支持手动创建食谱和导入食谱，提供了食品、单位、标注、分类、标签、用具等多种相关数据的管理，方便整理大量食谱。
- 「**食材与购物清单**」：根据食谱自动生成食材清单，并可整合为购物清单，支持多用户协作编辑。
- 「**膳食计划**」：创建每日/每周的饮食计划，关联食谱并自动生成所需食材汇总。
- 「**多平台访问**」：适配电脑、平板或手机，随时随地查看食谱。

>[!info]  信息
>可以看到 Mealie 的功能是非常全面的，然而，也正是因为全面的功能，导致维护 Mealie 的数据库工作量会比较大，本文也在着力于解决这一困难。

## 安装部署

软件可以通过 [Docker](https://hub.docker.com/r/hkotel/mealie) 进行安装部署，命令如下：

```dockerfile
docker run -itd --name Mealie --restart always\
  -p 9925:9000 \
  -e ALLOW_SIGNUP=false \
  -e PUID=「PUID」 \
  -e PGID=「PGID」 \
  -e TZ=Asia/Shanghai \
  -e BASE_URL=「URL」 \
  -e DB_ENGINE=postgres \
  -e POSTGRES_USER=「USER」 \
  -e POSTGRES_PASSWORD=「PASSWORD」 \
  -e POSTGRES_SERVER=「HOST」 \
  -e POSTGRES_PORT=「PORT」 \
  -e POSTGRES_DB=「DATABASE」 \
  -v 「MEALIE_PATH」:/app/data \
  hkotel/mealie:latest
```

>[!info]  信息
>这里使用了`PostgreSQL`数据库，如果没有指定数据库，则会使用默认的`SQLite`数据库

## 枚举值维护

安装完成之后，还需要对于枚举值进行一定的维护，这样后续的使用过程中会更加得心应手。

点击左上角的「用户头像」可以进入「用户设置」页面，这里有一个非常重要的功能「数据库维护」。

![](https://img.papergate.top:5000/i/2025/06/686213a985c23.webp)

进入后可以对数据库中常用的枚举值进行维护：

### 食材数据

标注、食品、单位是对于食材本身枚举参数的维护。

#### 标注

标注就是单个食材的类型，比如可以设置如下：

![](https://img.papergate.top:5000/i/2025/06/6862153bc36a0.webp)

#### 食品

在完成上一步标注的设置之后，可以对食品进行简单的维护，因为后面可以通过 API 来维护食品，所以可以先简单构建即可：

![](https://img.papergate.top:5000/i/2025/06/6862159d7e197.webp)

#### 单位

单位表示单个食材的计量单位，本身没有太多的可选项，简单维护即可：

![](https://img.papergate.top:5000/i/2025/06/686215cd12ca7.webp)

### 食谱数据

食谱数据是对每个菜品的标签数据的维护。

#### 分类

按照我的个人理解进行了简单的分类，类别可以同时选择多个：

![](https://img.papergate.top:5000/i/2025/06/686216ce48c17.webp)

#### 标签

按照我的理解按照难易度和口味设置了标签：

![](https://img.papergate.top:5000/i/2025/06/6862172a80f14.webp)

#### 用具

稍微设置一下，后期也可以进行添加：

![](https://img.papergate.top:5000/i/2025/06/68621761d03b6.webp)

## 添加食谱

>[!info]  信息
>设置完枚举值之后，可以开始尝试添加食谱，这里本人建议仅作为练习，尝试一下各种添加方式。对于少量的食谱，手动创建还比较方便，但如果食谱很多的情况下，就应当优先考虑使用流程化的程序进行添加。

添加食谱分为「手动创建」和「导入食谱」两种，「手动创建」可选择的字段更加多一些，「导入食谱」功能我个人使用下来感觉不是很完善，很多「手动创建」可以选择的字段，在「导入食谱」下无法使用。

### 手动创建

在左上角点击按钮：

![](https://img.papergate.top:5000/i/2025/06/6862181199619.webp)

给食谱添加一个不可重复的名称：

![](https://img.papergate.top:5000/i/2025/06/686218e4d31ce.webp)

然后会进入详细设置页面，在这里可以点击「设定」，可以显示出更多的细节内容：

![](https://img.papergate.top:5000/i/2025/06/68621a9d42222.webp)

食材方面可以选择之前设定的枚举值进行填入，这里也可以直接创建新的枚举值并填入：

![](https://img.papergate.top:5000/i/2025/06/68621ae48e8ce.webp)

同样，分类、标签、所需用具也可以创建新的值：

![](https://img.papergate.top:5000/i/2025/06/68621b761b93f.webp)

做法方面也可以设置的相当的详细，如下：

![](https://img.papergate.top:5000/i/2025/06/68621c5491815.webp)

营养方面可以进行的设置也很多，包括卡路里、碳水、胆固醇、脂肪、纤维、蛋白质、饱和脂肪、钠、糖、反式脂肪、不饱和脂肪：

![](https://img.papergate.top:5000/i/2025/06/68621c995eb4f.webp)

其他的一些信息可以放到备注里面去：

![](https://img.papergate.top:5000/i/2025/06/68621d0f21498.webp)

### 导入食谱

导入食谱有一个「从 HTML 或者 JSON 导入」的方式，导入数据的模板可以前往[这个网址](https://schema.org/Recipe)查看：

```json
{  
  "@context": "https://schema.org",  
  "@type": "Recipe",  
  "author": "John Smith",  
  "cookTime": "PT1H",  
  "datePublished": "2009-05-08",  
  "description": "This classic banana bread recipe comes from my mom -- the walnuts add a nice texture and flavor to the banana bread.",  
  "image": "bananabread.jpg",  
  "recipeIngredient": [  
    "3 or 4 ripe bananas, smashed",  
    "1 egg",  
    "3/4 cup of sugar"  
  ],  
  "interactionStatistic": {  
    "@type": "InteractionCounter",  
    "interactionType": "https://schema.org/Comment",  
    "userInteractionCount": "140"  
  },  
  "name": "Mom's World Famous Banana Bread",  
  "nutrition": {  
    "@type": "NutritionInformation",  
    "calories": "240 calories",  
    "fatContent": "9 grams fat"  
  },  
  "prepTime": "PT15M",  
  "recipeInstructions": "Preheat the oven to 350 degrees. Mix in the ingredients in a bowl. Add the flour last. Pour the mixture into a loaf pan and bake for one hour.",  
  "recipeYield": "1 loaf",  
  "suitableForDiet": "https://schema.org/LowFatDiet"  
}
```

![](https://img.papergate.top:5000/i/2025/06/68621e0a292b9.webp)

>[!info]  信息
>我稍微尝试了一些写法之后发现，这样导入可以选择的字段比较有限，信息量不如手动创建多，我个人而言并不推荐使用这种方式。

### 使用 API 新增食谱

因为导入食谱可以选择的字段有限，手动创建食谱又比较麻烦，难以批量创建，我们可以使用官方提供的 API 模拟手动创建食谱的过程。

首先，点击左上角的「用户头像」可以进入「用户设置」页面，创建一个 「API 令牌」

![](https://img.papergate.top:5000/i/2025/06/686236f6b02a1.webp)

我们查看一下应用提供的全部 API 接口，应用接入 `Swagger`,只需要在域名后面添加`/docs`即可以访问 API 接口了，比如：

```bash
https://xxx.com/docs
```

在`Recipe:CRUD`列表下，我们可以看到「新增食谱」和「修改食谱」的方法：

![](https://img.papergate.top:5000/i/2025/06/6862386575937.webp)

#### API 令牌

使用`Bearer Token`将令牌输入即可：

![](https://img.papergate.top:5000/i/2025/06/6862391101cfe.webp)

#### 新增食谱

查看文档，「新增食谱」可以使用 `POST` 请求访问接口：

```bash
https://xxx.com/api/recipes
```

只需要传入食谱的名称即可：

```json
{
  "name": "测试食谱"
}
```

#### 修改食谱

查看文档，「修改食谱」需要使用`PATCH`请求访问：

```bash
https://xxx.com/api/recipes/ce-shi-shi-pu
```

需要传入的参数和手动创建时相同，下面给出了一个比较详细的例子：

```json
{  
  "name": "测试食谱",  
  "slug": "ce-shi-shi-pu",  
  "image": null,  
  "recipe_servings": 1.0,  
  "recipe_yield_quantity": 1.0,  
  "recipe_yield": null,  
  "total_time": "1 小时",  
  "prep_time": "30 分钟",  
  "perform_time": "40 分钟",  
  "cook_time": null,  
  "description": "色泽棕红，细嫩鲜香，豆鼓味浓，咸鲜适口，佐酒助餐均宜。",  
  "recipe_category": [  
    {  
      "id": "a192c515-3de0-458a-af3c-cdf2e0568799",  
      "name": "汤类",  
      "slug": "tang-lei"  
    }  
  ],  
  "tags": [  
    {  
      "id": "32c29b3c-2f4b-467d-8c83-61f9d0740ac7",  
      "name": "简单",  
      "slug": "jian-dan"  
    },  
    {  
      "id": "e4560c97-3039-404f-82ae-15b7c0d2692d",  
      "name": "甜",  
      "slug": "tian"  
    }  
  ],  
  "tools": [],  
  "rating": null,  
  "org_url": "https://www.baidu.com",  
  "last_made": null,  
  "recipe_ingredient": [  
    {  
      "quantity": 750,  
      "unit": {  
        "id": "870bc7db-350e-4388-9cdc-efc0724fee7d",  
        "name": "克"  
      },  
      "food": {  
        "id": "df64f6ce-0df5-4ad1-899b-90899c372252",  
        "name": "猪肉"  
      },  
      "note": "",  
      "title": null,  
      "reference_id": "8e96d136-376c-463c-b959-317bc6b5dfcb"  
    }  
  ],  
  "recipe_instructions": [  
    {  
      "title": "处理食材",  
      "summary": "洗净",  
      "text": "将鲜鲫鱼去鳞、鳃、内脏，清洗干净，然后下油锅略炸一下捞起沥油\n待用。",  
      "ingredient_references": []  
    }  
  ],  
  "nutrition": {  
    "calories": 20,  
    "carbohydrate_content": 30,  
    "cholesterol_content": 40,  
    "fat_content": 50,  
    "fiber_content": 60,  
    "protein_content": 70,  
    "saturated_fat_content": 80,  
    "sodium_content": 90,  
    "sugar_content": 100,  
    "trans_fat_content": 110,  
    "unsaturated_fat_content": 120  
  },  
  "settings": {  
    "public": true,  
    "show_nutrition": true,  
    "show_assets": true,  
    "landscape_view": false,  
    "disable_comments": false,  
    "disable_amount": false,  
    "locked": false  
  },  
  "assets": [],  
  "notes": [  
    {  
      "title": "工艺关键",  
      "text": "鱼不可炸制过久，皮硬即捞出沥油。\n酱油、白糖用量要少，成菜后不能吃出甜味。\n收汁时，汤汁的多少要掌握适度，不可收的过于，以免糊锅。"  
    }  
  ],  
  "extras": {},  
  "comments": []  
}
```

#### 获取枚举值

可以看到，上一步「修改食谱」时，凡是涉及到几个枚举值的地方，都需要传入一条完整的枚举值数据，涉及到 ID 号等。

查看文档，需要使用 `GET` 请求「获取枚举值」的方法主要有以下这些：

```bash
https://xxx.com/api/groups/labels?page=1&perPage=50
https://xxx.com/api/foods?page=1&perPage=50
https://xxx.com/api/units?page=1&perPage=50
https://xxx.com/api/organizers/categories?page=1&perPage=50
https://xxx.com/api/organizers/tags?page=1&perPage=50
https://xxx.com/api/organizers/tools?page=1&perPage=50
```

#### 新增枚举值

当我们所需的枚举值不在查询结果中时，需要使用 `POST` 请求「新增枚举值」，主要方法如下：

新增标注：

```bash
https://xxx.com/api/groups/labels
```

需要传入的参数：

```json
{
  "name": "荤菜",
  "color": "#FF7043"
}
```

新增食品：

```bash
https://xxx.com/api/foods
```

需要传入的参数：

```json
{
  "name": "猪肉",
  "labelId": "44e03c79-4da6-4c51-b9bf-a8913a45cf5e",
}
```

新增单位：

```bash
https://xxx.com/api/units
```

需要传入的参数：

```json
{
  "name": "毫升"
}
```

新增分类：

```bash
https://xxx.com/api/organizers/categories
```

需要传入的参数：

```json
{
  "name": "主食"
}
```

新增标签：

```bash
https://xxx.com/api/organizers/tags
```

需要传入的参数：

```json
{
  "name": "简单"
}
```

新增用具：

```bash
https://xxx.com/api/organizers/tools
```

需要传入的参数：

```json
{
  "name": "微波炉"
}
```

## 总结

根据上面列出的使用 API 新增食谱的方法，我们可以知晓，理论上，我们是可以使用一个流程化的程序来快速生成一条食谱数据的。

>[!info]  信息
> 实际上，大部分现实中我们所见到的菜谱，并不会像 Mealie 这么详细的列举出所有可以填入的参数，很多参数是不会直接写在食谱上的，而是要根据食谱，结合常识和一定的计算才可以推断出来。

>[!example]  示例
>就比如，绝大部分食谱上根本不可能印有食谱的营养数据，而食物的热量、蛋白质、脂肪等参数，经过一定的推断和计算是可以算个大概的。

所以在后续，使用 AI 工具自动推算出这些数据，并且自动生成相应的数据格式并写入 Mealie 数据库才是一套更加行之有效的方式。

---

> 作者: Aphros  
> URL: https://blog.papergate.top/posts/mealie%E6%9E%84%E5%BB%BA%E4%BA%8B%E6%97%A0%E5%B7%A8%E7%BB%86%E7%9A%84%E9%A3%9F%E8%B0%B1%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9F/  

