How can I refactor my code to clear off - "local variable 'data' referenced before assignment"

My code returns is intended to return queryset based on selected dates or months however these two are almost similar yet only one works.

Here is my both 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())

This is the query view that works.

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]
            .......

Though this one throws a reference error : local variable 'data' referenced before assignment

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]
            .....

Model:

class Milk(models.Model):
    amount_in_kgs = models.PositiveIntegerField(validators=[MinValueValidator(0), MaxValueValidator(50)])
    milking_date = models.DateTimeField(auto_now_add=True)
   ...

It happens when your form is invalid.

Nesting the variables that use data variable would help:

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')))

                # Now the following two declarations are in this code block
                # where "data" variable is declared already.
                labels = [c['month'].strftime("%m-%Y") for c in data]
                values = [x['amt'] for x in data]
            .....

You could also set a default for data variable before the if code block:

data = []
if form.is_valid():
...

The solution depends on your use-case.

PS. the issue is the same in both views (milk_records_range_per_month and milk_records_range_per_day).

Back to Top