python - 함수 - Django 선택 상자 빈 옵션 사용자 정의/제거




파이썬 title 함수 (10)

나는 장고 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)

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


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을 설정해도 선택 위젯의 선택 목록은 새로 고쳐지지 않습니다. 이 버그를 버그로 간주해야 하는지를 알기 위해 장고에 익숙하지 않습니다.


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

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

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


나는 오늘 이것을 어지럽 혀서 겁쟁이 해킹 멋진 솔루션을 내놓았다.

# Cowardly handle ModelChoiceField empty label
# we all hate that '-----' thing
class ModelChoiceField_init_hack(object):
    @property
    def empty_label(self):
        return self._empty_label

    @empty_label.setter
    def empty_label(self, value):
        self._empty_label = value
        if value and value.startswith('-'):
            self._empty_label = 'Select an option'
ModelChoiceField.__bases__ += (ModelChoiceField_init_hack,)

이제 기본 ModelChoiceField 빈 라벨을 원하는대로 조정할 수 있습니다. :-)

추신 : downvotes에 대한 필요성, 비 유해한 원숭이 패치는 항상 편리합니다.


나는 해결책을 찾는다 !!

하지만 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),
        }

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

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

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

참고 :이 장고 1.7 시도한


문서에서

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

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


이 문제에 대한 완전한 토론과 해결 방법은 여기 를 참조 하십시오 .


이것을 테스트하지는 않았지만 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

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

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

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


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:]




django-forms