Pull requests

#4 Declined
Repository
evildmp evildmp
Branch
modifiers
Repository
spookylukey spookylukey
Branch
modifiers

Modifiers for filters (not ready for merge)

Author
  1. evildmp avatarevildmp
Reviewers
Description

OK, here's what I've got so far.

Modifier class

Firstly, I have introduced a new Modifier class.

Every Filter instance has a modifier attribute, which is an instance of the Modifier class.

The Filter is initialised with a modifier argument, which unless specified is the base Modifier class, which does nothing.

In a FilterSet we can now do:

fields = [
    (
        'author', 
        {"modifier": TextSearchModifier()}
    ),
]

This sub-class of Modifier, TextSearchModifier, is the only one I have created so far.

Initialising Modifier

Each Modifier class takes two arguments when initialised, template and search_key.

supplied templates

Even if the Modifier doesn't do anything different when it comes to querying, it might still want to use a different template, which is now also determined by the Modifier.

The templates themselves meanwhile are in a templates directory, and I have provided a django_easyfilters/text_search.html for the text search.

apply_filter()

The other important thing a Modifier has is its own apply_filter() method.

Now when FilterSet.apply_filters() is looping over the filters, it will also call the apply_filter() methods in the Modifier, which might do something different, if required (as the one in TextSearchModifier does).

The TextSearchModifier() method makes use of the search_key. If it's not provided, it will just default to filter.field_obj.name. That's only useful if we want to match the exact text on that particular field, so we can also do for example:

fields = [
    (
        'author', 
        {
            "modifier": TextSearchModifier(
                search_key="author__name__contains",
            ), 
        }
    ),
]

which means we could search for author FKs containing the term.

Template

I have used:

{% load pagination_tags %}

{% autopaginate newsarticles 20 %}

<form action="" method="GET">
    <input type=submit name="searchbtn" value="Search">
    {{ newsarticlesfilter }}
</form>

{% paginate %}

{% for newsarticle in newsarticles %}
  <div class="resource">
    <h2>{{ newsarticle.title }}</h2>
    <div><b>Please contact:</b>
    {% for person in newsarticle.please_contact.all %}
      {{ person }}{% if not forloop.last %},{% endif %}
    {% endfor %}
    <br><b>Published by:</b> {{ newsarticle.hosted_by }}</div>
  </div>
{% endfor %}

So I have wrapped the whole of the filter variable in a form, and each Filter in the Filterset will pump either a django_easyfilters/text_search.html or a django_easyfilters/default.html into it.

It needs to be like this because there could be multiple text search filters in action, and while each could have its own Clear button, there should only be one Search button I think.

Issues

It almost works. http://v029.medcn.uwcm.ac.uk:8000/news-and-events/django_easy_filter/

Here's my view:

class NewsArticleFilterSet(FilterSet):
    fields = [
        (
            'hosted_by', 
            {
                "modifier": class NewsArticleFilterSet(FilterSet):
    fields = [
        (
            'hosted_by', 
            {
                "modifier": TextSearchModifier(
                    search_key="hosted_by__name__contains",
                ), 
            }
        ),
        # (
        #     'title', 
        #     {
        #         "modifier": TextSearchModifier(
        #             search_key="title__contains",
        #         )    
        #     }
        # ),
        'date',  
        ]

Multiple TextSearchModifiers won't work

I've commented out the second one; I'm sure it used to work before with multiple ones, but now, nothing is returned even if the second box is left blank. The URL might look like: ?searchbtn=Search&hosted_by=Public&title=, and even though the searchvariable within the TextSearchModifier.apply_filter() in that case might be null, it still seems to affect the search.

Text searches destroy existing filters

You can do a text search followed by a date filter and that will work, but a text search after a date filter will destroy the date filter. That seems really hard to solve. I have been trying to work out a way to get the existing filters into the context so hidden <input> buttons can restore them into the URL that's created.

I think that fuller view functionality in django-easyfilters will be required for that.

Text search boxes don't retain their text

Again, I think that to do this in django-easyfilters will require a view class or function in it, so it can manipulate what it puts into the templates.

The approach

I am not at all sure of the general approach. However it seemed important to solve this problem not by simply creating new Filter subclasses and types, because the needs for different templates/behaviours could still be part of existing Filters. The needs seem to be orthogonal to each other, hence the creation of the Modifier class to express that.

Comments (1)

  1. evildmp author

    I remembered another thing I wanted to do, though I suspect it won't be possible without JS: if a text form field is left empty, it should not then be reflected in the URL query that's produced.

Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.