Hi!
I have a fairly complex working admin customization that works well with ordinary foreign key fields.
First, there is a mixin class that adds data attributes to options of any forms.widgets.Select
-based class:
class AddDataAttrsToOptionsSelectMixin:
def create_option(self, name, value, label, selected, index, subindex=None, attrs=None):
option = super().create_option(name, value, label, selected, index, subindex, attrs)
# self.select_option_data is initialized in add_data_attr_options_to_widget()
# with a dictionary of data attributes.
for data_attr, values in self.select_option_data.items():
option['attrs'][data_attr] = values[option['value']]
return option
Second, there is a function that applies the mixin to the given widget dynamically during runtime:
def add_data_attr_options_to_widget(widget, data):
widget.select_option_data = data
widget_cls = widget.__class__
widget.__class__ = type(f'{widget_cls.__name__}WithDataAttrs',
(AddDataAttrsToOptionsSelectMixin, widget_cls), {})
Suppose you have a Customer
model with notes
field that is used in a SalesOrder
model:
class Customer(models.Model):
notes = models.TextField(blank=True)
class SalesOrder(models.Model):
customer = models.ForeignKey(Customer)
then you would add notes to the customers in the customer drop-down in sales order admin as follows:
class SalesOrderAdminModelForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
data_customer_notes = {
'data-notes': dict(Customer.objects.values_list('id', 'notes'))
}
data_customer_notes['data-notes'][''] = False # empty option
add_data_attr_options_to_widget(self.fields['customer'].widget, data_customer_notes)
@admin.register(SalesOrder)
class SalesOrderAdmin(admin.ModelAdmin):
form = SalesOrderAdminModelForm
and you could use the notes in custom admin JavaScript as follows:
var $selected = $('#id_customer').find(":selected")
var noteText = $selected.attr('data-notes')
alert('Selected customer note: ' + noteText)
So far, so good, this works very well.
The problem is that there are many customers and the customers
field should really use autocomplete in admin:
@admin.register(SalesOrder)
class SalesOrderAdmin(admin.ModelAdmin):
autocomplete_fields = ('customer',)
...
Is there a way to add attributes to the results of the admin autocomplete AJAX endpoint and assure that the attributes are propagated to option items with Selec2, so that the JavaScript snippet from above will continue to work?
var $selected = $('#id_customer').find(":selected")
var noteText = $selected.attr('data-notes')
alert('Selected customer note: ' + noteText)
Thank you in advance for any hints!