Search code examples
jquerypythondjangodjango-autocomplete-light

Customising the output of items using django-autocomplete-light v3


In earlier versions of django-autocomplete-light you could use a template to render each returned entry, which included the ability to insert custom HTML

I can't figure out how to do that using the regular API, so I'm trying to add it in.

So far I have a class like this which uses mark_safe and the HTML is being passed through:

class TemplateRenderSelect2QuerySetView(autocomplete.Select2QuerySetView):
    def get_result_label(self, result):
        """Return the label of a result."""
        template = get_template("autocomplete_light/item.html")

        context = Context({"item": result})
        return mark_safe(template.render(context))

And the template autocomplete_light/item.html is:

<b>{{ item.name }}</b>

But thats being rendered as:

enter image description here

But the JSON is correct with the right tags:

{"pagination": {"more": false}, "results": [{"text": "<b>Victoria</b>", "id": 11}]}

How can I get django-admin to render the HTML properly?


edit: I found some extra documentation on custom HTML and tried setting attrs={'data-html': 'true'} against the widget, but its still not working


Solution

  • As always the answer is subclassing, in this case the tip is to override get_result_title:

    class CustomisableAutocomplete(autocomplete.Select2QuerySetView):
        template_name = "autocomplete_light/item.html"
    
        def get_result_title(self, result):
            """Return the label of a result."""
    
            template = get_template(self.template_name)
            context = Context({"result": result})
            return template.render(context)
    

    If you want to have a title that isn't cluttered with tags, you can override get_results and return more data:

    class CustomisableAutocomplete(autocomplete.Select2QuerySetView):
        template_name = "autocomplete_light/item.html"
        def get_result_title(self, result):
            """Return the title of a result."""
            return six.text_type(result)
    
        def get_result_text(self, result):
            """Return the label of a result."""
    
            template = get_template(self.template_name)
            context = Context({"result": result})
            return template.render(context)
    
        def get_results(self, context):
            """Return data for the 'results' key of the response."""
            return [
                {
                    'id': self.get_result_value(result),
                    'title': self.get_result_title(result),
                    'text': self.get_result_text(result),
                } for result in context['object_list']
            ]