8

OVERVIEW


A url with query parameters looks like.

http://example.api.com/search/?name=jhon&age=26

and on view if i am using django-filter all parameters are automatically extracted from request and it will return a filtered query-set .

views.py

class SearchView(TemplateView):
   template_name = "search.html"

   def get_queryset(self):
       return SearchFilter(request.GET, queryset=Model.objects.all()).qs

   def get_context_data(self, **kwargs):
      context = super(SearchView, self).get_context_data(**kwargs)
      return context

If i want to extract it manually from request.GET i can do.

def get_queryset(self):
   # extracting query parameter 
   q = self.request.GET.get('name')

PROBLEM STATEMENT


My search url looks like

 http://example.api.com/search/jhon-26

I am doing this because i don't want to reveal keys like 'name' and 'age' to public, this is for security abstraction these are the column of my db table .

I am getting jhon-26 in **kwargs, I want to split it and set as query parameter to request.GET so that my filter class will work fine

QUESTION


Is there anything to set attribute to request.GET?

# may be any set function available for this
self.request.GET.set('name', 'jhon')

How can i achieve this.

Satendra
  • 6,755
  • 4
  • 26
  • 46

3 Answers3

29

I found solution to set query parameters to request.GET here

As request.GET QueryDict instance is immutable so we can not modify it directly so for that we need to set its _mutable property to True

if not request.GET._mutable:
   request.GET._mutable = True

# now you can edit it
request.GET['name'] = 'jhon'
request.GET['age'] = 26
Satendra
  • 6,755
  • 4
  • 26
  • 46
  • 2
    This is definitely not the recommended approach. using `request.GET = request.GET.copy()` then adding properties to this `request.GET['name'] = 'jhon'` is a much safer solution. As the highest rated answer in your linked solution states "This has been purposefully designed so that none of the application components are allowed to edit the source request data" – MeanwhileInHell Jul 28 '22 at 09:39
2

Well, you can do what django-filter does for you by simply saying:

  result = Model.objects.filter(**dict)

However, for request.GET, you'd have to format it to make a valid dictionary since it's values are usually list. You can simply do:

  formatted = {key: dictionary.get(key)[0] for key in dict(request.GET).keys()}

And then you can add the remaining variables into it:

   formatted['age'] = 26 //As extracted from **kwargs. etc.

And then do:

  result = Model.objects.filter(**formatted)

If you do not necessarily need to use request.GET (Since there's a way around what django-filter does), then you can simply form your dictionary and use it in the model's filter method.

By the way, why are you using request.GET if you do not want the public to see your data? How did you form your url? You may want to Ignore all of that as far as your code is working fine anyway!

yusuf.oguntola
  • 492
  • 3
  • 10
  • django-filters configurations allow us to make filtering easy and remove overheads which we face if we write manual query to filter object, also it make a filter feature modular which is a good practise to be followed. Also i want to show my data to public but i just want to abstract keys which are directly a column in db table, So if i manage to do what i am asking is much efficient way i guess. – Satendra Jul 19 '17 at 11:45
  • It is achievable without django-filter as you explained. But how it will work with django-filter? is there any possible way? – Satendra Jul 19 '17 at 12:11
  • 1
    You may want to add your values to request.GET then. `request.GET` is a dict so you can simply do `request.GET['new_key'] = value`. However, it's immutable by default so you'd have to remove the immutability with `request.GET._mutable = True` **This is not recommended though** – yusuf.oguntola Jul 19 '17 at 15:53
1

Build your filter dynamically like so;

    query_data={}
    name = request.query_params.get('name')
    age = request.query_params.get('age')
    if name is not None:
        query_data['name'] = name
    if age is not None:
        query_data['age'] = age

    return Model.objects.filter(**query_data)
        
7guyo
  • 3,047
  • 1
  • 30
  • 31