djangoformsmonkeypatching

Change default widgets of Django to custom ones


My usecase: I want to use a different DateInput. But I want to reduce code duplication. I want all forms, which don't explicitly want a different DateInput widget, to use my custom widget.

Any change to solve this without monkey patching?

Example

models.py:

class MyModel(models.Model):
    date=models.DateField()

forms.py:

class MyForm(forms.ModelForm):
    class Meta:
        model=MyModel

The above code should use my custom widget. I don't want to change the above models.py and forms.py, since there are many.


Solution

  • Unfortunately, I don't think you can get this working with your exact code listed above.

    Without hacking django, essentially there are 2 parts to this. The first is creating a custom form field, and the second is defaulting your custom model field to your newly created form field.

    To create your custom Form Field, you could override the existing django forms.DateField and update the widget.

    # form_fields.py
    from django.forms import DateField
    from myapp.widgets import MyWidget
    
    class MyDateFormField(DateField):
        widget = MyWidget
    

    And then after you have your form field created, you're going to have to override the django model field to default to your new form field

    # fields.py
    from django.db.models import DateField
    from myapp.form_fields import MyDateFormField
    
    class MyDateField(DateField):
        def formfield(self, **kwargs):
            defaults = {'form_class': MyDateFormField}
            defaults.update(kwargs)
            return super(DateField, self).formfield(**defaults)
    

    You would then have your custom model field, which you would need to slightly change your code to use.

    from myapp.fields import MyDateField
    
    class MyModel(models.Model):
        date=MyDateField()
    

    It's not exactly what you were asking for (have to change the model field), but hopefully this gets you in the right direction.