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

食物追踪App添加FoodLog对象时IntegrityError问题求助

问题:添加食物项时触发NOT NULL约束错误

django.db.utils.IntegrityError: NOT NULL constraint failed: accounts_foodlogfooditem.food_log_id
[23/Sep/2023 13:56:08] "POST /accounts/food-log/ HTTP/1.1" 500 153768


错误原因分析

当前视图逻辑存在两个核心问题:

  1. 当用户直接提交食物项表单但未选择日期(或日期表单验证失败)时,food_log变量保持为None,赋值给food_log_food_item.food_log会触发数据库非空约束错误。
  2. 视图未保证处理食物项表单前,必须存在有效的FoodLog实例,导致关联字段缺失。

修复方案

修改视图逻辑,确保只有在获取到有效FoodLog实例后,才处理食物项的保存操作,同时增加重定向避免重复提交:

from django.shortcuts import render, redirect
from django.utils import timezone

def food_log(request):
    food_log = None
    total_macros = {}
    today = timezone.now().date()

    if request.method == 'POST':
        # 通过action区分不同提交动作
        action = request.POST.get('action')
        date_form = DateForm(request.POST)
        food_item_form = FoodLogFoodItemForm(request.POST)

        if action == 'select_date':
            # 处理日期选择请求
            if date_form.is_valid():
                selected_date = date_form.cleaned_data['date']
                food_log, created = FoodLog.objects.get_or_create(user=request.user, date=selected_date)
                total_macros = food_log.calculate_total_macros_log()
        
        elif action == 'add_food':
            # 处理添加食物请求,优先从表单获取日期
            if date_form.is_valid():
                selected_date = date_form.cleaned_data['date']
                food_log, created = FoodLog.objects.get_or_create(user=request.user, date=selected_date)
            else:
                # 日期表单无效时,默认使用当天的FoodLog
                food_log = FoodLog.objects.filter(user=request.user, date=today).first()
            
            # 确保FoodLog存在时再保存食物项
            if food_log and food_item_form.is_valid():
                food_log_food_item = food_item_form.save(commit=False)
                food_log_food_item.food_log = food_log
                food_log_food_item.save()
                # 重定向避免重复提交
                return redirect('food_log')

    else:
        # GET请求默认加载当天的FoodLog
        food_log = FoodLog.objects.filter(user=request.user, date=today).first()
        date_form = DateForm(initial={'date': today})
        if food_log:
            total_macros = food_log.calculate_total_macros_log()

    food_item_form = FoodLogFoodItemForm()

    return render(request, 'food_log.html',
                  {'food_log': food_log, 'date_form': date_form, 'food_item_form': food_item_form,
                   'total_macros': total_macros})

模板优化建议

在模板中区分日期选择和食物添加的表单,确保提交时携带选中的日期,同时隐藏食物添加表单直到用户选择日期:

<form method="post">
    {% csrf_token %}
    {{ date_form.as_p }}
    <button type="submit" name="action" value="select_date">选择日期</button>
</form>

{% if food_log %}
<form method="post">
    {% csrf_token %}
    <!-- 隐藏日期字段,确保提交时携带当前选中的日期 -->
    {{ date_form.date.as_hidden }}
    {{ food_item_form.as_p }}
    <button type="submit" name="action" value="add_food">添加食物</button>
</form>

<div class="macros-summary">
    <h3>宏量营养总计</h3>
    <p>卡路里: {{ total_macros.log_total_kcal|floatformat:2 }}</p>
    <p>碳水化合物: {{ total_macros.log_total_carbohydrates|floatformat:2 }}g</p>
    <p>脂肪: {{ total_macros.log_total_fats|floatformat:2 }}g</p>
    <p>蛋白质: {{ total_macros.log_total_proteins|floatformat:2 }}g</p>
</div>
{% endif %}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 10:53:20