# Can't change type attribute in django-crispy-forms

**URL:** <https://forum.djangoproject.com/t/cant-change-type-attribute-in-django-crispy-forms/10054>\
**Category:** Using Django\
**Created:** [October 10, 2021, 1:32pm UTC](https://forum.djangoproject.com/t/cant-change-type-attribute-in-django-crispy-forms/10054 "2021-10-10T13:32:19Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![Mr-Mistoffelees](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/mr-mistoffelees/32/5794_2.png) [@Mr-Mistoffelees](https://forum.djangoproject.com/u/Mr-Mistoffelees)\
**Post date:** [October 10, 2021, 1:32pm UTC](https://forum.djangoproject.com/t/cant-change-type-attribute-in-django-crispy-forms/10054/1 "2021-10-10T13:32:19Z")

</div>

Hi all,

I’m using django-crispy-forms with the crispy-bootstrap5 package. (As far as I know, I need the latter one for using the newest bootstrap version 5. If the impression I gained from some google results is wrong - or there is any other best practice -, please let me know.)

I’m not able to change the type-attribute from text to e.g. date or range in the following scenario:

**views.py**

```auto
class PresentationForm(ModelForm):
    class Meta:
        model = PreviewEntry
        fields = ["name", "first_day", "second_day", "starttime", "endtime"]
    @property
    def helper(self):
        helper = FormHelper()
        helper.layout = Layout(
            Field('name', wrapper_class='mt-3 row'),
# =====> type='date' is later rendered as type='text' 
            Field('first_day', wrapper_class='mt-3 row', type='date'),
            Field('second_day', wrapper_class='mt-3 row', type='date'),
               # starttime and endtime are left out

class CreateEntry(generic.CreateView):
    model = PreviewEntry
    template_name = "mytemplate.html"
    form_class = PresentationForm
    success_url = 'success.html'

```

settings.py:

```auto
INSTALLED_APPS = [
...
    'crispy_forms',
    'crispy_bootstrap5',
]

CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5"
CRISPY_TEMPLATE_PACK = "bootstrap5"

```

mytemplate.html

```auto
{% extends base.html %}
{% block content %}
    {% crispy form %}
{% endblock %}

```

This works perfectly except of the fact that the type-field of my “first\_day” and “second\_day” element are rendered as type=‘text’ instead of type=‘date’ (where the browser would provide a datepicker).

```auto
<input type="text" name="first_day" class="dateinput form-control" required="" id="id_first_day">

```

Later in the form I would like to use type=“range”. This is also not possible.

Of course I could do something like this:

```auto
helper.layout = Layout(

...

HTML('''
        <div id="div_id_starttime" class="mb-3 row">
            <label for="id_starttime" class="form-label col-4 requiredField">Starttime<span class="asteriskField"></span> </label>
            <div class="col-8">
                <input class="col-10" name="starttime" id="id_starttime" type="range" value="8" min="0" max="24" oninput="this.nextElementSibling.value = this.value + ' Uhr' ">
                <output>8 Uhr</output>
            </div>
        </div>
        '''),
)
...

```

This approach works really fine. But I doubt that there isn’t a better way to do.

Any ideas on what is best practice to change the type in a crispy-form? Already searched the documentation [2] but didn’t find anything about that.

[1] [crispy-bootstrap5 · PyPI](https://pypi.org/project/crispy-bootstrap5/)  
[2] [Search — django-crispy-forms 1.11.1 documentation](https://django-crispy-forms.readthedocs.io/en/latest/search.html?q=type&check_keywords=yes&area=default)

---

<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:** [October 10, 2021, 11:54pm UTC](https://forum.djangoproject.com/t/cant-change-type-attribute-in-django-crispy-forms/10054/2 "2021-10-10T23:54:03Z")

</div>

There are a couple thoughts that come to mind, I’m not sure any are “optimal” or “best” or even “good”.

- The crispy Field class renders the `type` attribute from the `input_type` attribute of the instance of the `Field` object. So you could subclass `Field` to create a crispy `DateField` class with the desired `input_type` attribute.

- Specify the widget for the field, setting the ‘type’ in the attrs for that widget.

- Create your own template that overrides the base system template allowing for a separate setting to set the type attribute in the input tag.

---

<div class="post-metadata">

**Author:** ![Jonathan-Adly](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/jonathan-adly/32/6012_2.png) [@Jonathan-Adly](https://forum.djangoproject.com/u/Jonathan-Adly)\
**Post date:** [October 10, 2021, 11:55pm UTC](https://forum.djangoproject.com/t/cant-change-type-attribute-in-django-crispy-forms/10054/3 "2021-10-10T23:55:40Z")

</div>

I am not sure I understood the questions directly. I am answering assuming you just want to have a datepicker on your forms. If that’s the case, here is how I do my datepickers.

```auto
from django import forms
from django.forms import ModelForm

class DateInput(forms.DateInput):
    input_type = "date"

class PresentationForm(forms.ModelForm):
     class Meta:
           model = PreviewEntry
           fields = ["name", "first_day", "second_day", "starttime", "endtime"]
            widgets = {
            "first_day": DateInput(),
            "second_day" : DateInput()
}

```

Hopefully that helps!

---

<div class="post-metadata">

**Author:** ![Mr-Mistoffelees](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/mr-mistoffelees/32/5794_2.png) [@Mr-Mistoffelees](https://forum.djangoproject.com/u/Mr-Mistoffelees)\
**Post date:** [October 11, 2021, 9:46am UTC](https://forum.djangoproject.com/t/cant-change-type-attribute-in-django-crispy-forms/10054/4 "2021-10-11T09:46:00Z")

</div>

@KenWhitesell Argh. I already got that feeling that there isn’t an easy one-minute approach available. 😃 Thanks a lot (again!) for your input. Option 1 and Option 2 sound pretty interesting to me.

@Jonathan-Adly Thanks for your answer. I would like to have a datepicker and a range in my form. Also I would like to let crispy render my form, by using the “helper” function in the PresentationForm(ModelForm).  
Your solution works fine for me if I don’t use crispy and solely create my form using “fields = []”. But when I use “form\_class” instead of “fields” (to reference to my PresentationForm(ModelForm) for using all those handy crispy stuff) I don’t see a possibility to use the DateInput object. That’s possibly the case because I missed something. So if there is any option to integrate the DateInput object in my ModelForm, I would appreciate the broad hint. 🙂

Thanks and BR

---

<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:** [October 11, 2021, 11:52am UTC](https://forum.djangoproject.com/t/cant-change-type-attribute-in-django-crispy-forms/10054/5 "2021-10-11T11:52:26Z")

</div>

@Jonathan-Adly has effectively implemented my second option. It should work for you. Your reference to the `form_class` in the CBV doesn’t alter his solution.

He’s showing the change necessary to your PresentationForm to use the custom `DateInput` field defined immediately before it. (Phyically - you add his DateInput class just before your PresentationForm class.)

---

<div class="post-metadata">

**Author:** ![Mr-Mistoffelees](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/mr-mistoffelees/32/5794_2.png) [@Mr-Mistoffelees](https://forum.djangoproject.com/u/Mr-Mistoffelees)\
**Post date:** [October 11, 2021, 12:06pm UTC](https://forum.djangoproject.com/t/cant-change-type-attribute-in-django-crispy-forms/10054/6 "2021-10-11T12:06:48Z")

</div>

Arg! Sorry, I just didn’t get it… 🙄

Thanks @Jonathan-Adly and @KenWhitesell for your great support. The solution proposed by @Jonathan-Adly works perfectly well. Will re-read the widget’s documentation… 🙂

---

<div class="post-metadata">

**Author:** ![Mr-Mistoffelees](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/mr-mistoffelees/32/5794_2.png) [@Mr-Mistoffelees](https://forum.djangoproject.com/u/Mr-Mistoffelees)\
**Post date:** [October 11, 2021, 4:17pm UTC](https://forum.djangoproject.com/t/cant-change-type-attribute-in-django-crispy-forms/10054/7 "2021-10-11T16:17:58Z")

</div>

Just a short status update:

The main issue regarding “date” was solved.

My issue regarding the _type=“range”_ can’t be fixed that easy. Everything works fine with the HTML workaround and probably I will use no. 3 of @KenWhitesell 's idea to create an own template for that single case, but I was curious how this could be solved using idea no. 1, by subclassing the Field to create a crispy RangeField class with the desired attribute.

If anynoe is interested in helping, this would be very much appreciated (just spent about three hours trying to solve this by myself…). Just wanted to say: Everything works and this is just for my personal curiosity. 🙂

**The issue**  
I cannot overwrite the default “class” attribute “textinput textInput form-control” with the attribute “col-10”, so the range button looks really ugly.

What I would like to receive:  
`<input type="range" name="starttime" class="col-10" input_type="range" required="" id="id_starttime">`

What I receive:  
`<input type="range" name="starttime" class="col-10 textinput textInput form-control" input_type="range" required="" id="id_starttime">`

views.py:

```auto
    class Meta:
        model = PreviewCampaign
        fields = [""first_day", "last_day", "starttime", "endtime",]
        widgets = {
            "first_day": DateInput(),
            "last_day": DateInput(),
            "starttime": forms.TextInput(attrs={'type': 'range', 'class': 'col-10'})
<!== =======> Also doesn't work: ==>
            "starttime": forms.TextInput(attrs={'type': 'range', 'css_class': 'col-10'})
...

```

So I searched for the Field Instance and found it here [1]. Also had a lookt at the source code [2]. Overwriting wouldn’t be an issue, but I cannot find the code where the “css\_class” attribute is specified. So just wondering what I’ve overseen 😕

[1] [layout — django-crispy-forms 1.11.1 documentation](https://django-crispy-forms.readthedocs.io/en/latest/_modules/layout.html#Field)  
[2] [GitHub - django-crispy-forms/django-crispy-forms: The best way to have DRY Django forms. The app provides a tag and filter that lets you quickly render forms in a div format while providing an enormous amount of capability to configure and control the rendered HTML.](https://github.com/django-crispy-forms/django-crispy-forms)

---

<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:** [October 11, 2021, 4:40pm UTC](https://forum.djangoproject.com/t/cant-change-type-attribute-in-django-crispy-forms/10054/8 "2021-10-11T16:40:29Z")

</div>

> [@Mr-Mistoffelees](#):
>
> `<input type="range" name="starttime" class="col-10" input_type="range" required="" id="id_starttime">`
> 
> What I receive:  
> `<input type="range" name="starttime" class="col-10 textinput textInput form-control" input_type="range" required="" id="id_starttime">`

I don’t understand the problem here - you’re getting `col-10` as one of the css classes, which is what you’re asking for.

Ahh, ok, you’ve got the issue where you _don’t_ want the Bootstrap / Crispy css classes to be added.

Don’t have any immediate solutions at my fingertips right now, but I know there are multiple solutions for this.  
But first, what is the issue with what you’re getting? You’re describing it as “really ugly”, but what does that translate to?

---

<div class="post-metadata">

**Author:** ![Mr-Mistoffelees](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/mr-mistoffelees/32/5794_2.png) [@Mr-Mistoffelees](https://forum.djangoproject.com/u/Mr-Mistoffelees)\
**Post date:** [October 11, 2021, 7:44pm UTC](https://forum.djangoproject.com/t/cant-change-type-attribute-in-django-crispy-forms/10054/9 "2021-10-11T19:44:43Z")

</div>

This is how it should look, if class= “col-10”  
 ![with](https://us1.discourse-cdn.com/flex026/uploads/djangoproject/original/2X/3/342ff6ddb18bdfb7db9840e419c74daccd951f61.png)

And this is how it looks like if class=" `col-10 textinput textInput form-control`"  
 ![without](https://us1.discourse-cdn.com/flex026/uploads/djangoproject/original/2X/b/b2f3ee35e1129bf75dfa9eae26f9c725a54b9acc.png)

---

<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:** [October 12, 2021, 12:03am UTC](https://forum.djangoproject.com/t/cant-change-type-attribute-in-django-crispy-forms/10054/10 "2021-10-12T00:03:37Z")

</div>

I can’t recreate the image you’re showing.

My only suggestion for this would be to look at the styling being applied in your browser’s developer tools to see exactly what element is creating the problem. Once you’ve done that, you can override it in your css.

---

<div class="post-metadata">

**Author:** ![Mr-Mistoffelees](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/mr-mistoffelees/32/5794_2.png) [@Mr-Mistoffelees](https://forum.djangoproject.com/u/Mr-Mistoffelees)\
**Post date:** [October 13, 2021, 10:44am UTC](https://forum.djangoproject.com/t/cant-change-type-attribute-in-django-crispy-forms/10054/11 "2021-10-13T10:44:06Z")

</div>

@KenWhitesell Thanks a lot for your time. I had a look at the attributes in the developer tools. The “form-control” attribute is the one that changes the look of the range-slider and makes it look ugly.

**BUT:**  
I spent two evenings trying to understand widgets and writing my first own widget. 3/4th of the time was spent for unsuccessfully overwriting methods of the `forms.Widget` class, before realizing that the code I used from stackoverflow as an inspiration was totally useless.

**So:**  
Here us the code of my first widget that renders a range slider. It works fine. Feedback is of course appreciated. 🙂

views.py:

```auto
class MyWidget(forms.Widget):
    template_name = 'myprojectpath/widgets/testwidget.html'

class PresentationForm(ModelForm):

    class Meta:
        model = MyModel
        fields = [""first_day", "last_day", "starttime", "endtime"]
        widgets = {
            "first_day": DateInput(),
            "last_day": DateInput(),
            "starttime": MyWidget(attrs={'min': 0, 'max': 24, 'def_value': 8, 'unit': 'Uhr'})
        }
    @property
    def helper(self):
        helper = FormHelper()
        helper.layout = Layout(
            ...
            Field(starttime)
            ...

...

    class CreateMyView(generic.CreateView):
        model = MyModel
        template_name = "template.html"
        form_class = PresentationForm
        success_url = 'success.html'

```

testwidget.html

```auto
        <input class="col-10" name="{{widget.name}}" id="id_{{ widget.name }}"
               type="range"
            {% if 'defvalue' in widget.attrs %}
            value="{{ widget.attrs.defvalue }}"
            {% endif %}

               min="{{ widget.attrs.min }}"
               max="{{ widget.attrs.max }}"
               oninput="this.nextElementSibling.value = this.value
               {% if 'unit' in widget.attrs %}
               + ' ' + ' {{widget.attrs.unit}} '
               {% endif %}
                " >
        <output>{{ widget.attrs.defvalue }}
            {% if 'unit' in widget.attrs %}
            {{widget.attrs.unit}}
            {% endif %}
        </output>

```

---

<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:** [October 13, 2021, 11:57am UTC](https://forum.djangoproject.com/t/cant-change-type-attribute-in-django-crispy-forms/10054/12 "2021-10-13T11:57:43Z")

</div>

That’s certainly the more direct, flexible, and probably “appropriate” solution.

I had a different solution in mind.

Note: the following is untried - just something I’m winging off-hand.

My first attempt to fix this would be to add something like this to my css file:

```auto
input[type=range].form-control {
    attribute: setting;
}

```

This would be a high-priority selector that I believe would override a selector just based on css class, and you can then reset whatever attribute(s) is being set by the form-control class that is causing the problem.

---

<div class="post-metadata">

**Author:** ![Mr-Mistoffelees](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/mr-mistoffelees/32/5794_2.png) [@Mr-Mistoffelees](https://forum.djangoproject.com/u/Mr-Mistoffelees)\
**Post date:** [October 13, 2021, 12:24pm UTC](https://forum.djangoproject.com/t/cant-change-type-attribute-in-django-crispy-forms/10054/13 "2021-10-13T12:24:46Z")

</div>

Just tried it out.

```auto
input[type=range].form-control {
    appearance: auto;
}

```

also works fine. Thanks! 🙂

* * *

P.S. / Update: Just trying around: Then I would also need to add the “5 o’clock” behind the … part. Not sure if there is a nice and easy solution for that one.
