11

While using Django modelforms I have a Integer field which is numeric only. But in the browser it comes as a text field in which I can enter "characters". I want to make this only "numeric". How to do this ? i.e. users should be able to enter only numbers.

We can do it 1 way by setting the attribute of the field.

1)

def __init__(self,*args,**kwargs):

        super(PropertyForm,self).__init__(*args, **kwargs)        
        self.fields['brokers_phone_number'].widget.attrs['type'] = "number"

This does not seem to work. I am using html 5 and the browser is Chrome. What am I doing wrong ? How can It be done better ?

Omkar Khair
  • 1,364
  • 2
  • 17
  • 40
Akash Deshpande
  • 2,583
  • 10
  • 41
  • 82

5 Answers5

22

Django 1.6 has a NumberInput Widget, but 1.6 is currently not stable.

But you could try something like this:

from django.forms import ModelForm, CharField, TextInput

class PropertyForm(ModelForm):

    brokers_phone_number = CharField( widget=TextInput(attrs={'type':'number'}))

    class Meta:
     ...
shry
  • 1,872
  • 16
  • 9
3

In the end I ended up using a jQuery based solution. Question here. Instead of adding type I added a class "number" and added jquery number validation on it. But this is a hackish solution, especially when we have html 5 "number" in place. If anyone finds a way to do this please answer.

In the form:

 def __init__(self,*args,**kwargs):
    super( PropertyFloorForm, self).__init__(*args, **kwargs)
    self.fields['number_of_units'].widget.attrs['class'] = "number"

In the template

$(document).ready(function() {
    $(".number").keydown(function(event) {
        // Allow: backspace, delete, tab, escape, and enter
        if (event.keyCode == 46 || event.keyCode == 8 || event.keyCode == 9 || event.keyCode == 27 || event.keyCode == 13 ||
            // Allow: Ctrl+A
            (event.keyCode == 65 && event.ctrlKey === true) ||
            // Allow: home, end, left, right
            (event.keyCode >= 35 && event.keyCode <= 39)) {
            // let it happen, don't do anything
            return;
        } else {
            // Ensure that it is a number and stop the keypress
            if (event.shiftKey || (event.keyCode < 48 || event.keyCode > 57) && (event.keyCode < 96 || event.keyCode > 105)) {
                event.preventDefault();
            }
        }
    });
});
Saeid
  • 4,147
  • 7
  • 27
  • 43
Akash Deshpande
  • 2,583
  • 10
  • 41
  • 82
  • clientside validation is only half-way, you should also validate serverside (clean methods of your form). – Jingo Sep 26 '13 at 10:37
  • Yes I am doing that. But My client has special requirements wherein he wants to be able to enter just numbers. – Akash Deshpande Sep 26 '13 at 10:54
2

Here is another solution:

  • Add validators in the model file
  • Add css class to fields in the model form
  • Use jquery to change type of the the above class to 'number' on document/page load

IN THE MODEL:

    exp_from = models.IntegerField(default=0,
        validators=[
            MaxValueValidator(100),
            MinValueValidator(0)
        ])

    exp_to = models.IntegerField(default=1,
        validators=[
            MaxValueValidator(100),
            MinValueValidator(1)
        ])

IN THE MODEL FORM - add a jquery class

self.fields['exp_from'].widget.attrs['class'] = "text_type_number"
self.fields['exp_to'].widget.attrs['class'] = "text_type_number"

IN THE HTML FILE/JS FILE

$(document).ready(function(){
   $('.text_type_number').attr('type', 'number');
});
Nav
  • 741
  • 1
  • 6
  • 12
1

I know this is a faily old thread, am adding this for posterity

To get around this issue save the following as html5type.py

from django import template
register = template.Library()
def html5type(var):
    if isinstance(var, int):
        return 'number'
    else:
        return 'text'  

register.filter('html5type', html5type)

Then, in template:

{% load html5type %}
<input type={{ field.value | html5type }} ></input>

Of course you can extend the html5type function further for other types

Caveat: Numeric fields need a default value for the above to work

1

Instead of RegexValidator, give validation in forms attributes only like...

class StaffDetailsForm(forms.ModelForm):
    number = forms.CharField(required=True,widget=forms.TextInput(attrs={'class':'form-control' , 'autocomplete': 'off','pattern':'[0-9]+', 'title':'Enter numbers Only '}))

and so on...

Else you will have to handle the error in views. It worked for me try this simple method... This will allow users to enter only Number only

HDJEMAI
  • 9,436
  • 46
  • 67
  • 93
Javed
  • 1,613
  • 17
  • 16