This is known as a "combo box", somewhat different to a select.
Check this google search:
html5
combo box django
Some useful video tutorials + some explanations on how it all works.
A simpler approach - override the widget class similar to how you have done, but there is no need to override them all and I would avoid doing so. If you just need to add some attributes, you can add to the attrs dict of the existing widget instead
of replacing it entirely. Plenty of examples exist for that, including the (excellent) django documentation. For your combo box selector you would need to override the widget in order to render the html so you use something different to Select.
Something like (except from a recent project of mine) the following in the form:
class SomeForm(forms.Form)
...
HEAR_ABOUT_US = (
'Celebrant',
'brochure about us',
'funeral director',
'facebook page or post',
'medical or social worker',
'priest, pastor or minister',
'friend or family member',
'other...',
)
...
hear_about = forms.CharField(label='Where did you hear about us?', max_length=64, required=False,
widget=ListTextWidget(name='hear_about', data_list=HEAR_ABOUT_US),
help_text='Please let us know how you heard about us (press down or click arrow for options)')
...
And the widget, which could probably do with some improvement:
class ListTextWidget(forms.TextInput):
def __init__(self, name, data_list, *args, **kwargs):
super().__init__(*args, **kwargs)
self._name = name
self._list = data_list
self.attrs.update(list=f'list__{self._name}')
def render(self, name, value, attrs=None, renderer=None):
text_html = super(ListTextWidget, self).render(name, value, attrs=attrs)
data_list = f'<datalist id="list__{self._name}">'
for item in self._list:
data_list += f'<option value="{item}">'
data_list += '</datalist>'
return (text_html + data_list)
HTH, David