'''
my_project/my_widgets.py

'''
from django.forms import CheckboxInput, MultiWidget


class NullableWidget(MultiWidget):
    """
    A Widget that wraps another Widget and renders it along with a checkbox
    that unchecked means that the value should be None (NULL) [#4136]

    """
    def __init__(self, subwidget, attrs=None):
        self.checkbox = CheckboxInput()
        self.subwidget = subwidget
        super(NullableWidget, self).__init__(
            [self.checkbox, self.subwidget], attrs
        )

    def decompress(self, value):
        if value is None:
            return [False, '']
        else:
            return [True, value]

    def value_from_datadict(self, data, files, name):
        is_set, value = [widget.value_from_datadict(data, files, name + '_%s' % i) for i, widget in enumerate(self.widgets)]

        if is_set:
            return value
        else:
            return None

    def _has_changed(self, initial, data):
        '''
        When checkbox is unticked and Text
        '''
        if initial is None:
            initial = self.decompress(initial)
        else:
            if not isinstance(initial, list):
                initial = self.decompress(initial)

        multi_data = self.decompress(data)
        for widget, initial, data in zip(self.widgets, initial, multi_data):
            if widget._has_changed(initial, data):
                return True
        return False

'''
my_project/models.py

'''
from django.db import models

class MyModel(models.Model):
    my_nullable_charfield = models.CharField("verbose name",
        blank=True,
        null=True,
        unique=True,
        default=None,
        max_length=3)
'''
my_project/forms.py

'''
from django import forms

from my_project.models import MyModel
from my_project.my_widgets import NullableWidget


class MyModelForm(forms.ModelForm):
    class Meta:
        model = MyModel
        widgets = {
            "my_nullable_charfield": NullableWidget(forms.TextInput())
        }
