wagtail-autocomplete icon indicating copy to clipboard operation
wagtail-autocomplete copied to clipboard

Autocomplete Manager

Open harrislapiroff opened this issue 5 years ago • 2 comments

As the amount of customization offered on autocompletable objects grows, it seems useful to organize the customizable attributes and methods into a single object. This idea grew out of the discussion in #47.

Currently you can customize autocomplete properties like so:

class MyAutocompletableModel(ClusterableModel):
    name = models.CharField(max_length=255)

    autocomplete_search_field = 'name'

    def autocomplete_label(self):
        return self.name

    @classmethod
    def autocomplete_create(kls: type, value: str):
        return kls.objects.create(name=value)

If implemented now, #36 would add yet another classmethod to the mix. To clean this up and keep it more organized, we'll introduce a new AutocompleteManager type. The default autocomplete manager would look something like this:

class AutocompleteManager(object):
    search_field = 'title'
    label_field = 'title'

    def search(self, model_class: type, value: str) -> QuerySet:
        query_kwargs = {'{}__icontains'.format(self.search_field): value}
        return model_class.objects.filter(**query_kwargs)

    def label(self, obj: models.Model) -> str:
        return getattr(obj, self.label_field)

A subclass of it might look like

class SearchingAutocompleteManager(AutocompleteManager):
    def search(self, model_class: type, value: str) -> QuerySet:
        return model_class.objects.search(value)

    # Notice that no `create` method is specified by default,
    # but can be specified on a subclass
    def create(self, model_class: type, value: str) -> models.Model:
        return model_class.objects.create(title=value)

    def label(self, obj: models.Model) -> str:
        return obj.__unicode__()

You would register a particular manager with a particular target either declaratively:

class MyAutocompletingPage(Page):
    # ...
    autocomplete_manager = SearchingAutocompleteManager()

or with a class decorator:

@autocompletable(SearchingAutocompleteManager())
class MyAutocompletingPage(Page):
    # ...

harrislapiroff avatar May 17 '19 21:05 harrislapiroff

Veeeeeery preliminary proof of concept work for this exists on 50-manager

harrislapiroff avatar Jun 05 '19 13:06 harrislapiroff

@harrislapiroff this is looking really good. I think a major benefit of breaking things off into a separate component like this is: It could give developers flexibility to list the same model in different ways.

For example:

  • Include product codes in an admin-facing list, but only show product names in a public-facing one
  • Include draft items in an admin-facing list, but not a public-facing one
  • Show the draft_title in an admin-facing list, but title in a public-facing one

How difficult do you think it would be to add support for this?

ababic avatar Nov 16 '19 14:11 ababic