iommirocks / iommi

Your first pick for a django power cord
http://iommi.rocks
BSD 3-Clause "New" or "Revised" License
718 stars 47 forks source link

EditTable not compatible with a choices field with named groups #422

Open ociule opened 1 year ago

ociule commented 1 year ago

Hi there,

I'm setting up a model with a choices field using named groups (doc here https://docs.djangoproject.com/en/4.2/ref/models/fields/#django.db.models.Field.choices)


MEDIA_CHOICES = [
    (
        "Audio",
        (
            ("vinyl", "Vinyl"),
            ("cd", "CD"),
        ),
    ),
    (
        "Video",
        (
            ("vhs", "VHS Tape"),
            ("dvd", "DVD"),
        ),
    ),
    ("unknown", "Unknown"),
]

class Student(models.Model):

    media_choice = models.CharField(
        max_length=12,
        choices=MEDIA_CHOICES,
    )

def example_view_func(request):

    edit_table = EditTable(
        auto__model=Student,
        columns__select__include=True,
        columns__media_choice__edit__include=True,
    ).bind(request=request)

    dispatch = edit_table.perform_dispatch()
    if dispatch is not None:
        return dispatch

    context = dict(
        edit_table=edit_table,
        assets=edit_table.iommi_collected_assets(),
        title=f"Additional Quantities for { obj }",
    )

    return render(request, "example.html", context=context)

However the select the EditTable generates for this is broken, as the html template doesn't know about named groups and I have to use a custom template to fix this

It would be great to support this named group option as Django supports it in admin etc

Edit: added view func code. Edit: not just the select is broken but anything that touches the iommi form field's choices, as it's parsed incorrectly from the ModelField.choices. As said in comments the field validation is broken too and has to be tempfixed

Cheers

ociule commented 1 year ago

The default template used is https://github.com/iommirocks/iommi/blob/master/iommi/templates/iommi/form/choice.html

which tries to use grouped_choice_tuples which doesn't work without a choice_to_optgroup callable

I've used a custom template for this field to fix this:

columns__media_choice__edit__input__template="choice_edit_named_groups.html"

<select{{ field.input.attrs }}>

    {% for optgroup, _, choice_tuples, _, _ in field.choice_tuples %}
        {% if optgroup %}
            <optgroup label="{{optgroup}}">
        {% endif %}
            {% for choice in choice_tuples %}
                <option value="{{ choice.1|stringformat:'s' }}" {% if choice.1 == field.value %}selected="selected"{% endif %}>{{ choice.0 }}</option>
            {% endfor %}
        {% if optgroup %}
            </optgroup>
        {% endif %}
    {% endfor %}
</select>
{{ field.help }}
{{ field.errors }}

Edit: updated template

ociule commented 1 year ago

Nvm, the template fix is useless as the form throws a validation error "$VALUE not in available choices" which comes from here https://github.com/iommirocks/iommi/blob/4013e1b14d8738483f078921405c0c9b98dc463e/iommi/form.py#LL290C11-L290C11


def choice_is_valid(field, parsed_data, **_):
    return parsed_data in field.choices, f'{parsed_data} not in available choices'

So I have to disable this broken field is_valid by replacing it in the EditTable constructor: columns__media_choice__edit__is_valid=lambda **_: (True, None),