2016-02-16 3 views
0

Я пытаюсь переопределить render_option метод присутствует внутри Select Класс виджета из моего forms.py файла. Поэтому я добавил метод с тем же именем внутри соответствующего класса формы модели. Но это не сработает (этот метод не отменяется). Мой forms.py файл выглядит,Как переопределить виджет формы модели в Django?

class CustomSelectMultiple(Select): 

    allow_multiple_selected = True 

    def render_option(self, selected_choices, option_value, option_label): 
     print 'Inside custom render_option\n\n' 
     if option_value is None: 
      option_value = '' 
     option_value = force_text(option_value) 
     if option_value in selected_choices: 
      selected_html = mark_safe(' selected="selected"') 
      if not self.allow_multiple_selected: 
       # Only allow for a single selection. 
       selected_choices.remove(option_value) 
     else: 
      selected_html = '' 
     return format_html('<option value="{}" data-img-src="www.foo.com" {}>{}</option>', 
          option_value, 
          selected_html, 
          force_text(option_label)) 

    def render_options(self, choices, selected_choices): 
     print 'Inside custom render_options\n\n' 
     print self 
     print choices 
     # Normalize to strings. 
     selected_choices = set(force_text(v) for v in selected_choices) 
     output = [] 
     for option_value, option_label in chain(self.choices, choices): 
      if isinstance(option_label, (list, tuple)): 
       output.append(format_html('<optgroup label="{}">', force_text(option_value))) 
       for option in option_label: 
        output.append(self.render_option(selected_choices, *option)) 
       output.append('</optgroup>') 
      else: 
       output.append(self.render_option(selected_choices, option_value, option_label)) 
     #print output 
     return '\n'.join(output) 

    def render(self, name, value, attrs=None, choices=()): 
     print 'Inside custom render\n\n' 
     if value is None: 
      value = [] 
     final_attrs = self.build_attrs(attrs, name=name) 
     output = [format_html('<select multiple="multiple"{}>', flatatt(final_attrs))] 
     options = self.render_options(choices, value) 
     if options: 
      output.append(options) 
     output.append('</select>') 
     return mark_safe('\n'.join(output)) 

    def value_from_datadict(self, data, files, name): 
     if isinstance(data, MultiValueDict): 
      return data.getlist(name) 
     return data.get(name) 


class GuideUpdateForm(ModelForm): 
    def __init__(self, *args, **kwargs): 
     super(GuideUpdateForm, self).__init__(*args, **kwargs) 
     self.fields['date_modified'].widget = HiddenInput() 
     self.fields['point_of_interest'].widget = CustomSelectMultiple() 

    class Meta: 
     fields = ('name', 'image', 'point_of_interest', 'date_modified',) 
     model = Guide 

Я также попытался изменить свой Meta класс, как,

class Meta: 
     fields = ('name', 'image', 'point_of_interest', 'date_modified',) 
     model = Guide 
     widgets = { 
      'point_of_interest': SelectMultiple(attrs={'data-img-src': 'www.foo.com'}), 
     } 

Но добавить это атрибут data-img-src только select тег, но не ко всем option тегов, присутствующих внутри select бирка.

Обратите внимание, что SelectMultiple класса вызывает renderoptions метода Select класса, который в дальнейшем вызывает метод renderoption, которые не имеют attrs=None аргумента ключевого слова.

+0

@Sayse см [ 'widget.Select'] (https://docs.djangoproject.com/en/1.9/ _modules/django/forms/widgets/# SelectMultiple) –

+0

Конечно, это то, что я получал, ваш фрагмент кода выше имеет метод в форме, но я могу найти ссылку на него внутри класса [widget class] (https: // github.com/django/django/blob/master/django/forms/widgets.py#L528) – Sayse

+1

извините, не удалось обновить код .. Pls проверить это сейчас .. Я попытался переопределить встроенные методы, но он не может получить datas from db. –

ответ

2

Судя от собственного решения, похоже, вы, возможно, искали ModelChoiceField

self.fields['point_of_interest'] = forms.ModelChoiceField(widget=CustomSelectMultiple(), 
                  queryset=poi.objects.all()) 

Параметр QuerySet состоит из «A QuerySet модельных объектов, из которых будет выбор для поля и будет использоваться для проверки выбора пользователя ».

это создает список кортежей идентификаторов, имен? Потому что я хочу дополнительный тег, чтобы выглядеть как option value="id">name</option>

Я уверен, что по умолчанию id, __str__ где __str__ является строковым представлением модели. Если вы хотите, чтобы это было специфично для имени, то вы можете переопределить это поле и установить label_from_instance

class MyModelChoiceField(ModelChoiceField): 
    def label_from_instance(self, obj): 
     return obj.name 
+0

создает ли список кортежей идентификаторов, имен? Поскольку я хочу, чтобы тег опции выглядел как 'option value =" id "> name' –

+0

@AvinashRaj - Theres необязательно ['to_field_name'] (https://docs.djangoproject.com/en/1.9/ref/forms /fields/#django.forms.ModelChoiceField.to_field_name), если это то, о чем вы просили? Я уверен, что значение по умолчанию, отображаемое для пользователя, равно любому представлению '__str__', но в остальном значение по умолчанию -' id, __str__' (см., Например, ссылку to_field_name_). – Sayse

+0

Если я использую метод ur, я 'm получает значение параметра как пустую строку. My str-представление модели - это имя. плюс один для усилий ура. –

1

Мне удалось решить эту проблему, передав значения db в choices kwargs.

from models import poi 
class GuideUpdateForm(ModelForm): 
    def __init__(self, *args, **kwargs): 
     super(GuideUpdateForm, self).__init__(*args, **kwargs) 
     self.fields['date_modified'].widget = HiddenInput() 
     self.fields['point_of_interest'] = forms.ChoiceField(widget=CustomSelectMultiple(), choices=[(i.id,i.name) for i in poi.objects.all()])