Search code examples
pythondjangodjango-admin

Field value not being populated except when it's being debugged


I'm having a weird problem where normally field_val should be set to some particular value but is being set to "". When I debug in vscode and look into the value from the debugger, inspecting it (possibly triggering something), suddenly the variable becomes available. When I'm not debugging the value is empty string. I couldn't understand what's happening here. Is there some kind of lazy evaluation that I'm missing in django forms?

I'm trying to keep the submitted value in the datalist when the form submission fails. Trying to take that value from the self.instance which is an instance of my django db model basically.

class DatalistFieldMixin:
    def make_field_datalist(self, field_name, choices, choice_format=lambda c: c):
        field_val = getattr(self.instance, field_name) or ""

        # Create the datalist widget while setting the html "value" attribute.
        # And set the widget as the form field.
        if self.fields.get(field_name):
            widget = DatalistWidget(
                choices=[choice_format(c) for c in choices],
                attrs={"value": field_val},
            )
            self.fields[field_name].widget = widget


class ObjectAdminForm(DatalistFieldMixin, forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.make_field_datalist(
            field_name="broadsign_active_container_id",
            choices=BroadsignContainer.objects.all(),
            choice_format=lambda c: (
                c.container_id,
                " - ".join((str(c.container_id), c.container_name)),
            ),
        )

Real quick gif explaining my issue: issue_gif


Solution

  • I couldn't understand what's happening here, but in the end I am getting the field value from the self.data and self.instance combined.

    Essentially this ensures that the html datalist input value is being filled when:

    • the form submission fails with invalid data,
    • if the instance already has a value,
    • sets the value to "" when the field is None (otherwise it appears as "None" in the datalist).

    And or "" part in getattr(self.instance, field_name) or "" was necessary due to getattr(self.instance, field_name) literally existing as equal to None.

    class DatalistFieldMixin:
        def make_field_datalist(self, field_name, choices, choice_format=lambda c: c):
            field_val = self.data.get(field_name, getattr(self.instance, field_name) or "")
    
            # Create the datalist widget while setting the html "value" attribute.
            # And set the widget as the form field.
            if self.fields.get(field_name):
                widget = DatalistWidget(
                    choices=[choice_format(c) for c in choices],
                    attrs={"value": field_val},
                )
                self.fields[field_name].widget = widget