Muhammad Hamid Raza
Muhammad Hamid Raza

Reputation: 205

Understanding request parameters in python

I have following piece of code. Can anyone please help me understand what is actually going on in this code?

Especially, self.request.GET.get and page < 1 and 1 or page part.

def get(self, *v, **kv):
    page = int( self.request.GET.get('page', 1) )
    page = page < 1 and 1 or page
    items_per_page = int( self.request.GET.get('items_per_page', 500))
    items_per_page = items_per_page < 1 and 500 or items_per_page
    from_date = convert_to_utc(parse_datetime(self.request.GET.get('from')))[0] \
                or datetime.utcnow().replace(hour=0, minute=0, second=0, microsecond=0)
    to_date = convert_to_utc(parse_datetime(self.request.GET.get('to')))[0]

Upvotes: 0

Views: 2245

Answers (2)

Brendan Goggin
Brendan Goggin

Reputation: 2381

@mhawke posted a great answer, but I still want to expand on it a bit.

Here is the webapp2 documentation for the request object. I highly recommend taking a look at that, and also the Webob documentation for the request, because webapp2 Requests and Responses are taken from the Webob framework (go ahead and take a look at the response docs while you're at it).

An important thing to note is that the GET data is a multi-dict, which also comes from the Webob framework. A multidict is basically a dict, but one key can have multiple values. Here is an example from the webapp2 docs:

request = Request.blank('/test?check=a&check=b&name=Bob')

# The whole MultiDict:
# GET([('check', 'a'), ('check', 'b'), ('name', 'Bob')])
get_values = request.GET

# The last value for a key: 'b'
check_value = request.GET['check']

# All values for a key: ['a', 'b']
check_values = request.GET.getall('check')

# An iterable with all items in the MultiDict:
# [('check', 'a'), ('check', 'b'), ('name', 'Bob')]
request.GET.items()

That info will come in handy if you end up using checkboxes to provide a list of values for one key (a "check all that apply" section on a form).

So in your code, self.request.GET.get('page', 1) is retrieving the value for page from the multidict, and returning 1 if that key is not found. This same logic is applied for the key items_per_page, from, and to: retrieve the value for that key, and return the default value provided if the key is not found.

Then you have these two lines:

page = page < 1 and 1 or page

and

items_per_page = items_per_page < 1 and 500 or items_per_page

As @mhawke stated, this is a nasty way of saying:

if page < 1:
    page = 1
if items_per_page < 1:
    items_per_page = 500

In fact, if you get a chance you should change that code to be more readable.

Upvotes: 1

mhawke
mhawke

Reputation: 87134

self.request.GET is provided by the webapp2 framework through the class in which get() is implemented. It provides your code with access to a dictionary containing any query string parameters that were sent with the HTTP request, e.g. a URL such as:

http://localhost/resource?page=1&items_per_page=20

has two parameters in the query string: page and items_per_page with values 1 and 20 respectively. webapp2 processes the URL and provides your application with a dictionary containing these parameters, e.g. self.request.GET might look like this:

{'page': 1, 'items_per_page': 20, ...}

self.request.GET.get() performs a lookup in the dictionary for the requested key (e.g. page) and returns its value if the key is present in the dictionary. If the key is not in the dictionary a default value is returned; for self.request.GET.get('page', 1) the default value would be 1 if the URL did not contain the page query parameter. See dict.get() for details.


The next bit is a nasty way of defaulting to page 1 if the value supplied in the query string is less than 1:

page = page < 1 and 1 or page

can be written like this:

page = ((page < 1) and 1) or page

If the user supplied value of page is less than 1, page < 1 will be True, then True and 1 will evaluate to 1 - and so 1 is used as the value of page. Any value >=1 will result in page < 1 being False so the or clause will be the value of the expression.

This can be rewritten in a much more readable way like this:

if page < 1:
    page = 1

or like this:

page = 1 if page < 1 else page

which even more clearly shows the intention of the code.

Upvotes: 3

Related Questions