微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何在django中向选项标签添加属性?

如何解决如何在django中向选项标签添加属性?

| 我必须将title属性添加到ModelChoiceField的选项中。这是我的管理员代码
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
我可以添加任何属性来选择小部件,但是我不知道如何向选项标签添加属性。任何想法 ?     

解决方法

        首先,不要修改
__init__
中的字段,如果要覆盖小部件,请使用
Meta
内部类,如果要覆盖表单字段,请像普通(非模型)形式一样声明它们。 如果
Select
小部件没有执行您想要的操作,则只需制作一个即可。原始窗口小部件使用
render_option
方法获取单个选项的HTML表示-创建一个子类,覆盖它,然后添加所需的任何内容。
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:
        # ...
    ,        我有一个类似的问题,我需要向每个选项动态添加自定义属性。但是在Django 2.0中,html呈现已移至Widget基类中,因此修改
render_option
不再有效。这是对我有用的解决方案:
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,attrs=None)
        for k,v in self.src.items():
            options[\'attrs\'][k] = v[options[\'value\']]
        return options

class CustomForm(forms.Form):
    def __init__(self,**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)
然后在视图中,使用
{\'form\': CustomForm(choices=choices,src=src)}
渲染上下文,其中
src
是这样的字典:
{\'attr-name\': {\'option_value\': \'attr_value\'}}
。     ,        这是我从Forms.Select继承的一类(感谢Cat Plus Plus使我开始学习)。初始化时,提供option_title_field参数,指示用于“ 11”标题属性的字段。
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,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],option_title_list[more_choices.index(c)]) for c in more_choices]
            except:
                more_choices = [(c[0],\'\') for c in more_choices] # couldn\'t get title values
            output = []
            for option_value,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_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\')
    )
    ,        从django 1.11及更高版本中删除了
render_option
方法。请参阅此链接:https://docs.djangoproject.com/zh-CN/1.11/releases/1.11/#changes-due-to-the-introduction-of-template-based-widget-rendering 这是一种适用于我的解决方案,不同于Kayoz的解决方案。我没有像示例中那样修改名称,但我希望它仍然清楚。在模型表单中,我覆盖了该字段:
class MyForm(forms.ModelForm):
    project = ProjectModelChoiceField(label=_(\'Project\'),widget=ProjectSelect())
然后,我从上面声明类,并另外声明一个迭代器:
class ProjectModelChoiceIterator(django.forms.models.ModelChoiceIterator):
    def choice(self,obj):
        # return (self.field.prepare_value(obj),self.field.label_from_instance(obj)) #it used to be like this,but we need the extra context from the object not just the label. 
        return (self.field.prepare_value(obj),obj)

class ProjectModelChoiceField(django.forms.models.ModelChoiceField):
   def _get_choices(self):
       if hasattr(self,\'_choices\'):
           return self._choices
       return ProjectModelChoiceIterator(self)


class ProjectSelect(django.forms.Select):

    def create_option(self,attrs=None):
        context = super(ProjectSelect,attrs=None)

        context[\'attrs\'][\'extra-attribute\'] = label.extra_attribute #label is now an object,not just a string.
        return context
    ,        如果要使用实例来设置属性值,这是一种解决方案。
class IconSelectWidget(forms.Select):
    def create_option(self,**kwargs):
        option = super().create_option(name,**kwargs)
        if value:
            icon = self.choices.queryset.get(pk=value)  # get icon instance
            option[\'attrs\'][\'title\'] = icon.title  # set option attribute
        return option

class LocModelForm(forms.ModelForm):
    icons = forms.ModelChoiceField(
        queryset=Photo.objects.filter(galleries__title_slug=\'markers\'),widget=IconSelectWidget
    )
    ,        使用Django 1.11,我发现了使用已记录的API的另一种方法。如果您覆盖
get_context
并深入挖掘结构,您将在
context[\'widget\'][\'optgroups\'][1][option_idx][\'attrs\']
中看到各个选项的属性。例如,在我的子类中,我有以下代码:
class SelectWithData(widgets.Select):
    option_data = {}

    def __init__(self,option_data={}):
        super(SelectWithData,choices)
        self.option_data = option_data

    def get_context(self,attrs):
        context = super(SelectWithData,self).get_context(name,attrs)
        for optgroup in context[\'widget\'].get(\'optgroups\',[]):
            for option in optgroup[1]:
                for k,v in six.iteritems(self.option_data.get(option[\'value\'],{})):
                    option[\'attrs\'][\'data-\' + escape(k)] = escape(v)
        return context
    

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。