# Implementing a Datalist

**URL:** <https://forum.djangoproject.com/t/implementing-a-datalist/2052>\
**Category:** Templates & Frontend\
**Created:** [April 20, 2020, 5:22pm UTC](https://forum.djangoproject.com/t/implementing-a-datalist/2052 "2020-04-20T17:22:42Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![ChimeraBlack1](https://avatars.discourse-cdn.com/v4/letter/c/439d5e/32.png) [@ChimeraBlack1](https://forum.djangoproject.com/u/ChimeraBlack1)\
**Post date:** [April 20, 2020, 5:22pm UTC](https://forum.djangoproject.com/t/implementing-a-datalist/2052/1 "2020-04-20T17:22:42Z")

</div>

Hi There,

I’m having trouble implementing a datalist using forms in django. It’s very confusing and I can’t seem to figure out how to do it. Seems like it should be the type of thing that takes 5 minutes. Any idea why I can’t seem to use this basic HTML5 element?

Thanks,

Chris.

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [April 20, 2020, 5:34pm UTC](https://forum.djangoproject.com/t/implementing-a-datalist/2052/2 "2020-04-20T17:34:10Z")

</div>

It looks like you could use this by creating a [custom widget](https://docs.djangoproject.com/en/3.0/ref/forms/widgets/#module-django.forms.widgets) that would use that html element when rendering the field. This will likely involve creating a custom template to use when rendering that widget.

---

<div class="post-metadata">

**Author:** ![ChimeraBlack1](https://avatars.discourse-cdn.com/v4/letter/c/439d5e/32.png) [@ChimeraBlack1](https://forum.djangoproject.com/u/ChimeraBlack1)\
**Post date:** [April 20, 2020, 5:57pm UTC](https://forum.djangoproject.com/t/implementing-a-datalist/2052/3 "2020-04-20T17:57:44Z")

</div>

This doesn’t work because there is no forms.DataList

---

<div class="post-metadata">

**Author:** ![ChimeraBlack1](https://avatars.discourse-cdn.com/v4/letter/c/439d5e/32.png) [@ChimeraBlack1](https://forum.djangoproject.com/u/ChimeraBlack1)\
**Post date:** [April 20, 2020, 6:01pm UTC](https://forum.djangoproject.com/t/implementing-a-datalist/2052/5 "2020-04-20T18:01:50Z")

</div>

I don’t understand how they built this…There’s a list of built in widgets and datalist isn’t one of them. Is there no way to create a custom widget and tell it what HTML5 element I want, and have it try to render that?

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [April 20, 2020, 6:53pm UTC](https://forum.djangoproject.com/t/implementing-a-datalist/2052/6 "2020-04-20T18:53:41Z")

</div>

Yes, that’s exactly what you want to do - create a custom widget with a template that uses datalist.

First, read about [specifying widgets](https://docs.djangoproject.com/en/3.0/ref/forms/widgets/#specifying-widgets). Notice how the widget is a parameter in the form field definition, and refers to a class. Since it’s just a class, you could write your own class and use it, instead.

Now, if you read about [Widget](https://docs.djangoproject.com/en/3.0/ref/forms/widgets/#base-widget-classes), you’ll see how classes inheriting from the base Widget class have a method named [get\_context](https://docs.djangoproject.com/en/3.0/ref/forms/widgets/#django.forms.Widget.get_context). The get\_context dictionary identifies that there’s a key in that dictionary named template\_name, which identifies the name of the template to be used to render that widget.

So from reading this, it appears to me like you have two similar options for replacing the template name on a widget by creating a subclass of the Select widget. You could either just create your subclass and define a new value for the self.template\_name attribute in your **init** method, or you could create a get\_context method in your subclass that replaces the value of template\_name within the context. (IMO, the first is easier, the second is more flexible - really depends upon your needs for further customization.) Both allow you to specific your own template to use to render your field. I would then look at the standard template to get some ideas as to how to code your template - perhaps even just copying it to replace the parts you need replaced.

Just a couple notes to keep in mind:

- Django is just python. All the facilities that exist within python are available to you. So it’s all just code that can be modified / replaced as needed.
- Django is designed to be extended / enhanced / modified. In most cases, anytime you want to change how something behaves, you can pretty much expect there to be a ‘hook’ or connection point for you to make your modifications.

---

<div class="post-metadata">

**Author:** ![ChimeraBlack1](https://avatars.discourse-cdn.com/v4/letter/c/439d5e/32.png) [@ChimeraBlack1](https://forum.djangoproject.com/u/ChimeraBlack1)\
**Post date:** [April 20, 2020, 7:46pm UTC](https://forum.djangoproject.com/t/implementing-a-datalist/2052/8 "2020-04-20T19:46:27Z")

</div>

Could you show me an example? I’m totally boggled by what you’re saying.

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [April 20, 2020, 7:53pm UTC](https://forum.djangoproject.com/t/implementing-a-datalist/2052/9 "2020-04-20T19:53:35Z")

</div>

The best examples are the Django source code itself, browsable at [github](https://github.com/django/django/tree/master/django)

In particular, I’d like to point your attention to the system provided widgets for [Input](https://github.com/django/django/blob/505fec6badba0622bbf97bb659188c3d62a9bc58/django/forms/widgets.py#L279) and [TextInput](https://github.com/django/django/blob/505fec6badba0622bbf97bb659188c3d62a9bc58/django/forms/widgets.py#L298). Notice how TextInput extends the Input class.

---

<div class="post-metadata">

**Author:** ![ChimeraBlack1](https://avatars.discourse-cdn.com/v4/letter/c/439d5e/32.png) [@ChimeraBlack1](https://forum.djangoproject.com/u/ChimeraBlack1)\
**Post date:** [April 20, 2020, 8:19pm UTC](https://forum.djangoproject.com/t/implementing-a-datalist/2052/11 "2020-04-20T20:19:38Z")

</div>

I tried to interpret what you said, and this is what I can understand you asking me to do:

```auto
class mySubclass(forms.Form):
    def __init__ (self, template_name):
        self.template_name = template_name

class CommentForm(forms.Form):
    name = forms.CharField()
    url = forms.URLField()
    comment = forms.CharField(widget=mySubclass("datalist"))

```

but I am getting the error: TypeError: **init** () missing 1 required positional argument: ‘template\_name’

Do you know what I’m doing wrong?

Thanks.

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [April 20, 2020, 8:23pm UTC](https://forum.djangoproject.com/t/implementing-a-datalist/2052/12 "2020-04-20T20:23:10Z")

</div>

Ok, you’re off to a good start. But yes, there are a couple things to improve.

- Your mySubclass should be a subclass of a widget, not a form.

- Did you look at the TextInput class I referenced in a previous reply? Reading and understanding what it is doing, should address the specific error you’ve listed.

---

<div class="post-metadata">

**Author:** ![ChimeraBlack1](https://avatars.discourse-cdn.com/v4/letter/c/439d5e/32.png) [@ChimeraBlack1](https://forum.djangoproject.com/u/ChimeraBlack1)\
**Post date:** [April 20, 2020, 8:35pm UTC](https://forum.djangoproject.com/t/implementing-a-datalist/2052/13 "2020-04-20T20:35:15Z")

</div>

How would I subclass a widget? I can’t see how to import Widget or Input or any of those classes from Django.

And yes I read the TextInput link you sent. It seems to be a class that sets two variables, “input\_type” to ‘text’ and “template\_name” to a django template.

I’m still not seeing the connection on how this creates a datalist in the end.

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [April 20, 2020, 8:45pm UTC](https://forum.djangoproject.com/t/implementing-a-datalist/2052/14 "2020-04-20T20:45:55Z")

</div>

Importing a widget - no different than importing any other class. You use the import statement with the module structure being the path to the appropriate file:

```
from django.forms.widgets import Input

```

The template\_name is the name of the template to render for your widget. You’ll need to create your own template. You can start by looking at the Django-provided [select widget](https://github.com/django/django/blob/master/django/forms/templates/django/forms/widgets/select.html) which contains an html select element - which is what I believe you want to replace with the datalist element .

---

<div class="post-metadata">

**Author:** ![ChimeraBlack1](https://avatars.discourse-cdn.com/v4/letter/c/439d5e/32.png) [@ChimeraBlack1](https://forum.djangoproject.com/u/ChimeraBlack1)\
**Post date:** [April 20, 2020, 9:03pm UTC](https://forum.djangoproject.com/t/implementing-a-datalist/2052/16 "2020-04-20T21:03:28Z")

</div>

OK, so I did that and just straight copied their TextInput subclass, and the server crashes. I get the error:

‘mySubclass’ object has no attribute ‘attrs’

```auto
class mySubclass(Input):
    input_type = 'text'
    template_name ="django/forms/widgets/text.html"

```

Any idea? I’m not sure where it got the idea it needs attrs, or even where that series of letters comes from whatsoever.

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [April 20, 2020, 9:06pm UTC](https://forum.djangoproject.com/t/implementing-a-datalist/2052/17 "2020-04-20T21:06:14Z")

</div>

What’s the code that’s actually trying to use the widget?

If it’s what you posted above:

```auto
class CommentForm(forms.Form):
    name = forms.CharField()
    url = forms.URLField()
    comment = forms.CharField(widget=mySubclass("datalist"))

```

Then your comment field isn’t correct. Notice that the [widget parameter](https://docs.djangoproject.com/en/3.0/topics/forms/#widgets) is looking for a class, not an instance of a class.

---

<div class="post-metadata">

**Author:** ![ChimeraBlack1](https://avatars.discourse-cdn.com/v4/letter/c/439d5e/32.png) [@ChimeraBlack1](https://forum.djangoproject.com/u/ChimeraBlack1)\
**Post date:** [April 20, 2020, 9:12pm UTC](https://forum.djangoproject.com/t/implementing-a-datalist/2052/19 "2020-04-20T21:12:07Z")

</div>

Yah that’s the part trying to use it, but it doesn’t even get that far. It gives me an error on an exact copy of their subclass.

```auto
class mySubclass(Input):
    input_type = 'text'
    template_name ="django/forms/widgets/text.html"

class CommentForm(forms.Form):
    name = forms.CharField()
    url = forms.URLField()
    comment = forms.CharField(widget=mySubclass)

```

error:

```auto
venv\lib\site-packages\django\forms\widgets.py", line 205, in __deepcopy__
    obj.attrs = self.attrs.copy()
AttributeError: 'mySubclass' object has no attribute 'attrs'

```

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [April 20, 2020, 9:22pm UTC](https://forum.djangoproject.com/t/implementing-a-datalist/2052/20 "2020-04-20T21:22:45Z")

</div>

Interesting. I can do the following from the shell:

```auto
>>> class myI(Input):
... input_type = 'text'
... template_name = 'django/forms/widgets/text.html'
...
>>> m = myI()
>>> m.render("x", "y")
'<input type="text" name="x" value="y">'

>>>
>>> class CF(forms.Form):
... name = forms.CharField()
... comment = forms.CharField(widget=myI)
...

>>> cf = CF()
>>> cf.as_p()
'<p><label for="id_name">Name:</label> <input type="text" name="name" required id="id_name"></p>\n<p><label for="id_comment">Comment:</label> <input type="text" name="comment" required id="id_comment"></p>'
>>>

```

Don’t know why you’re getting that error. Other classes are inheriting from Input without doing anything special.

However, you could try:

```auto
class mySubclass(Input):
    input_type = 'text'
    template_name = 'django/forms/widgets/text.html'

    def __init__ (self, attrs=None):
        super(). __init__ (attrs)

```

That will at least ensure that your class has an attrs attribute.

---

<div class="post-metadata">

**Author:** ![ChimeraBlack1](https://avatars.discourse-cdn.com/v4/letter/c/439d5e/32.png) [@ChimeraBlack1](https://forum.djangoproject.com/u/ChimeraBlack1)\
**Post date:** [April 20, 2020, 9:50pm UTC](https://forum.djangoproject.com/t/implementing-a-datalist/2052/22 "2020-04-20T21:50:27Z")

</div>

OK sweet, got that part working without the need for the “attrs” attribute. Seems I just needed to manually stop and restart the server. I feel like I’m getting close now. Thanks for all your help on this by the way! 4 hours so far! WOW! amazing!

So now I’ve copied the code from the select widget as you suggested, and it looks like this after modification:

```auto
<datalist name="{{ widget.name }}"{% include "django/forms/widgets/attrs.html" %}>{% for group_name, group_choices, group_index in widget.optgroups %}{% if group_name %}
    <optgroup label="{{ group_name }}">{% endif %}{% for option in group_choices %}
    {% include option.template_name with widget=option %}{% endfor %}{% if group_name %}
    </optgroup>{% endif %}{% endfor %}
</datalist>

```

I’m pretty sure I still need to change that “django/forms/widgets/attrs.html” to something, but I’m not sure what. And right now, I’ve got another issue locating the template.

my template dirs looks like this:

```auto
'DIRS': [os.path.join(BASE_DIR, 'templates')],

```

So I have my templates for my apps on the same level as the manage.py file and the other apps.  
I put the copied template code from above into “templates/forms/datalist.html”. I also modified mySubclass to be:

```auto
class mySubclass(Input):
    input_type = 'text'
    template_name ="forms/datalist.html"

```

But now I’m getting the error:

```auto
venv\lib\site-packages\django\template\backends\django.py", line 84, in reraise
    raise new from exc
django.template.exceptions.TemplateDoesNotExist: forms/datalist.html

```

Any idea what I might be doing wrong?

Thanks again!

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [April 20, 2020, 10:10pm UTC](https://forum.djangoproject.com/t/implementing-a-datalist/2052/23 "2020-04-20T22:10:27Z")

</div>

You probably don’t need to change the reference to the attrs.html template. It’s a pre-existing hook for supplying custom attributed to the html element. That can stay the same.

I’d start by looking at how you’re referencing other templates in your app to see what directories you’re using and how you’re using them in your code. (I organize my templates differently - I use the pattern of having a templates directory in each app. But this is one topic that _always_ trips me up.)

So I dug up one of my functional settings files, the templates section looks like this:

```auto
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': ['templates',
                 ],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
                'menu.context_processors.menu',
            ],
        },
    },
]

```

This looks for my template files in:

```auto
 <projectname>/<appname>/templates/<appname>

```

So if I have two apps named reports and work in a project named fmc, then the templates are stored in:

```
fmc/reports/templates/reports/

```

and

```
fmc/work/templates/work/
```

---

<div class="post-metadata">

**Author:** ![ppittavi](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/ppittavi/32/9317_2.png) [@ppittavi](https://forum.djangoproject.com/u/ppittavi)\
**Post date:** [July 18, 2022, 12:26pm UTC](https://forum.djangoproject.com/t/implementing-a-datalist/2052/24 "2022-07-18T12:26:59Z")

</div>

I did it simply using a choiche field and overriding the template directly in form class. It seems to work:

```auto
class Customers(forms.Form):
    CUSTOMER_CHOICES = (
        (None, ""),
        (1, "Customer A"),
        (2, "Customer B"),
        (3, "Customer C"),
        (4, "Customer D"),
        (5, "Customer E"),
    )
    customer = forms.ChoiceField(
                   choices = CUSTOMER_CHOICES,
                   coerce = str,
                   required=False
                  )
    customer.widget.template_name = 'widgets/datalist.html'

```

for the widget template i started from select widget template:

```auto
 <input list="{{ widget.name }}s" name="{{ widget.name }}"{% include "django/forms/widgets/attrs.html" %}>
 <datalist id="{{ widget.name }}s">
	 {% for group_name, group_choices, group_index in widget.optgroups %}{% if group_name %}
	   <optgroup label="{{ group_name }}">{% endif %}{% for option in group_choices %}
	   {% include option.template_name with widget=option %}{% endfor %}{% if group_name %}
	   </optgroup>{% endif %}{% endfor %}
 </datalist>

```

To be able to override widgets template You need to install “django.forms” as app in your settings and set variable:  
FORM\_RENDERER = ‘django.forms.renderers.TemplatesSetting’

---

<div class="post-metadata">

**Author:** ![xcixor](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/xcixor/32/10097_2.png) [@xcixor](https://forum.djangoproject.com/u/xcixor)\
**Post date:** [September 23, 2022, 11:03am UTC](https://forum.djangoproject.com/t/implementing-a-datalist/2052/25 "2022-09-23T11:03:29Z")

</div>

How do fix the error with free text “Select a valid choice. That choice is not one of the available choices”

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [September 23, 2022, 12:43pm UTC](https://forum.djangoproject.com/t/implementing-a-datalist/2052/26 "2022-09-23T12:43:40Z")

</div>

I suggest you open a new topic for this, including all the relevent code.
