Home > Blockchain >  Django Return Queryset from Database table by filtering using Dictionary values
Django Return Queryset from Database table by filtering using Dictionary values

Time:05-22

My goal is to return rows from the books table using values sent by a user through a search form. The search form contains multiple fields author, ISBN and title.

NB: In the code, the author field is a char, but converted to ID based on authors name due to foreign key relation.

In this code, there's a get request converted to Dictionary and transformed to allow it to query data from the books table.

def search(request):

    form = BooksForm()

    if request.method == 'GET':

        # convert get request to dictionary
         book_search = dict(request.GET)
         print("data before cleaning", book_search)

       #get the name from the dictionary get request
         author_name =request.GET['author']
       
        #get the author id from the author table
         author = Author.objects.filter(full_name__contains=author_name).values()

         #get author_id from author queryset
         author_id = author[0]['id']

      #update the dict with the author id to allow search in books models (foreing key)
         book_search['author'] = author_id
         print("data after cleaning",book_search)

         result_set = Book.objects.filter(**book_search)

         print("book search queryset",result_set)

Problem: When I query the books table using the dictionary it returns an empty query set and I want it to return books from in table. Does anyone have an idea of how I can make the code work?

CodePudding user response:

Please don't allow to filter on arbitrary keys. This makes the view sensitive to request forgery where a person can for example make a request with author__gender as key, and F as value, and thus can expose data that you might want to hide.

You can use a library like django-filter [GitHub] to determine how to filter the queryset. Here you can make a filter that looks like:

import django_filters

class BookFilter(django_filters.FilterSet):
    author = django_filters.CharFilter(
        field_name='author__full_name',
        lookup_expr='contains'
    )

    class Meta:
        model = Book
        fields = ['isbn']

With this filter, it will only use the author and isbn keys of the request.GET, and thus ignore other keys that might want to filter on sensitive data.

You then can use this with:

def search(request):
    book_filter = ProductFilter(request.GET)
    print('book search queryset', book_filter.qs)
    return render(request, 'name-of-template.html', {'book_filter': book_filter})

In the template you can then use {{ book_filter.form }} for a form based on the filter, and {% for item in book_filter.qs %} … {% endfor %} to enumerate over the items in the filtered queryset.

  • Related