복붙노트

[PYTHON] 튜플을 사용할 때 ChoiceField에 빈 레이블이 표시되지 않습니다.

PYTHON

튜플을 사용할 때 ChoiceField에 빈 레이블이 표시되지 않습니다.

내 데이터베이스에서 대회에 대한 데이터를 보관할 것입니다. 경쟁 조건을 특정 기준으로 검색 할 수 있기를 원합니다.

경쟁 유형은 튜플에 보관됩니다. 약간 단축 된 예 :

COMPETITION_TYPE_CHOICES = (
    (1, 'Olympic Games'),
    (2, 'ISU Championships'),
    (3, 'Grand Prix Series'),
)

이러한 모델에서 사용됩니다 (다시 - 이것은 모델의 단축 / 단순화 된 버전입니다).

class Competition(models.Model):
    name = models.CharField(max_length=256)
    type = models.IntegerField(choices=COMPETITION_TYPE_CHOICES) 

필드가 검색 양식에 필요하지 않도록 양식을 다음과 같이 정의합니다.

class CompetitionSearchForm(forms.Form):
    name = forms.CharField(required=False)
    type = forms.ChoiceField(choices=COMPETITION_TYPE_CHOICES,required=False)

ChoiceField의 선택 위젯에서 빈 레이블을 표시하고 싶습니다. 그러나 하나가 표시되지 않습니다. 어떤 도움이 많이 감사하겠습니다 :)

해결법

  1. ==============================

    1.나는 DRY 원칙을 위반하지 않고 원하는 방식으로 작동하는 솔루션을 발견했습니다. 별로 깨끗하지는 않지만 내가해야 할 일이있을 것입니다.

    나는 DRY 원칙을 위반하지 않고 원하는 방식으로 작동하는 솔루션을 발견했습니다. 별로 깨끗하지는 않지만 내가해야 할 일이있을 것입니다.

    문서화 선택 사항에 따르면 튜플 일 필요는 없습니다.

    그래서 제가 지금 생각하고있는 해결책은 다음과 같습니다.

    COMPETITION_TYPE_CHOICES = [
         (1, 'Olympic Games'),
         (2, 'ISU Championships'),
         (3, 'Grand Prix Series'),
    ]
    
    COMP_TYPE_CHOICES_AND_EMPTY = [('','All')] + COMPETITION_TYPE_CHOICES
    

    그리고:

    class CompetitionSearchForm(forms.Form):
        name = forms.CharField(required=False)
        type = forms.ChoiceField(choices=COMP_TYPE_CHOICES_AND_EMPTY, required=False)
    

    모델은 그대로 유지됩니다.

  2. ==============================

    2.Monika와 Evgeniy의 솔루션을 아무리 시도해 보았지만 Monika는 선택이 튜플 일 필요가 없다는 점에서 좋은 지적을했습니다. 따라서 가장 쉽고 (가장 DRYest 한) 해결책은 Django가 Model Field에서 이미 수행 한 작업을 수행하는 것입니다. 공백 선택 사항과 튜플을 목록으로 변환 한 후 함께 추가하면됩니다.

    Monika와 Evgeniy의 솔루션을 아무리 시도해 보았지만 Monika는 선택이 튜플 일 필요가 없다는 점에서 좋은 지적을했습니다. 따라서 가장 쉽고 (가장 DRYest 한) 해결책은 Django가 Model Field에서 이미 수행 한 작업을 수행하는 것입니다. 공백 선택 사항과 튜플을 목록으로 변환 한 후 함께 추가하면됩니다.

    from django.db.models.fields import BLANK_CHOICE_DASH
    
    ...
    
    type = forms.ChoiceField(choices=BLANK_CHOICE_DASH + list(COMPETITION_TYPE_CHOICES), required=False)
    
  3. ==============================

    3.form init 메소드에서 필드 선택 사항을 업데이트하는 것이 더 좋습니다.

    form init 메소드에서 필드 선택 사항을 업데이트하는 것이 더 좋습니다.

    COMPETITION_TYPE_CHOICES = (
        (1, 'Olympic Games'),
        (2, 'ISU Championships'),
        (3, 'Grand Prix Series'),
    )
    
    
    class CompetitionSearchForm(forms.Form):
        name = forms.CharField(required=False)
        type = forms.ChoiceField(choices=COMPETITION_TYPE_CHOICES,required=False)
    
        def __init__(self, *args, **kwargs):
            super(CompetitionSearchForm, self).__init__(*args, **kwargs)
            self.fields['type'].choices.insert(0, ('','---------' ) )
    
  4. ==============================

    4.공백 대안이 아직 추가되지 않았는지 확인하는 Evgeniy의 대답에 대한 약간의 변경.

    공백 대안이 아직 추가되지 않았는지 확인하는 Evgeniy의 대답에 대한 약간의 변경.

    검사가 없으면 (적어도 내장 된 runserver를 실행할 때) 각 페이지 재로드마다 하나의 여분의 빈 레이블이 추가됩니다.

    COMPETITION_TYPE_CHOICES = (
        (1, 'Olympic Games'),
        (2, 'ISU Championships'),
        (3, 'Grand Prix Series'),
    )
    
    class CompetitionSearchForm(forms.Form):
        name = forms.CharField(required=False)
        type = forms.ChoiceField(choices=COMPETITION_TYPE_CHOICES,required=False)
    
        def __init__(self, *args, **kwargs):
            super(CompetitionSearchForm, self).__init__(*args, **kwargs)
            if not self.fields['type'].choices[0][0] == '':
                self.fields['type'].choices.insert(0, ('','---------' ) )
    
  5. ==============================

    5.문서에 따르면 :

    문서에 따르면 :

    그래서, 당신은 간단 할 수 있습니다 :

    sample_field = forms.ChoiceField(choices=(('', '---'),) + Model.YOUR_CHOICES)
    
  6. ==============================

    6.모델 필드에 blank = True를 추가하십시오 (원하는 동작으로 가정). 그런 다음 양식을 ModelForm으로 변경하고 필드 정의를 제거하십시오. blank = True로 설정 한 필드는 모델의 유효성을 검사하거나 저장할 때 필요하지 않습니다. 다시 말하지만, 이것은 당신이 원하는 것이 아닐지도 모르지만 장고가 자동으로 몇 가지 일을 처리 할 수있게 해줍니다.

    모델 필드에 blank = True를 추가하십시오 (원하는 동작으로 가정). 그런 다음 양식을 ModelForm으로 변경하고 필드 정의를 제거하십시오. blank = True로 설정 한 필드는 모델의 유효성을 검사하거나 저장할 때 필요하지 않습니다. 다시 말하지만, 이것은 당신이 원하는 것이 아닐지도 모르지만 장고가 자동으로 몇 가지 일을 처리 할 수있게 해줍니다.

    그렇지 않으면 COMPETITION_TYPE_CHOICES을 (를) 다음으로 변경하십시오.

    COMPETITION_TYPE_CHOICES = (
        ('', '---------'),
        ('1', 'Olympic Games'),
        ('2', 'ISU Championships'),
        ('3', 'Grand Prix Series'),
    )
    
  7. ==============================

    7.이미 모델 클래스가있는 경우 ModelForm을 사용하지 않는 이유는 무엇입니까?

    이미 모델 클래스가있는 경우 ModelForm을 사용하지 않는 이유는 무엇입니까?

    최상의 솔루션 :

    forms.py

    class CompetitionSearchForm(ModelForm):
    
        class Meta:
            model = Competition
    

    models.py

    class Competition(models.Model):
        name = models.CharField(max_length=256)
        type = models.IntegerField(choices=COMPETITION_TYPE_CHOICES, default=COMPETITION_TYPE_CHOICES[0][0], blank=True)
    

    목록에서 empty_label을 제거하려면 blank = False로 설정할 수 있습니다

  8. ==============================

    8.파티에 좀 늦었 어.

    파티에 좀 늦었 어.

    선택 사항을 전혀 수정하지 않고 위젯으로 처리하는 것은 어떻습니까?

    from django.db.models import BLANK_CHOICE_DASH
    
    class EmptySelect(Select):
        empty_value = BLANK_CHOICE_DASH[0]
        empty_label = BLANK_CHOICE_DASH[1]
    
        @property
        def choices(self):
            yield (self.empty_value, self.empty_label,)
            for choice in self._choices:
                yield choice
    
        @choices.setter
        def choices(self, val):
            self._choices = val
    

    그럼 그냥 부르세요.

    class CompetitionSearchForm(forms.Form):
        name = forms.CharField(required=False)
        type = forms.ChoiceField(choices=COMPETITION_TYPE_CHOICES,required=False, widget=EmptySelect)
    

    이것은 당신이 결국 무엇입니까 :

    print(CompetitionSearchForm().as_p())
    <p>
        <label for="id_name">Name:</label>
        <input id="id_name" name="name" type="text" />
    </p>
    <p>
        <label for="id_type">Type:</label>
        <select id="id_type" name="type">
            <option value="" selected="selected">------</option>
            <option value="1">Olympic Games</option>
            <option value="2">ISU Championships</option>
            <option value="3">Grand Prix Series</option>
        </select>
    </p>
    
  9. from https://stackoverflow.com/questions/1765757/choicefield-doesnt-display-an-empty-label-when-using-a-tuple by cc-by-sa and MIT license