4

EDIT The reason my question is different to the possible duplicate is because that does not address the issue of making it non manditory while also removing the default option "-------"

I want to make a RadioSelect survey question non mandatory in a forms.ModelForm

To use RadioSelect I am adding the widget in my ModelForm (below) as Djangos model does not provide a RadioSelect or Select widget.

The standard way of doing this is to pass Blank=True as an argument. However as I found out in another question I asked it turns out that if you pass blank=True as an argument from models.CharField to the forms.RadioSelect widget it will leave the default option "-------" in place even if you use default=None.

I have to remove the default option "-------".

So how do I make the RadioSelect questions non mandatory while also not including the default option "-------"?

Thanks

forms.py

class SurveyFormB(forms.ModelForm): 

    class Meta:
        model = Person
        fields = ['internet_usage', 'smart_phone_ownership', 'smart_phone_usage']        

        widgets = {'internet_usage' : forms.RadioSelect,
                   'smart_phone_ownership' : forms.Select,
                   'smart_phone_usage' : forms.RadioSelect,
                   }

models.py

#How often do you use the Internet?  
INTERNET_LESS_THAN_ONE_HOUR_A_DAY = 'Less than one hour per day'
INTERNET_ONE_TO_TWO_HOURS_A_DAY = '1 - 2 hours per day'
INTERNET_TWO_TO_FOUR_HOURS_A_DAY = '2 - 4 hours per day'
INTERNET_FOUR_TO_SIX_HOURS_A_DAY = '4 - 6 hours per day'
INTERNET_SIX_TO_EIGHT_HOURS_A_DAY = '6 - 8 hours per day'
INTERNET_EIGHT_PLUS_HOURS_A_DAY = '8 + hours per day'

INTERNET_USAGE = (
    (INTERNET_LESS_THAN_ONE_HOUR_A_DAY, 'Less than one hour a day'),
    (INTERNET_ONE_TO_TWO_HOURS_A_DAY, '1 - 2 hours a day'),
    (INTERNET_TWO_TO_FOUR_HOURS_A_DAY, '2 - 4 hours a day'),
    (INTERNET_FOUR_TO_SIX_HOURS_A_DAY, '4 - 6 hours a Day'),
    (INTERNET_SIX_TO_EIGHT_HOURS_A_DAY, '6 - 8 hours a day'),
    (INTERNET_EIGHT_PLUS_HOURS_A_DAY, '8 + hours a day'),
           )

internet_usage = models.CharField(null=True, max_length=100, default=None, choices=INTERNET_USAGE, verbose_name='How long do you spend on the Internet each day?')
Community
  • 1
  • 1
Deepend
  • 4,057
  • 17
  • 60
  • 101
  • 1
    Food for thought, your way of creating choice `INTERNET_USAGE` is not ideal. Firstly, the tuple has same value and still has string defined twice and also `The first element in each tuple is the actual value to be set on the model, and the second element is the human-readable name.` – Nagaraj Tantri May 13 '15 at 15:22
  • Thanks, I am constantly trying to improve this. Im not really a 100% sure what you mean, can you give an example of one row please? – Deepend May 13 '15 at 16:00
  • 1
    Sure, think of it like this: `INTERNET_USAGE = ( ('One', 'Less than one hour a day'), ('Two', '1 - 2 hours a day'), ('Three', '2 - 4 hours a day'),......)` Now when you get the value as `One` it means the first, `Two` second option selected and so on. – Nagaraj Tantri May 13 '15 at 16:20
  • So with this solution I can remove the first few lines e.g. `INTERNET_LESS_THAN_ONE_HOUR_A_DAY = 'Less than one hour per day'` ? That would massively reduce my code. – Deepend May 13 '15 at 16:46
  • possible duplicate of [How to get rid of the bogus choice generated by RadioSelect of Django Form](http://stackoverflow.com/questions/5824037/how-to-get-rid-of-the-bogus-choice-generated-by-radioselect-of-django-form) – Nagaraj Tantri May 13 '15 at 17:04
  • Try the answer by NickJ in http://stackoverflow.com/questions/5824037/how-to-get-rid-of-the-bogus-choice-generated-by-radioselect-of-django-form – Nagaraj Tantri May 13 '15 at 17:04
  • I am looking at that answer, Its unclear where he adds the new widget he created. I have tried putting it in my models.py and forms.py but with no luck. any suggestions? – Deepend May 13 '15 at 17:45
  • 1
    Could you show what have you added, that is not working? Because it can be added anywhere, but only ensure that, `widgets = {'internet_usage' : forms.RadioSelect, ...` is changed to `widgets = {'internet_usage' : RadioSelectNotNull, ...` Ensure you have the correct import statements – Nagaraj Tantri May 14 '15 at 05:00
  • This worked perfectly once I changed the `forms.RadioSelect` to `RadioSelectNotNull` Thanks so much for the help and tips – Deepend May 14 '15 at 19:00
  • So you want me to write an answer for this or would you be willing to close the question if you feel that its duplicate? :) – Nagaraj Tantri May 15 '15 at 02:38
  • I think it is sufficiently different that It might help someone else in future. Reference NickJs solution and highlight the non mandatory nature of the Q – Deepend May 15 '15 at 12:41

1 Answers1

3

Considering the answer by NickJ and use the RadioSelectNotNull as follows:

forms.py

from itertools import chain
from django.forms import RadioSelect
from django.utils.encoding import force_unicode

class RadioSelectNotNull(RadioSelect):

    def get_renderer(self, name, value, attrs=None, choices=()):
        """Returns an instance of the renderer."""
        if value is None: value = ''
        str_value = force_unicode(value) # Normalize to string.
        final_attrs = self.build_attrs(attrs)
        choices = list(chain(self.choices, choices))
        if choices[0][0] == '':
            choices.pop(0)
        return self.renderer(name, str_value, final_attrs, choices)


class SurveyFormB(forms.ModelForm): 

    class Meta:
        model = Person
        fields = ['internet_usage', 'smart_phone_ownership', 'smart_phone_usage']        

        widgets = {'internet_usage' : RadioSelectNotNull,
                   'smart_phone_ownership' : forms.Select,
                   'smart_phone_usage' : RadioSelectNotNull,
                   }

Do note, if you can also modify the choices field as:

models.py

INTERNET_USAGE = (
    ("One", 'Less than one hour a day'),
    ( "Two", '1 - 2 hours a day'),
    ( "Three", '2 - 4 hours a day'),
    ( "Four", '4 - 6 hours a Day'),
    ( "Five", '6 - 8 hours a day'),
    ( "Six", '8 + hours a day'),
)

internet_usage = models.CharField(null=True, max_length=100, default=None, choices=INTERNET_USAGE, verbose_name='How long do you spend on the Internet each day?')
Community
  • 1
  • 1
Nagaraj Tantri
  • 5,172
  • 12
  • 54
  • 78