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

如何重构代码解决‘局部变量data在赋值前被引用’错误?

问题:按月查询视图抛出“局部变量'data'在赋值前被引用”错误

我写了两个功能逻辑相近的视图,分别按日期范围和月份范围返回Milk记录的聚合数据,但按月查询的视图抛出“局部变量'data'在赋值前被引用”错误,按日期查询的视图却能正常运行。以下是相关代码及问题详情:


相关代码

forms.py

class DateInput(forms.DateInput):
    input_type = 'date'
class MonthInput(forms.DateTimeInput):
    input_type = 'month'
    
class DateRangeInputForm(forms.Form):
    start = forms.DateField(widget=DateInput())
    end = forms.DateField(widget=DateInput())

class MonthRangeInputForm(forms.Form):
    start = forms.DateField(widget=MonthInput())
    end = forms.DateField(widget=MonthInput())

可正常运行的按日期查询视图

def milk_records_range_per_day(self, request):
        if request.method == "POST":
            form = forms.DateRangeInputForm(request.POST)
            if form.is_valid():
                data = (models.Milk.objects.filter(milking_date__date__range=(
                    form.cleaned_data['start'], form.cleaned_data['end']))
                    .annotate(date=functions.TruncDate("milking_date"))
                    .values("date")
                    .annotate(amt=Sum('amount_in_kgs')))
            labels = [c['date'].strftime("%d-%m-%Y") for c in data]
            values = [x['amt'] for x in data]
            # 后续逻辑省略

报错的按月查询视图

def milk_records_range_per_month(self, request):
        if request.method == "POST":
            form = forms.MonthRangeInputForm(request.POST)
            if form.is_valid():
                data = (models.Milk.objects.filter(milking_date__month__range=(
                        form.cleaned_data['start'],form.cleaned_data['end']))
                        .annotate(month=functions.TruncMonth("milking_date"))
                        .values("month")
                        .annotate(amt=Sum('amount_in_kgs')))
            labels = [c['month'].strftime("%m-%Y") for c in data]
            values = [x['amt'] for x in data]
            # 后续逻辑省略

Milk模型

class Milk(models.Model):
    amount_in_kgs = models.PositiveIntegerField(validators=[MinValueValidator(0), MaxValueValidator(50)])
    milking_date = models.DateTimeField(auto_now_add=True)
    # 其他字段省略

问题原因分析

  1. 表单验证失败导致data未赋值:MonthRangeInputForm使用input_type='month'的控件,提交的是YYYY-MM格式的字符串,但DateField默认无法解析这种格式,会导致form.is_valid()返回False,此时data变量没有被赋值,后续代码引用data就会抛出“局部变量'data'在赋值前被引用”的错误。而按日期查询的表单用的是date类型控件,提交的是完整日期,DateField能正常解析,所以表单验证大概率能通过。

  2. 过滤条件错误:milking_date__month__range是错误用法,__month提取的是月份数字(1-12),无法处理跨年份的月份范围(比如从2023-11到2024-02就会因为月份数字11>2而过滤不到数据)。


解决方案

步骤1:修正表单字段的日期解析格式

修改MonthRangeInputForm,给DateField指定支持YYYY-MM格式的input_formats参数,让表单能正确解析月份输入:

class MonthRangeInputForm(forms.Form):
    start = forms.DateField(widget=MonthInput(), input_formats=['%Y-%m'])
    end = forms.DateField(widget=MonthInput(), input_formats=['%Y-%m'])

步骤2:修正查询的过滤条件

把错误的milking_date__month__range改成基于完整日期范围的过滤,同时处理月份的首尾日期:

import calendar

def milk_records_range_per_month(self, request):
        if request.method == "POST":
            form = forms.MonthRangeInputForm(request.POST)
            # 初始化data为空QuerySet,避免验证失败时无赋值
            data = models.Milk.objects.none()
            if form.is_valid():
                start_date = form.cleaned_data['start']
                # 获取结束月份的最后一天
                end_year, end_month = form.cleaned_data['end'].year, form.cleaned_data['end'].month
                end_month_last_day = calendar.monthrange(end_year, end_month)[1]
                end_date = form.cleaned_data['end'].replace(day=end_month_last_day)
                
                data = (models.Milk.objects.filter(milking_date__range=(start_date, end_date))
                        .annotate(month=functions.TruncMonth("milking_date"))
                        .values("month")
                        .annotate(amt=Sum('amount_in_kgs')))
            labels = [c['month'].strftime("%m-%Y") for c in data]
            values = [x['amt'] for x in data]
            # 后续逻辑省略

步骤3:处理表单验证失败的情况

在if form.is_valid()之前给data赋默认值(比如空QuerySet),确保无论表单是否验证通过,data变量都有值,避免报错。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 02:01:14