Django empty label in choice field - no queryset

2019-07-08 11:17发布

Setting the empty label for on a choice field is giving me some issues. I've looked at answers like this, but this is just talking about the form.

Suppose I have the following model:

class MyColorModel(models.Model):
    BLUE = 'blue'
    RED = 'red'
    GREEN = 'green'
    COLOR_CHOICES = (
        (BLUE, 'Blue'),
        (RED, 'Red'),
        (GREEN, 'Green'))

   my_color = models.CharField(max_length=5, choices=COLOR_CHOICES, blank=True)

And this form:

class MyColorForm(forms.ModelForm):
   class Meta:
       model = MyColorModel
       fields = ['mycolor']

By default, this will display a choice field, with the blank label set to ------

I've came up with the following options to set the label.

1) Change COLOR_CHOICES in my model to:

COLOR_CHOICES = (
    ('', '---Please select your color---'),
    (BLUE, 'Blue'),
    (RED, 'Red'),
    (GREEN, 'Green'),

2) Change COLOR_CHOICES in my model to:

COLOR_CHOICES = (
    (None, '---Please select your color---'),
    (BLUE, 'Blue'),
    (RED, 'Red'),
    (GREEN, 'Green'),

3) Add the following init method to my model form:

def __init__(*args, **kwargs):
    super(MyColorForm, self).__init__(*args, **kwargs)
    self.fields['my_color'].choices =  [('', '---Please select your color---')] + MyColorModel.COLOR_CHOICES

Options 1 led to some side effects where if statements that I had started failing, that's what led me to create option 2.

Is it fine adding the blank label to my model (option 2)? Any side effects if I add it there, or is it better to add it on the form? It just seems like quite a lot of code just to set the empty label when I do it in the form.

标签: django forms
2条回答
【Aperson】
2楼-- · 2019-07-08 11:49

Setting what you want on the form is a more correct way to do achieve what you want. In Django, models contain the essential fields and behaviors of the data you’re storing. That said, they define how your information is structured in the database.

1. I didn't check it, but your first option
COLOR_CHOICES = (
    ('', '---Please select your color---'),
    (BLUE, 'Blue'),
    (RED, 'Red'),
    (GREEN, 'Green'),

my_color = models.CharField(max_length=5, choices=COLOR_CHOICES)

might not work, as your first choice is an empty string, but your my_color field does not contain the blank=True argument. This means it won't allow saving the empty string to the database. But in case you want this field to be mandatory, then your definition of the empty choice should not be here, as it does not bring any added value as it does not hold any additional information regarding your data structure.

2. Your second option is definitely not the way to go [1]:

Avoid using null on string-based fields such as CharField and TextField because empty string values will always be stored as empty strings, not as NULL. If a string-based field has null=True, that means it has two possible values for “no data”: NULL, and the empty string. In most cases, it’s redundant to have two possible values for “no data;” the Django convention is to use the empty string, not NULL.

3. Your third option looks good. I didn't work for some time with django forms, but if your code works, the Form is a more suitable place to define how your form should look like than doing it in your models, so go for that option.

Or take a look at the solutions from the SO question linked in your post and implement those.

Good luck!

查看更多
我欲成王,谁敢阻挡
3楼-- · 2019-07-08 11:53

So you want to set empty_label for all model Forms, created from your? Adding an empty option in choices is fine, its even stated in the docs.

Unless blank=False is set on the field along with a default then a label containing "---------" will be rendered with the select box. To override this behavior, add a tuple to choices containing None; e.g. (None, 'Your String For Display'). Alternatively, you can use an empty string instead of None where this makes sense - such as on a CharField.

But in order to stop showing the default one you need to set blank=False. So give a try to something like this:

class MyColorModel(models.Model):
    BLUE = 'blue'
    RED = 'red'
    GREEN = 'green'
    COLOR_CHOICES = (
        ('', '---Please select your color---')
        (BLUE, 'Blue'),
        (RED, 'Red'),
        (GREEN, 'Green'))

   my_color = models.CharField(max_length=5, choices=COLOR_CHOICES, blank=False, null=False, default='')

But in my opinion the best way to do it is just to set empty_label on the form.field.

def __init__(*args, **kwargs):
    super(MyColorForm, self).__init__(*args, **kwargs)
    self.fields['my_color'].empty_label = '---Please select your color---'
查看更多
登录 后发表回答