How can I search the choice field using display name?

Issue #70 invalid
Former user created an issue

Sorry to create a duplicated issue in the example page.

I want to query the item from the database using django SmallIntegerField. The code I used is

Here is the class defination:

class Equipment(models.Model):
    asset_status = (
        (0, 'online'),
        (1, 'offline'),
        (2, 'unknown'),
        (3, 'wrong'),
        (4, 'x'),
    )
status = models.SmallIntegerField(
        choices=asset_status, default=0, verbose_name='Device Status')

The query code I used is

def filter_queryset(self, qs):
    sSearch = self.request.GET.get('search[value]', None)
    print(sSearch)
    if sSearch:
        qs = qs.filter(Q(status__icontains=sSearch))
        return qs

I want to query this column by 'online', 'offline' and so on. Do you know how to do this?

The reference I have searched are

https://stackoverflow.com/questions/41054755/search-choice-field-by-the-name-in-django-python

I also see the Choices API in https://django-model-utils.readthedocs.io/en/latest/utilities.html#choices

But there is no Q. I am not sure whether it works. Could you please tell me about this?

And I searched for a method called get_FOO_display, but I don't think it can be solved. Neither did I think it can be combined with Q.

Thanks

Comments (2)

  1. Benjamin Riddell

    There are 2 solutions that I can suggest. I don’t think this is particularly relevant to django-datatables-view, rather it is more just the how you’re handling Django instead. Your filter is going to be ran against the database so it needs to use the values that are in the database. The database does not store the human-readable name but rather it stores the integer.

    My first recommendation is that you try and follow the MVC pattern that Django follows. When writing your code, keep your values and their human-readable names localaised. So in your current situation, I would not submit the human-readable name in the request. I would instead submit the actual value. So your input field that is making the request would look more like:

    <select name="search">
      <option value="0">online</option>
      <option value="1">offline</option>
      <option value="2">unknown</option>
      <option value="3">wrong</option>
      <option value="4">x</option>
    </select>
    

    This can be done in the template with ease so that choices only need to be updated once in the right place. I would suggest reading up on using choices in forms with Django. (Sorry I don’t have time to find the specific readings but it does exist in their documentation.)

    With this solution, when the request is made, the integer value will get sent instead. The integer value would


    If you don’t want to do my first recommendation. Then you can match the string value made in the request, to the integer value of the choice. This can be done with dict comprehension.

    reversed_asset_status = {human_name.lower(): value for value, human_name in Equipment.asset_status}

    Your query code would use this line instead

    qs = qs.filter(Q(status=reversed_asset_status(sSearch.lower())))


    Please note that the first recommendation is actually tidier and far more extensible than the latter. Though the second option looks like you only need to change 2 lines of code. The above option means you don't need to override the filter_queryset function.

  2. Maciej Wisniowski repo owner

    Please use the solution suggested by @Benjamin Riddell (thanks Benjamin). This is not directly related to django-datatables-view so I'm closing this as invalid.

  3. Log in to comment