You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django REST Framework菜单API JSON数据入库报错求助

错误原因与解决方案

1. 核心错误原因

报错AttributeError: 'str' object has no attribute 'get'是因为你直接遍历了整个JSON字典(json_data是包含meals和ingredients键的字典),循环中拿到的meal_data其实是字典的键名(字符串类型,比如"meals"),自然没有.get()方法。

2. 分步修复方案

2.1 修正JSON数据遍历逻辑

你需要从JSON字典中取出meals数组来遍历餐品数据,而不是直接遍历整个字典:

def store_json_data(json_data):
    # 先取出meals数组,再遍历
    for meal_data in json_data.get('meals', []):
        # 后续逻辑...

2.2 修复Ingredient模型与关联逻辑

你的Ingredient模型没有meal字段,但代码中Ingredient.objects.get_or_create用了meal=meal,这会抛出字段不存在的错误。Meal和Ingredient是多对多关系,通过MealIngredient中间表关联,所以要先创建Ingredient,再创建中间表实例来关联:

# 替换原ingredient创建逻辑
ingredient, _ = Ingredient.objects.get_or_create(name=ingredient_data.get('name', ''))
# 创建Meal和Ingredient的关联
MealIngredient.objects.get_or_create(meal=meal, ingredient=ingredient)

2.3 处理Ingredient的groups字段

JSON中groups是数组,但你的模型里是CharField,需要将数组转为字符串(比如逗号分隔):

# 处理全局ingredients数据时
for global_ingredient_data in json_data.get('ingredients', []):
    groups = ','.join(global_ingredient_data.get('groups', []))
    ingredient, _ = Ingredient.objects.get_or_create(
        name=global_ingredient_data.get('name', ''),
        defaults={'groups': groups}
    )
    # 处理options...

2.4 分离餐品与全局配料的处理逻辑

JSON里的meals字段是餐品关联的配料(仅包含名称、数量),ingredients字段是全局配料的详细信息(包含groups、options),需要分开处理:

  • 先处理全局配料,保存groups和options
  • 再处理餐品,关联已保存的配料

2.5 修正Option创建逻辑

Option属于全局配料,所以要从json_data['ingredients']中获取options数据,而不是餐品里的配料:

for global_ingredient_data in json_data.get('ingredients', []):
    ingredient, _ = Ingredient.objects.get_or_create(
        name=global_ingredient_data.get('name', ''),
        defaults={'groups': ','.join(global_ingredient_data.get('groups', []))}
    )
    for option_data in global_ingredient_data.get('options', []):
        option, _ = Option.objects.get_or_create(
            ingredient=ingredient,
            quality=option_data.get('quality', ''),
            defaults={
                'name': option_data.get('name', ''),
                'price': option_data.get('price', 0.0),
                'per_amount': option_data.get('per_amount', '')
            }
        )

2.6 优化数据导入时机

不要在models.py中直接调用load_json_file(path),这会导致每次Django启动都执行导入。建议创建Django管理命令(management/commands/import_menu.py)来执行导入操作。

3. 完整修正后的代码示例

models.py(仅修正模型字段逻辑,结构不变)

from django.db import models

class Meal(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=100)
    is_vegetarian = models.BooleanField(default=False)
    is_vegan = models.BooleanField(default=False)

class Ingredient(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=100)
    groups = models.CharField(max_length=100)

class Option(models.Model):
    id = models.AutoField(primary_key=True)
    ingredient = models.ForeignKey(Ingredient, on_delete=models.CASCADE)
    name = models.CharField(max_length=100)
    quality = models.CharField(max_length=100)
    price = models.FloatField()
    per_amount = models.CharField(max_length=100)

class MealIngredient(models.Model):
    id = models.AutoField(primary_key=True)
    meal = models.ForeignKey(Meal, on_delete=models.CASCADE)
    ingredient = models.ForeignKey(Ingredient, on_delete=models.CASCADE)

管理命令示例(import_menu.py)

# 在app目录下创建management/commands/import_menu.py
from django.core.management.base import BaseCommand
import json
from api.models import Meal, Ingredient, Option, MealIngredient

class Command(BaseCommand):
    help = 'Import menu data from JSON file'

    def handle(self, *args, **kwargs):
        path = r"C:\Users\OSMAN MERT\Desktop\menu\menu_core\menu.json"
        with open(path) as json_file:
            json_data = json.load(json_file)
            
            # 先处理全局配料
            for global_ingredient_data in json_data.get('ingredients', []):
                groups = ','.join(global_ingredient_data.get('groups', []))
                ingredient, _ = Ingredient.objects.get_or_create(
                    name=global_ingredient_data.get('name', ''),
                    defaults={'groups': groups}
                )
                # 处理配料选项
                for option_data in global_ingredient_data.get('options', []):
                    Option.objects.get_or_create(
                        ingredient=ingredient,
                        quality=option_data.get('quality', ''),
                        defaults={
                            'name': option_data.get('name', ''),
                            'price': option_data.get('price', 0.0),
                            'per_amount': option_data.get('per_amount', '')
                        }
                    )
            
            # 处理餐品
            for meal_data in json_data.get('meals', []):
                meal, created = Meal.objects.get_or_create(
                    name=meal_data.get('name', ''),
                    defaults={
                        'is_vegetarian': meal_data.get('is_vegetarian', False),
                        'is_vegan': meal_data.get('is_vegan', False)
                    }
                )
                # 关联餐品与配料
                for ingredient_data in meal_data.get('ingredients', []):
                    ingredient = Ingredient.objects.filter(name=ingredient_data.get('name', '')).first()
                    if ingredient:
                        MealIngredient.objects.get_or_create(meal=meal, ingredient=ingredient)
            
            self.stdout.write(self.style.SUCCESS('Menu data imported successfully!'))

修正JSON语法错误

你提供的JSON末尾缺少闭合的]和},修正后:

{
"meals": [
  {
    "id": 1,
    "name": "Rice and chicken bowl",
    "ingredients": [
      { "name": "Rice", "quantity": 120, "quantity_type": "gram" },
      { "name": "Chicken", "quantity": 85, "quantity_type": "gram" }
    ]
  },
  {
    "id": 2,
    "name": "Pasta with marinara sauce and vegetables",
    "ingredients": [
      { "name": "Pasta", "quantity": 115, "quantity_type": "gram" },
      {
        "name": "Marinara sauce",
        "quantity": 120,
        "quantity_type": "millilitre"
      },
      { "name": "Vegetables", "quantity": 240, "quantity_type": "gram" }
    ]
  }
],

"ingredients": [
  {
    "name": "Rice",
    "groups": ["vegan", "vegetarian"],
    "options": [
      {
        "name": "Long grain white rice",
        "quality": "high",
        "price": 3,
        "per_amount": "kilogram"
      }
    ]
  }
]
}

4. 执行导入

在项目根目录运行命令:

python manage.py import_menu

内容的提问来源于stack exchange,提问作者Mert Altintas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 00:52:40