2011-06-25 29 views
9

Tôi phải thêm thuộc tính tiêu đề vào các tùy chọn của ModelChoiceField. Đây là mã quản trị của tôi cho rằng:Làm cách nào để thêm thuộc tính vào thẻ tùy chọn trong django?

class LocModelForm(forms.ModelForm): 
     def __init__(self,*args,**kwargs): 
      super(LocModelForm,self).__init__(*args,**kwargs) 
      self.fields['icons'] = forms.ModelChoiceField(queryset = Photo.objects.filter(galleries__title_slug = "markers")) 
      self.fields['icons'].widget.attrs['class'] = 'mydds' 


     class Meta: 
      model = Loc 
      widgets = { 
       'icons' : forms.Select(attrs={'id':'mydds'}), 
       } 

     class Media: 
      css = { 
       "all":("/media/css/dd.css",) 
       } 
      js=(
       '/media/js/dd.js', 
       ) 

class LocAdmin(admin.ModelAdmin): 
    form = LocModelForm 

Tôi có thể thêm bất kỳ thuộc tính nào để chọn tiện ích nhưng tôi không biết cách thêm thuộc tính vào thẻ tùy chọn. Bất kỳ ý tưởng ?

Trả lời

16

Trước hết, không sửa đổi các trường trong __init__, nếu bạn muốn ghi đè các tiện ích sử dụng Meta lớp bên trong, nếu bạn muốn ghi đè trường biểu mẫu, hãy khai báo chúng như bình thường (không phải mẫu).

Nếu tiện ích Select không làm những gì bạn muốn, sau đó chỉ cần thực hiện của riêng bạn. Tiện ích ban đầu sử dụng phương thức render_option để lấy biểu diễn HTML cho một tùy chọn - tạo một lớp con, ghi đè lên và thêm bất kỳ thứ gì bạn muốn.

class MySelect(forms.Select): 
    def render_option(self, selected_choices, option_value, option_label): 
     # look at the original for something to start with 
     return u'<option whatever>...</option>' 

class LocModelForm(forms.ModelForm): 
    icons = forms.ModelChoiceField(
     queryset = Photo.objects.filter(galleries__title_slug = "markers"), 
     widget = MySelect(attrs = {'id': 'mydds'}) 
    ) 

    class Meta: 
     # ... 
     # note that if you override the entire field, you don't have to override 
     # the widget here 
    class Media: 
     # ... 
+3

Có lý do cụ thể nào khiến các trường phải được sửa đổi trong lớp bên trong 'Meta' thay vì phương thức' __init__' không? Và lý do tương tự sẽ áp dụng cho việc sửa đổi/thêm các thuộc tính widget cho một trường? – hellsgate

+1

@hellsgate Trong hầu hết các trường hợp, không có lý do gì để không ghi đè '__init__' để đặt' widget.attrs'. Trong phần lớn các trường hợp sử dụng, chẳng hạn như sửa đổi thuộc tính html trên một tiện ích con mặc định khác * không * làm như vậy thông qua ghi đè '__init__' vi phạm DRY. Thật không may cho trường hợp của OP, anh ta sẽ phải xác định một widget tùy chỉnh vì thẻ '

+0

Cách tiếp cận này cũng có thể được sử dụng để mở rộng tiện ích 'SelectMultiple'. Chỉ cần phân lớp 'SelectMultiple' và chuyển nó thành widget' MySelect' tùy chỉnh. – NickBraunagel

4

Đây là lớp tôi tạo kế thừa từ biểu mẫu.Chọn (nhờ Cat Plus Plus để bắt đầu với điều này). Khi khởi tạo, hãy cung cấp thông số option_title_field cho biết trường nào sẽ sử dụng cho thuộc tính tiêu đề <option>.

from django import forms 
from django.utils.html import escape 

class SelectWithTitle(forms.Select): 
    def __init__(self, attrs=None, choices=(), option_title_field=''): 
     self.option_title_field = option_title_field 
     super(SelectWithTitle, self).__init__(attrs, choices) 

    def render_option(self, selected_choices, option_value, option_label, option_title=''): 
     print option_title 
     option_value = forms.util.force_unicode(option_value) 
     if option_value in selected_choices: 
      selected_html = u' selected="selected"' 
      if not self.allow_multiple_selected: 
       # Only allow for a single selection. 
       selected_choices.remove(option_value) 
     else: 
      selected_html = '' 
     return u'<option title="%s" value="%s"%s>%s</option>' % (
      escape(option_title), escape(option_value), selected_html, 
      forms.util.conditional_escape(forms.util.force_unicode(option_label))) 

    def render_options(self, choices, selected_choices): 
      # Normalize to strings. 
      selected_choices = set(forms.util.force_unicode(v) for v in selected_choices) 
      choices = [(c[0], c[1], '') for c in choices] 
      more_choices = [(c[0], c[1]) for c in self.choices] 
      try: 
       option_title_list = [val_list[0] for val_list in self.choices.queryset.values_list(self.option_title_field)] 
       if len(more_choices) > len(option_title_list): 
        option_title_list = [''] + option_title_list # pad for empty label field 
       more_choices = [(c[0], c[1], option_title_list[more_choices.index(c)]) for c in more_choices] 
      except: 
       more_choices = [(c[0], c[1], '') for c in more_choices] # couldn't get title values 
      output = [] 
      for option_value, option_label, option_title in chain(more_choices, choices): 
       if isinstance(option_label, (list, tuple)): 
        output.append(u'<optgroup label="%s">' % escape(forms.util.force_unicode(option_value))) 
        for option in option_label: 
         output.append(self.render_option(selected_choices, *option, **dict(option_title=option_title))) 
        output.append(u'</optgroup>') 
       else: # option_label is just a string 
        output.append(self.render_option(selected_choices, option_value, option_label, option_title)) 
      return u'\n'.join(output) 

class LocModelForm(forms.ModelForm): 
    icons = forms.ModelChoiceField(
     queryset = Photo.objects.filter(galleries__title_slug = "markers"), 
     widget = SelectWithTitle(option_title_field='FIELD_NAME_HERE') 
    ) 
0

Tôi gặp sự cố tương tự, nơi tôi cần thêm thuộc tính tùy chỉnh cho từng tùy chọn động. Nhưng trong Django 2.0, việc hiển thị html đã được chuyển vào lớp cơ sở Widget, vì vậy việc sửa đổi render_option không còn hoạt động nữa. Dưới đây là giải pháp mà làm việc cho tôi:

from django import forms 

class CustomSelect(forms.Select): 
    def __init__(self, *args, **kwargs): 
     self.src = kwargs.pop('src', {}) 
     super().__init__(*args, **kwargs) 

    def create_option(self, name, value, label, selected, index, subindex=None, attrs=None): 
     options = super(CustomSelect, self).create_option(name, value, label, selected, index, subindex=None, attrs=None) 
     for k, v in self.src.items(): 
      options['attrs'][k] = v[options['value']] 
     return options 

class CustomForm(forms.Form): 
    def __init__(self, *args, **kwargs): 
     src = kwargs.pop('src', {}) 
     choices = kwargs.pop('choices',()) 
     super().__init__(*args, **kwargs) 
     if choices: 
      self.fields['custom_field'].widget = CustomSelect(attrs={'class': 'some-class'}, src=src, choices=choices) 

    custom_field = forms.CharField(max_length=100) 

Sau đó, trong quan điểm, làm cho một bối cảnh với {'form': CustomForm(choices=choices, src=src)} nơi src là một cuốn từ điển như thế này: {'attr-name': {'option_value': 'attr_value'}}.

Các vấn đề liên quan