Search code examples
djangowidgetmodelform

Image fields or Boolean fields in django forms widgets?


I am trying to add an image field in the widgets dictionary but I don't know what is the property for forms to do that. like forms.TextInput what should I use for an image field or a Boolean field? here the code is giving me error in image property of widgets dictionary.

class CreateProductForm(ModelForm):
    class Meta:
        model = Product
        fields = ['name', 'price', 'category', 'description', 'image']
        widgets = {
            'name': forms.TextInput(attrs={'class': 'form-control'}),
            'price': forms.NumberInput(attrs={'class': 'form-control'}),
            'category': forms.Select(attrs={'class': 'form-control'}),
            'description': forms.Textarea(attrs={'class': 'form-control'}),
            'image': forms.ImageInput(attrs={'class': 'form-control'}),
        }

Solution

  • There are two file inputs you can use. The ClearableFileInput should be used if you are allowed to remove the image (i.e set it to blank/null). If not FileInput is the right choice.

    Also for booleans the CheckboxInput is the default from Django.

    class CreateProductForm(ModelForm):
        class Meta:
            model = Product
            fields = ['name', 'price', 'category', 'description', 'my_bool', 'image']
            widgets = {
                'my_bool': forms.CheckboxInput(attrs={'class': 'form-control'}),
                'image': forms.ClearableFileInput(attrs={'class': 'form-control', 'accept': 'image/*'}),
            }
    

    Rather than overriding all the widgets, it might be better to override __init__

    class CreateProductForm(ModelForm):
        ...
    
        def __init__(self, *args, **kwargs)
            super().__init__(*args, **kwargs)
            for field in self.fields.values():
                field.widget.attrs.update({'class': 'form-control'})
    

    You can even take this out into a separate mixin or base class for all your forms.

    Personally, I would suggest not doing any of this in Python but rather in the HTML template, just so it's clear where the classes come from.