且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

根据Django admin中的相关类别限制子类别下拉列表中的选择

更新时间:2023-11-30 14:43:10

似乎是实现这种关系的***方法,一个带有父关系的模型.这是我的解决方案,它基于原生 django 字段、模板标签和管理模板的小自定义.例如,我生成带有选项卡子项的自定义选择元素(基于本机 django).选择字段示例(对不起,俄语示例):

It seems that is the best way to realize this relations, one model with parent relation. Here is my solution which is based on native django fields,templatetags and little custom of admin template. In example, i generate custom select element with tabbed childs (based on native django). Example of select field (sorry, example in Russian language):

Select类的实现(用于编辑和创建):

Realization of Select class(for edit and create):

class mSelect(Widget):
    def __init__(self, attrs=None, choices=()):
        super(mSelect, self).__init__(attrs)
        # choices can be any iterable, but we may need to render this widget
        # multiple times. Thus, collapse it into a list so it can be consumed
        # more than once.
        self.choices = list(choices)

    def render(self, name, value, attrs=None, choices=()):

        if value is None: value = ''
        final_attrs = self.build_attrs(attrs, name=name)
        print name
        output = [u'<select name="%s" style="width:200px;">' % name]
        output.append(u"<option value=""%s>----------</option>")
        options = self.render_options(choices, [value])
        if options:
            output.append(options)
        output.append('</select>')
        return mark_safe(u'
'.join(output))

    def render_options(self, choices, selected_choices):

        def render_option(option_value, option_label):
            option_value = force_unicode(option_value)
            selected_html = (option_value in selected_choices) and u' selected="selected"' or u''
            return u'<option value="%s"%s style="padding-left:20px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;%s</option>' % (
                escape(option_value), selected_html,
                conditional_escape(force_unicode(option_label)))
        # Normalize to strings.
        selected_choices = set([force_unicode(v) for v in selected_choices])
        output = []

        for option_value, option_label in chain(self.choices, choices):
            childs = **YOUR_MODEL**.objects.filter(parent=option_value).order_by("**YOUR_FIELDNAME**")

            if len(childs)>0:
                output.append("<option value="%s" disabled >%s</option>" % (option_value,option_label))

                for child in childs:
                    output.append(render_option(child.id, child.iname))

        return u'
'.join(output)

然后你需要为你的模型创建modelAdmin类:

Then you need to create modelAdmin class for you model:

示例:

class **YOUMODELADMIN**(admin.ModelAdmin):
    .....
    .....
    .....

    def formfield_for_dbfield(self, db_field, **kwargs):
        if db_field.name == '**YOUR_FIELD_NAME**':
            kwargs["widget"] = mSelect()
        field = super(**YOUMODELADMIN**, self).formfield_for_dbfield(db_field, **kwargs)  
        return field

如果您需要在 admin(list_filter) 中显示此关系,我认为***的方法是为此字段 + javascript 函数编写模板标签以显示关系树.示例(图像+代码):(将文件 change_list.html 复制到您的模板文件夹中,例如:templates/admin/App/modelyourappname/templates/admin/yourmodelname/ change_list.html然后在列表过滤块中添加模板标签的调用:

If you need to show this relations in admin(list_filter) i think the best way is to write templatetag for this field+javascript function to show relation tree. Example(image+code): (copy file change_list.html into your template folder like: templates/admin/App/model or yourappname/templates/admin/yourmodelname/ change_list.html Then add call of your template tag in list filter block:

Javascript 块示例:

<script>
    function showTree(name_id)
    {
        if(document.getElementById("li_" + name_id).style.display=="none")
        {
            //document.getElementById("div_" + name_id).style.display = "block";
            document.getElementById("li_" + name_id).style.display = "block";
        }
        else
        {
            //document.getElementById("div_" + name_id).style.display = "none";
            document.getElementById("li_" + name_id).style.display = "none";
        }
    }
</script>

templatetag(python)示例代码:

def YOURTEMPLATETAG(request):
    root_link = "/admin/YOURAPP/YOURMODEL/"
    mvar = "YOURFIELD_ID__id__in"
    mlink = root_link + "?"

    for item in request.GET:
        if item!=mvar:
            mlink += "&%s=%s" % (item,request.GET[item])    

    arr_options = []
    dest = HERE YOU GET YOUR ROOT OBJECTS
    selected = ""

    for item in dest:
        show = False
        childs = HERE YOU GET YOU CHILD OBJECTS

        if len(childs)>0:
            str_req = "".join("%d," % child.id for child in childs).rstrip(",")

            if u"ptype__id__in" in request.GET:
                selected = request.GET["YOURFIELDNAME__id__in"]
                if selected in str_req.split(","):
                    show = True

            proot = {"name":item.iname,"link":str_req,"childs":childs,"show":show}

            arr_options.append(proot)

    if "," not in selected and len(selected)>0:
        selected = int(selected)
    return render_to_string("PATH_TO_YOUR_TEMPLATETAG_TEMPLATE/templatetags/show_options.html",{"mlink":mlink,"selected":selected,"options":arr_options,"name":u"YOUR FILTER NAME","tst":request})

templatetag的模板示例:

<h3>{{name}}</h3>
<ul>
    <!--li class="selected"?q=-->
    <li{% ifequal selected '' %} class="selected"{% endifequal %}><a href="?">Все</a></li>
    {% for item in options %}
        <li  {% ifequal selected item.link %} class="selected"{% endifequal %} >
            <a href="{{mlink}}&YOURFIELDNAME__id__in={{item.link}}">{{item.name}}</a>
            <a href="javascript:showTree('{{item.link}}')">[show tree]</a>
        </li>

        <li id="li_{{item.link}}" {% ifequal item.show 1 %}{%else%}style="display:none;"{%endifequal%}>
            <ul>
        {% for child in item.childs %}
            <li {% ifequal selected child.id %} class="selected"{% endifequal %}><div style="margin-left:10px;"><a href="{{mlink}}&YOURFIELDNAME__id__in={{child.id}}">{{child.FIELDOFNAME}}</a></div></li>
        {% endfor %}
            </ul>
        </li>

    {% endfor %}
</ul>

最后阻止 change_list.html:

....
....
          <div id="changelist-filter" style="width:350px;z-index:0;">
            {% load YOURTEMPLATETAGFILE %}
            {% show_date_cal request "/PATH_TO_YOUR_MODEL_VIEW/" %}
            <h2>Custom filters</h2>
            {% TEMPLATETAGNAME request %}


            <h2>{% trans 'Filter' %}</h2>
            {% for spec in cl.filter_specs %}{% admin_list_filter cl spec %}{% endfor %}
...
.....

我认为无论如何这个例子对于创建自定义控件+管理过滤器很有用对不起,如果不是)))

I think anyway this example will be useful for creating custom controls+admin filters Sorry if not )))