问题描述
我的目标是制作一个具有更多过滤器的高级" filter_horizontal,但是我似乎找不到要覆盖的小部件.我知道它使用related_widget_wrapper.html,但是如果我想以明确的方式向其添加功能,则要覆盖的小部件是什么.
I'm aiming to make an "advanced" filter_horizontal, one with more filters, but I can't seem to find the widget to override.I know it uses the related_widget_wrapper.html, but if I want to add functionalities to it in a clear way, what is the widget to override.
现在,我的备份解决方案是做一个完整的javascript解决方案,以在表单加载(从javascript创建)中添加一个下拉列表,并进行ajax调用来修改过滤器...但这似乎是一个过大的杀伤力.
For now my backup solution is to do a full javascript solution to prepend it with a dropdown on form load (created from javascript) and make ajax calls to modify the filter...but this seems as an overkill.
我到目前为止所做的:
# Override filteredSelectMultiple, add javascript and add attributes on the tag to identify the element, and add parameter url that will contain the ajax call
class AjaxFilterHorizontalWidget(FilteredSelectMultiple):
def __init__(self, url, verbose_name = '', is_stacked=False, attrs=None, choices=()):
self.url = url
super().__init__(verbose_name, is_stacked, attrs, choices)
def get_context(self, name, value, attrs):
context = super().get_context(name, value, attrs)
context['widget']['attrs']['data-url'] = self.url
context['widget']['attrs']['data-ajax-select'] = '1'
return context
class Media:
js = ['admin/js/ajax_filter_horizontal.js']
Ajax_filter_horizontal.js
Ajax_filter_horizontal.js
$(document).ready(function () {
$('select[data-ajax-select=1]').each(function (index, item) {
var currentRequest;
var url = $(item).data('url')
// var wrapper = $('#' + $(item).prop('id')).closest('.selector-available')
$(document).on('keyup', $('.selector-filter input'), function () {
if ($('.selector-filter input').val().length < 3) {
$(item).empty()
return
}
currentRequest = $.ajax({
url: url,
data: {q: $('.selector-filter input').val()},
beforeSend : function() {
if(currentRequest != null) {
currentRequest.abort();
}
},
success: function (data) {
$(item).empty()
let item_to = $('#' + $(item).prop('id').replace('_from', '_to'))
if (data.results.length > 500) {
$('#' + $(item).prop('id')).append('<option disabled value="" title="">Too many results, refine your search...</option>')
return
}
for (let instance of data.results) {
if ($('option[value='+instance.id+']', item_to).length == 0) {
$('#' + $(item).prop('id')).append('<option value="'+instance.id+'" title="'+instance.text+'">'+instance.text+'</option>')
}
}
SelectBox.init($(item).prop('id'))
}
})
});
});
});
我不得不重写该字段,只是为了删除验证(出于某种原因,验证也对原始值(filter_horizontal的左侧)进行了
I had to override the field, just to remove validation(for some reason the validation is also done on the original values, the left side of the filter_horizontal)
class AjaxMultipleChoiceField(MultipleChoiceField):
widget = AjaxFilterHorizontalWidget
def validate(self, value):
pass
"""Validate that the input is a list or tuple."""
# if self.required and not value:
# raise ValidationError(self.error_messages['required'], code='required')
这就是我所说的:
self.fields['person'] = `AjaxMultipleChoiceField(widget=AjaxFilterHorizontalWidget(url= '/person-autocomplete-advanced/', verbose_name='People to invite'))`
在编辑现有字段时,我无法在至"部分中找到预填充值的位置.
I can't manage to find where to prefill the values in the "to" section when I'm editing an existing field.
推荐答案
Django Model admin覆盖包含以下代码的 BaseModelAdmin
.
Django Model admin overrides BaseModelAdmin
which contains following code.
django.contrib.admin.options.py
class BaseModelAdmin(six.with_metaclass(forms.MediaDefiningClass)):
...
def formfield_for_dbfield(self, db_field, request, **kwargs):
...
if db_field.name in self.raw_id_fields:
kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.remote_field, self.admin_site, using=db)
elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)):
kwargs['widget'] = widgets.FilteredSelectMultiple(
db_field.verbose_name,
db_field.name in self.filter_vertical
)
可以观察到是否传递了 filter_vertical
或 filter_horizontal
参数在 ModelAdmin
选项中添加了 FilteredSelectMultiple
小部件.
It can be observed that if there is filter_vertical
or filter_horizontal
argument passedin ModelAdmin
option than it adds FilteredSelectMultiple
widget.
下面是 FilteredSelectMultiple
的来源.如有必要,您可以覆盖此
Below is the source of FilteredSelectMultiple
You may override this if necessary
django.contrib.admin.widgets.py
class FilteredSelectMultiple(forms.SelectMultiple):
"""
A SelectMultiple with a JavaScript filter interface.
Note that the resulting JavaScript assumes that the jsi18n
catalog has been loaded in the page
"""
@property
def media(self): # override this property in your custom class
js = ["core.js", "SelectBox.js", "SelectFilter2.js"]
return forms.Media(js=["admin/js/%s" % path for path in js])
...
def get_context(self, name, value, attrs):
context = super(FilteredSelectMultiple, self).get_context(name, value, attrs)
context['widget']['attrs']['class'] = 'selectfilter'
if self.is_stacked:
context['widget']['attrs']['class'] += 'stacked'
context['widget']['attrs']['data-field-name'] = self.verbose_name
context['widget']['attrs']['data-is-stacked'] = int(self.is_stacked)
return context
用于JS或媒体替代
您可能会发现 FilteredSelectMultiple
类的 media
属性包含多个js,您可以根据需要对其进行修改.
You could observe that media
property on FilteredSelectMultiple
class have several js included you may modify them as per your needs.
用于修改HTML模板
FilteredSelectMultiple
覆盖 django.forms.widgets.SelectMultiple
,最终覆盖 django.forms.widgets.Select
小部件.
FilteredSelectMultiple
overrides django.forms.widgets.SelectMultiple
which ultimately overrides django.forms.widgets.Select
widget.
因此可以说 FilteredSelectMultiple
使用了 Select
小部件
So it can be said that FilteredSelectMultiple
uses following properties of Select
widget
class Select(ChoiceWidget):
input_type = 'select'
template_name = 'django/forms/widgets/select.html'
option_template_name = 'django/forms/widgets/select_option.html'
add_id_index = False
checked_attribute = {'selected': True}
option_inherits_attrs = False
...
您可以在 FilteredSelectMultiple
类中覆盖这些选项.
You can override those options inside your FilteredSelectMultiple
class.
我希望以上信息对您有用.
I hope the information above is useful for you.
这篇关于Django管理员覆盖filter_horizontal的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!