python 파이썬 - Django 선택 상자 빈 옵션 사용자 정의 / 제거




함수 title (13)

나는 장고 1.0.2를 사용하고있다. 모델로 뒷받침되는 ModelForm을 작성했습니다. 이 모델은 비어있는 False = ForeignKey 있습니다. Django는이 양식에 대해 HTML을 생성 할 때 ForeignKey가 참조하는 테이블의 각 행에 대해 하나의 옵션이있는 선택 상자를 작성합니다. 또한 목록 맨 위에 값이없고 대시로 표시되는 옵션을 만듭니다.

<option value="">---------</option>

내가 알고 싶은 것은 :

  1. 선택 상자에서이 자동 생성 옵션을 제거하는 가장 깨끗한 방법은 무엇입니까?
  2. 다음과 같이 표시되도록 사용자 정의하는 가장 깨끗한 방법은 무엇입니까?

    <option value="">Select Item</option>
    

해결책을 찾기 위해 장고 티켓 4653 을 보았습니다.이 티켓 은 다른 사람들이 같은 질문을하고 장고의 기본 동작이 수정되었을 수도 있다는 느낌을주었습니다. 이 티켓은 1 년이 넘었으므로 이러한 것들을 수행 할 수있는 더 깨끗한 방법이 있기를 바랬습니다.

어떤 도움을 주셔서 감사합니다.

제프

편집 : 나는 같은 ForeignKey 필드를 구성했습니다 :

verb = models.ForeignKey(Verb, blank=False, default=get_default_verb)

이 옵션은 더 이상 빈 / 대시 옵션이 아닌 기본값을 설정하지만 불행히도 내 질문 중 하나를 해결하지 못하는 것 같습니다. 즉, 여전히 빈 / 대시 옵션이 목록에 나타납니다.


Answers

Carl의 답변으로 가이드와 Django 소스를 몇 시간 동안 응원 한 후에 이것이 완벽한 해결책이라고 생각합니다.

  1. 빈 옵션을 제거하려면 (Carl의 예를 확장) :

    class ThingForm(models.ModelForm):
      class Meta:
        model = Thing
    
      def __init__(self, *args, **kwargs):
        super(ThingForm, self).__init__(*args, **kwargs)
        self.fields['verb'].empty_label = None
        # following line needed to refresh widget copy of choice list
        self.fields['verb'].widget.choices =
          self.fields['verb'].choices
    
  2. 빈 옵션 레이블을 사용자 정의하려면 기본적으로 동일합니다.

    class ThingForm(models.ModelForm):
      class Meta:
        model = Thing
    
      def __init__(self, *args, **kwargs):
        super(ThingForm, self).__init__(*args, **kwargs)
        self.fields['verb'].empty_label = "Select a Verb"
        # following line needed to refresh widget copy of choice list
        self.fields['verb'].widget.choices =
          self.fields['verb'].choices
    

이 접근 방식은 ModelChoiceFields가 HTML로 렌더링되는 모든 시나리오에 적용되지만 저는 긍정적이지는 않습니다. 이 필드가 초기화 될 때 선택 항목이 선택 위젯으로 전달된다는 것을 알았습니다 (django.forms.fields.ChoiceField._set_choices 참조). 초기화 후에 empty_label을 설정해도 선택 위젯의 선택 목록은 새로 고쳐지지 않습니다. 이 버그를 버그로 간주해야 하는지를 알기 위해 장고에 익숙하지 않습니다.


문서에서

모델 필드에 blank = False와 명시 적 기본값 (초기 값 대신 처음에 선택됨)이 있으면 공백 선택은 포함되지 않습니다.

그래서 기본값을 설정하면 괜찮습니다.


ForeignKey 필드의 경우 모델의 default'' 설정하면 공백 옵션이 제거됩니다.

verb = models.ForeignKey(Verb, on_delete=models.CASCADE, default='')

CharField 와 같은 다른 필드의 경우 defaultNone default 설정할 수 있지만 Django 1.11의 ForeignKey 필드에서는 작동하지 않습니다.


나는 해결책을 찾는다 !!

하지만 ForeignKey는 아닙니다 :-)

아마 너를 도울 수있어. Django 소스 코드를 살펴본 결과 django.forms.extras.widgets.SelecteDateWidget ()은 none_value라는 속성 (0, '-----')과 같습니다. 그래서이 코드에서이 작업을 수행했습니다.

class StudentForm(ModelForm):
    class Meta:
        this_year = int(datetime.datetime.today().strftime('%Y')) 
        birth_years = []
        years = []

        for year in range(this_year - 2, this_year + 3 ):
            years.append(year)
        for year in range(this_year - 60, this_year+2):
            birth_years.append(year)

        model = Student
        exclude = ['user', 'fullname']
        date_widget = SelectDateWidget(years=years)

        date_widget.__setattr__('none_value', (0, 'THERE WAS THAT "-----" NO THERES THIS:-)'))
        widgets = {
            'beginning': date_widget,
            'birth': SelectDateWidget(years=birth_years),
        }

여기에 많은 좋은 답변이 있지만 구현에 대해 전적으로 만족하지 않습니다. 또한 다른 소스 (외래 키, 선택 사항)의 선택 위젯이 다른 동작을 산출한다는 사실에 다소 좌절감을 느낍니다.

필자는 선택 필드에 항상 공백 옵션이있는 디자인을 사용하고 있으며 필요한 경우 옆에 별표가 표시되며 양식이 비어있는 경우 유효성을 검사하지 않습니다. 즉, TypedChoiceField가 아닌 필드에 대해서만 empty_label을 제대로 재정의 할 수 있습니다.

결과 다음과 같습니다. 첫 번째 결과는 항상 필드의 이름입니다. 제 경우에는 label 입니다.

내가 끝내 준 일이 여기있다. 다음은 내 양식의 재정의 된 __init__ 메소드입니다.

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    for _, field in self.fields.items():
        if hasattr(field, 'empty_label'):
            field.empty_label = field.label
        if isinstance(field, forms.TypedChoiceField):
            field.choices = [('', field.label)] + [choice for choice in field.choices if choice[0]]

모델에서 사용할 수 있습니다.

class MyModel(models.Model):
    name = CharField('fieldname', max_length=10, default=None)

기본값 = 없음 이 답입니다. D

참고 :이 장고 1.7 시도한


Django 1.7부터 모델 필드 정의에서 선택 목록에 값을 추가하여 공백 값에 대한 레이블을 사용자 정의 할 수 있습니다. 필드 선택 구성에 대한 설명서에서

blank = False가 기본값과 함께 필드에 설정되어 있지 않으면 "---------"가 포함 된 레이블이 선택 상자와 함께 렌더링됩니다. 이 동작을 무시하려면 없음을 포함하는 선택 항목에 튜플을 추가합니다. 예 (None, 'Your String for Display'). 또는 CharField에서와 같이 None 대신 빈 문자열을 사용할 수 있습니다.

다른 버전의 장고에 대한 문서를 살펴본 결과이 장고 1.7추가 된 것을 발견했습니다.


이것을 테스트하지는 않았지만 Django의 코드를 읽고 here 에 기초하여 나는 그것이 작동한다고 믿습니다 :

class ThingForm(models.ModelForm):
  class Meta:
    model = Thing

  def __init__(self, *args, **kwargs):
    super(ThingForm, self).__init__(*args, **kwargs)
    self.fields['verb'].empty_label = None

편집 :이 documented 되어 있지만 자동 생성 된 ModelForm을 사용하는 경우 ModelChoiceField를 반드시 확인할 필요는 없습니다.

편집 : 그의 답변에 jlpp 메모로,이 완료되지 않았습니다 - 당신은 empty_label 특성을 변경 한 후 위젯에 선택 사항을 다시 할당해야합니다. 이것이 약간 해킹 된 것이기 때문에 이해하기 쉬운 다른 옵션은 ModelChoiceField 전체를 오버라이드하는 것입니다.

class ThingForm(models.ModelForm):
  verb = ModelChoiceField(Verb.objects.all(), empty_label=None)

  class Meta:
    model = Thing

django 1.4에서 필요한 것은 선택 필드에서 "default"값과 "blank = False"를 설정하는 것입니다.

class MyModel(models.Model):
    CHOICES = (
        (0, 'A'), 
        (1, 'B'),
    )
    choice_field = models.IntegerField(choices=CHOICES, blank=False, default=0)

최신 버전의 django에 대한 첫 번째 대답은 다음과 같아야합니다.

class ThingForm(models.ModelForm):
class Meta:
 model = Thing

  def __init__(self, *args, **kwargs):
    self.base_fields['cargo'].empty_label = None
    super(ThingForm, self).__init__(*args, **kwargs)`

당신은 admin에서 이것을 할 수 있습니다 :

formfield_overrides = {
    models.ForeignKey: {'empty_label': None},
}

self.fields['xxx'].empty_value = None 은 작동하지 않습니다. 필드 유형이 empty_label 등록 정보가없는 empty_label 경우.

우리가해야 할 일은 첫 번째 선택을 제거하는 것입니다.

1 . BaseForm 자동 생성 TypedChoiceField 를 생성 TypedChoiceField

class BaseForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        super(BaseForm, self).__init__(*args, **kwargs)

        for field_name in self.fields:
            field = self.fields.get(field_name)
            if field and isinstance(field , forms.TypedChoiceField):
                field.choices = field.choices[1:]
            # code to process other Field
            # ....

class AddClientForm(BaseForm):
     pass

2.only 약간 모양, 당신은 사용할 수있다 :

class AddClientForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        super(AddClientForm, self).__init__(*args, **kwargs)
        self.fields['xxx'].choices = self.fields['xxx'].choices[1:]





python django django-models django-forms