我有三个模型
class Category(models.Model):
name = models.CharField(max_length=128)
class SubCategory(models.Model):
category = models.ForeignKey(Category)
name = models.CharField(max_length = 400)
class Document(models.Model):
category = models.ForeignKey(Category, null=True,blank=True,help_text=_('Required'))
subcategory = models.ForeignKey(SubCategory, null=True, blank=True, help_text =_('Required'))
title = models.CharField(max_length=300)
现在在Admin界面中我有category,subcategory和title字段。 如果用户试图选择任何子类别,那么只有那个 应显示与Category相关的子类别项。 一个简单的例子是国家,州下拉列表。 我试图从Modelform中获取它,如
class DocumentAdminModelForm(ModelForm):
def __init__(self, *args, **kwargs):
super(DocumentAdminModelForm, self).__init__(*args, **kwargs)
self.fields['sub_category'] = forms.ModelChoiceField(queryset = SubCategory.objects.filter(category__id = self.fields['category'] ))
但它不起作用。我应该为此使用一些ajax和jquery吗? 还有其他方法可以建议??
由于
答案 0 :(得分:0)
这似乎是实现这种关系的最佳方式,一种是父母关系模式。 这是我的解决方案,它基于原生的django字段,模板标签和管理模板的小自定义。 在示例中,我生成带有选项卡式子项的自定义选择元素(基于本机django)。 选择字段的示例(抱歉,俄语示例):
alt text http://img576.imageshack.us/img576/5269/selects.png
实现选择类(用于编辑和创建):
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'\n'.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;\"> %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'\n'.join(output)
然后你需要为你的模型创建modelAdmin类:
示例:强>
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)中显示此关系,我认为最好的方法是为此字段编写templatetag + javascript函数以显示关系树。 实施例(图像+代码): (将文件change_list.html复制到您的模板文件夹中,如: templates / admin / App / model 或 yourappname / templates / admin / yourmodelname / change_list.html 然后在列表过滤器块中添加模板标记的调用:
alt text http://img714.imageshack.us/img714/5141/treetd.png
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 %}
...
.....
我认为无论如何这个例子对于创建自定义控件+管理过滤器非常有用 对不起,如果没有)))