Trouble Rendering Nested MultiValue Form Fields in Django - ProductPropertyField

33 Views Asked by At

I'm working on a Django project and facing difficulties while trying to create a multi-value form field called ProductPropertyField. My goal is to include multiple instances of ProductPropertyField within the final ProductPropertyField, but the rendering doesn't behave as expected.

I have a specific structure I want to achieve:

ProductPropertyField should contain multiple instances of ProductPropertyField. Each ProductPropertyField instance has three fields: key, value, and new_property. I'd like to use the provided code snippet as a reference for my implementation. Here's the code I'm using for ProductPropertyField:

class ProductPropertyWidget(forms.MultiWidget):
    use_fieldset = True

    def __init__(self, attrs={}, choices=[], key=None):
        key_widget = forms.TextInput(attrs=attrs.pop("key_widget", {}))
        value_widget = forms.Select(
            attrs=attrs.pop("value_widget", {}), choices=choices
        )
        new_property_widget = forms.TextInput(
            attrs=attrs.pop("new_property_widget", {})
        )
        widgets = [
            key_widget,
            value_widget,
            new_property_widget,
        ]
        super().__init__(widgets, attrs)
    
    def decompress(self, value):
        if value:
            key, value, new_property = value.split(",")
            return [key, value, new_property]
        return [None, None, None]

class ProductPropertiesWidget(forms.MultiWidget):
    use_fieldset = True

    def __init__(self, widgets=[], attrs={}):
        super().__init__(widgets=widgets, attrs=attrs)
    
    def decompress(self, value):
        if value:
            key, value, new_property = value.split(",")
            return [key, value, new_property]
        return [None for _ in self.widgets]

class ProductPropertyField(forms.MultiValueField):
widget = ProductPropertyWidget

    def __init__(self, *args, **kwargs):
        key_field = forms.CharField()
        value_field = forms.ChoiceField(choices=kwargs.pop("choices", []))
        new_property_field = forms.CharField()
    
        super().__init__(
            fields=[key_field, value_field, new_property_field],
            require_all_fields=False,
            *args,
            **kwargs,
        )
    
    def compress(self, data_list):
        return ",".join(data_list)

class ProductPropertiesField(forms.MultiValueField):
    def __init__(self, \*args, \*\*kwargs):
        widgets = \[\]
        fields = \[\]

        key_value = ProductProperty.objects.values("feature__key", "feature__value")
    
        values = {}
    
        for property in key_value:
            key = values.get(property["feature__key"], None)
    
            if not key:
                values[property["feature__key"]] = set()
    
            values[property["feature__key"]].add(property["feature__value"])
    
        for (
            key,
            values_set,
        ) in values.items():
            value_choices = [(v, v) for v in sorted(values_set)]
    
            widget = ProductPropertyWidget(
                attrs={"placeholder": "Some placeholder"},
                choices=value_choices,
                key=key,
            )
    
            field = ProductPropertyField(label=key, choices=value_choices)
    
            fields.append(field)
            widgets.append(widget)
    
        fields.append(
            forms.CharField(
                help_text="New property should be like property_key=value",
                label="New property",
            )
        )
    
        widgets.append(forms.TextInput(attrs={"placeholder": "Add new property"}))
        widget = ProductPropertiesWidget(widgets=widgets)
    
        super().__init__(fields=fields, widget=widget, *args, **kwargs)
    
    def compress(self, data_list):
        return ",".join(data_list)

I've followed the instructions given in the code comments, but the rendering is not as expected. The nested ProductPropertyField instances don't display correctly, and I'm having trouble figuring out the issue.

Could someone please help me identify the problem and provide guidance on how to correctly render nested ProductPropertyField instances within the final ProductPropertyField?

Thank you for your assistance

HTML Output:

<fieldset>
   <legend>Properties:</legend>
   <input name="properties_0_0" required="" type="text" />
   <select name="properties_0_1" required="">
      <option value="brass">brass</option>
      <option value="bronze">bronze</option>
      <option value="clay">clay</option>
      <option value="elephant skin">elephant skin</option>
      <option value="gold">gold</option>
      <option value="marble">marble</option>
      <option value="plastic">plastic</option>
      <option value="resin">resin</option>
      <option value="vinyl">vinyl</option>
      <option value="wooden">wooden</option>
   </select>
   <input name="properties_0_2" required="" type="text" />
   <input name="properties_1_0" required="" type="text" />
   <select name="properties_1_1" required="">
      <option value="black">black</option>
      <option value="blue">blue</option>
      <option value="bronze">bronze</option>
      <option value="golden">golden</option>
      <option value="green">green</option>
      <option value="multicolored">multicolored</option>
      <option value="off white">off white</option>
      <option value="red">red</option>
      <option value="steel colored">steel colored</option>
      <option value="wooden">wooden</option>
   </select>
   <input name="properties_1_2" required="" type="text" />
   <input name="properties_2" required="" type="text" placeholder="Add new property" />
</fieldset>

[This is the output that I got.](https://i.stack.imgur.com/xpeLU.png)

I want to wrap each instance in seperate fieldset.

0

There are 0 best solutions below