Basic Date Form Field is not populated?

Hey everyone. I can’t seem to fix this, what I consider, basic concept for loading a datefield from an existing model object to a form for “editing”.

The object “Batch” has a datefield called “startdate”. It’s saved in the object, and I can see it in the form field. Yet, it’s not displayed/loaded in HTML, when I ‘GET’ with a ‘pk’ in my view.

models.py:

class Batch(models.Model):

    def __str__(self):
        return self.name

    class Meta:
        verbose_name_plural = 'batches'

    name = models.CharField(max_length=50)
    startdate = models.DateTimeField(auto_now=True)
    enddate = models.DateTimeField(null=True, blank=True)
    lotId = models.CharField(max_length=7, null=True)
    size = DescriptiveQuantityField(base_units='liters', unit_choices=['liters','gallons'])
    active = models.BooleanField(default=True)
    fermenter = models.ForeignKey(Fermenter, on_delete=models.RESTRICT)
    startingGravity = QuantityField(base_units="sg")
    estimatedEndGravity = QuantityField(base_units="sg")
    category = models.ForeignKey(BatchCategory, on_delete=models.RESTRICT, blank=True, null=True)
    activity = models.ManyToManyField(ActivityLog, blank=True, related_name='batch')
    recipe = models.ForeignKey(Recipe, on_delete=models.RESTRICT, null=True, blank=True)

    def transfer(self,src_vessel, dst_vessel):
        pass

    def complete(self):
        self.enddate = datetime.now()
        self.active = False

    def current_gravity(self):
        pass


    def percent_complete(self):
        pass

forms.py:

class BatchAddForm(forms.Form):
    name = forms.CharField(widget=forms.TextInput(attrs={'placeholder':'Name of Batch'}),required=True)
    startdate = forms.DateField(label="Start Date",widget=DateInput(attrs={'type':'date'}),required=True)
    size = forms.CharField(widget=forms.TextInput(attrs={'placeholder':'i.e. 6 gallons'}),label = "Batch Size", required=True)
    fermenter = forms.ModelChoiceField(queryset=Fermenter.objects.all())
    startingGravity = forms.CharField(widget=PrecisionTextWidget(precision=3, base_units='sg'), label="Starting Gravity", required=True)
    estimatedEndGravity = forms.CharField(widget=PrecisionTextWidget(precision=3, base_units='sg'), label="Estimated End Gravity", required=True)
    recipe = forms.ModelChoiceField(queryset=Recipe.objects.all())

views.py:

def addBatch(request, pk=None):
    if request.method == "POST":
        form = BatchAddForm(request.POST)
        if form.is_valid():
            batch = Batch()
            batch.name = form.cleaned_data['name']
            batch.startdate = form.cleaned_data['startdate']
            batch.size = form.cleaned_data['size']
            batch.startingGravity = form.cleaned_data['startingGravity']
            batch.estimatedEndGravity = form.cleaned_data['estimatedEndGravity']
            batch.fermenter = form.cleaned_data['fermenter']
            newbatch = batch.save()
            batch.recipe = form.cleaned_data['recipe']
            batch.save()
            return HttpResponseRedirect(reverse('batch', kwargs={'pk': batch.pk}))
        else:
            return render(request, template_name='batchthis/addBatch.html', context={'form': form})
    else:
        if pk:
            batch = Batch.objects.get(pk=pk)
            form = BatchAddForm(initial=model_to_dict(batch))
            form.fermenter = batch.fermenter
            form.startdate = batch.startdate
            pdb.set_trace()
        else:
            form = BatchAddForm()
            form.fields['fermenter'].queryset = Fermenter.objects.filter(vessel__status=Vessel.STATUS_READY)
        return render(request, "batchthis/addBatch.html", {'form': form})

When doing a trace() in my views.py, prior to sending the render() I reviewed the data:

>(Pdb) form.startdate
datetime.datetime(2025, 2, 24, 0, 3, 51, 778136, tzinfo=datetime.timezone.utc)
>(Pdb) print(form.startdate)
2025-02-24 00:03:51.778136+00:00

Rendered HTML:

<div id="div_id_startdate" class="form-group">
        <label for="id_startdate" class=" requiredField">
                Start Date<span class="asteriskField">*</span>
        </label>
        <div>
                    <input type="date" name="startdate" class="dateinput form-control" required id="id_startdate">
        </div>
        
</div>

These two lines aren’t doing anything for you. The fields in the form that are being rendered are not direct attributes on the form instance. (Forms, like models, are built via metaclasses and in many ways do not behave like typical Python classes.)

How are you rendering the form? (What does the addBatch.html template look like?)

Side note: There’s a lot of this that gets simplified if your BatchAddForm were a ModelForm.

Those are there for troubleshooting. Will remove, but didn’t change anything, as you were implying.

Pretty simplistic, really, using Crispy Forms. Snipped out any of the includes or javascript for other fields. Funny thing, is that it SAVES fine. Just not rendering.

{% if form.errors %}
            <div class="alert alert-warning" role="alert">
                {{ form.errors }}
            </div>
{% endif %}
            <form method="POST" class="post-form" id="batchform" recipe-gravity-url="{% url 'getDataFromRecipe' %}">
                {% csrf_token %}
                <div class = "form-row">
                    <div class="form-group col-md-4 col-mb-0">
                        {{ form.recipe|as_crispy_field }}
                    </div>
                    <div class = "form-group col-md-4 col-mb-0">
                        {{ form.size|as_crispy_field }}
                    </div>
                    <div class = "form-group col-md-4 col-mb-0">
                        {{ form.startdate|as_crispy_field }}
                    </div>
                </div>
                <div class = "form-row">
                    <div class = "form-group col-md-4 col-mb-0">
                        {{ form.startingGravity|as_crispy_field }}
                    </div>
                    <div class = "form-group col-md-4 col-mb-0">
                        {{ form.estimatedEndGravity|as_crispy_field }}
                    </div>
                    <div class = "form-group col-md-4 col-mb-0">
                        {{ form.fermenter|as_crispy_field }}
                    </div>
                </div>
                <div class = "form-row">
                    <div class="form-group col-md-6 col-mb-0">
                        {{ form.name|as_crispy_field }}
                    </div>
                    <button type="submit" class="btn btn-primary btn-user btn-block">Save</button>
                </div>
            </form>

Renders as the following, with all other fields loaded:
image

<conjecture>
I’m going to make a wild guess that the issue might be an issue caused by the combination of using the model_to_dict function returning values (and not the objects - in this case what should be a DateTimeField) and the as_crispy_field method.

As a quick test, I’d remove the as_crispy_field filter from that field just to see what happens.

I’d also suggest trying to replace the Form with a ModelForm such that you can assign the instance directly to the form without using model_to_dict.
</conjecture>

Yeah. Initially, I was doing something a bit more complex, but refactored it elsewhere, so the need for individual fields isn’t needed anymore. I’ll work on replacing to model form, but the crispy_field removal is a good idea. Thanks.