Converting GET request parameter to int ... if it is numeric - python

lets say i'm showing some data to user , i want user to be able to perform some sort of filtering on a numeric field in the database using a GET form so i have something like this
code = request.GET.get('code')
condition = {}
if( code is not None and int(code) > 0 ):
condition['code'] = int(code)
Somemodel.objects.filter(**condition)
but this works only if i code contains a number otherwise i get this error
invalid literal for int() with base 10: ''
so what is the pythonic way to handle this problem ? should i use try/except block? i perfer to handle this in the same if statement considering i might add other filters

isnumeric could check if code can be cast to int and also check that code is positive (when converted to an integer) thus replacing int(code) > 0:
if code is not None and code.isnumeric():
condition['code'] = int(code)

You should use a Django form with one or more IntegerFields; they do this conversion for you, then you can get the result from cleaned_data.

This function convert GET params to python numeric/bool accordingly:
def convert_params_to_int_or_bool(params):
for k, v in params.items():
if v.isnumeric():
params[k] = int(v)
if v == 'false':
params[k] = False
if v == 'true':
params[k] = True

The reason you are getting this error because int() expects the value in number it can be in the form string but it should be a number like "22","33" etc are valid .
But in your case you are passing empty that's why its raising an error. You can achieve your desired output using type(), it helps you in checking the type of number
So the modified code is
code = request.GET.get('code')
condition = {}
if( code is not None and type(code) == int ):
condition['code'] = int(code)
Somemodel.objects.filter(**condition)
Hope it helps :)

Related

Python: Split String and convert to other type

I have a function which could get a String formatted like this:
"true"^^<http://www.w3.org/2001/XMLSchema#boolean>
"100"^^<http://www.w3.org/2001/XMLSchema#int>
Now i want to split the String on the ^^ Characters and convert the first part of the string based on the second part. I also want to remove the " first before converting.
This is my code which i use for this:
def getValue(tObject):
toReturn = tObject.split("^^")
if len(toReturn) == 2:
if toReturn[1] == "<http://www.w3.org/2001/XMLSchema#boolean>":
return bool(toReturn[0].replace('"', ""))
elif toReturn[1] == "<http://www.w3.org/2001/XMLSchema#int>":
return int(toReturn[0].replace('"', ""))
return None
But i'm not so happy with it. Is there maybe a more elegant (pythonic) way to archive this?
You can use a regex, to
check if the given value is valid
retrieve the value to cast, and the way to cast
PATTERN = re.compile(r'"(.*)"\^\^<http:.*#(\w+)>')
types = {"boolean": bool, "int": int}
def getValue(value):
m = PATTERN.fullmatch(value)
return types[m.group(2)](m.group(1)) if m else None
Instead of if len(...) you could just try to unpack the result and except a ValueError. Then you can use a dict for the types and str.strip instead of str.replace:
types = {'boolean': bool, 'int': int}
try:
value, type_hint = tObject.split('^^')
except ValueError:
return None
else:
return types[type_hint.rstrip('>').rsplit('#', 1)[1]](value.strip('"'))
Firstly, you could remove return None, since the function returns None by default.
Secondly, you could use toReturn[1].endswith("boolean>") to match the end of the string, instead of matching the whole string with toReturn[1] == "<http://www.w3.org/2001/XMLSchema#boolean>". Same with the int string as well.
Thirdly, you could store the return value in one variable before the if..elif, then you don't have to calculate it twice for each condition.
Code:
def getValue(tObject):
toReturn = tObject.split("^^")
if len(toReturn) == 2:
return_value = toReturn[0].replace('"', "")
if toReturn[1].endswith("boolean>"):
return bool(return_value)
elif toReturn[1].endswith("int>"):
return int(return_value)
This might not be much of a logic improvement, but the code does look less cluttered now. If you wan't more terse, "pythonic" ways of doing this problem, the other answers might be more suitable.

python isdigit() returning unexpected result

I'm making a basic BMI calculation program for a class assignment using TKinter for the GUI, and ran into a problem when trying to validate the user's input.
I'm trying to only allow numerical input and to deactivate the 'calculate' button and send an error message when the user enters anything that's not a number. However, at the minute it will throw up an error for a single digit number (e.g. 2) but will accept multiple digits (e.g. 23). I'm quite new to this so could you please explain why this is happening, or if there's a better way to write this?
Here are the relevant parts of my code:
#calculate button
cal = ttk.Button(main, text = 'Calculate!')
cal.grid(row = 4, column = 2)
#height entry box
hb = tk.Entry(main, textvariable = height)
hb.grid(row = 2, column = 2)
hb.bind('<Key>', lambda event: val(hb.get()))
#validation error message
vrs = tk.Label(main, text = 'Please enter a number in the box')
vrs.grid(row = 8, column = 2)
#so that its position is saved but won't appear until validation fails
vrs.grid_remove()
#validation function
def val(value):
if value.isdigit():
print('valid')
vrs.grid_remove()
cal.state(['!disabled'])
else:
print('invalid')
vrs.grid()
cal.state(['disabled'])
Thanks in advance for your help.
The first thing you should do to debug this is to print out value inside of val, to see if your assumptions are correct. Validating your assumptions is always the first step in debugging.
What you'll find is that your function is being called before the digit typed by the user is actually inserted into the widget. This is expected behavior.
The simple solution is to put your binding on <KeyRelease>, since the default behavior of inserting the character is on <KeyPress>:
hb.bind('<Any-KeyRelease>', lambda event: val(hb.get()))
Even better would be to use the Entry widget's built-in validation features. For an example, see https://stackoverflow.com/a/4140988/7432
You need to use isdigit on strings.
val = '23'
val.isdigit() # True
val = '4'
val.isdigit() # True
val = 'abc'
val.isdigit() # False
If you're not sure what the type of the input is, cast it first to a string before calling isdigit().
If you want only one-digit numbers, you'll have to check if int(val) < 10
isdigit is a string method. Are you expecting a string, an int, or a float?
You can add some typechecking code like this, so that your program validates regardless of whether the value is a numerical type or a string type.
def val(value):
if type(value) in (int, float):
# this is definitely a numerical value
elif type(value) in (str, unicode, bytes):
# this is definitely a string

Python "if" statement - if xpath is true

im trying to code in python (very new to it) and need to check if an xpath is there then variable = the xpath but if not variable = string.
An example is below
if tree.xpath('//*#id="page"]/div[1]/div/main/div/article/div/div[1]/section[2]/p[1]/span/text()') = true
$value = tree.xpath('//*#id="page"]/div[1]/div/main/div/article/div/div[1]/section[2]/p[1]/span/text()')
else
$value = ''
You should really start by doing the whole official tutorial before anything else, as it will anwser your question.
First point : Python objects all have a 'truth' value in a boolean context, which is defined by the object's type and actual value. For builtin types, all empty containers (lists, dicts, sets etc), the empty string, all numerical zeros and the None object are false, everything else is true. For non builtin types you'll have to check the package's documentation.
The builtin type bool will also tell you the boolean value of a given object, so all of the below tests are equivalent:
if myobj:
xxx
if bool(myobj):
xxx
if bool(myobj) == True:
xxx
BUT keep in mind that it doesn't imply that bool(myobj) is the same as myobj - the first one is the boolean value of your object, so the following is NOT equivalent (unless myobj is one of True, 1 or 1.0):
if myobj == True:
xxx
Now wrt/ your actual code snippet: it's not valid Python (bad indentation, invalid identifier $value, invalid use of the assignment operator =, missing : after the if and else statements, wrong capitalization for True...)
Assuming you meant:
# let's make this at least readable:
path = '//*#id="page"]/div[1]/div/main/div/article/div/div[1]/section[2]/p[1]/span/text()'
if tree.xpath(path) == True:
value = tree.xpath(path)
else:
value = ''
The obvious error is the explicit test against True (tree.xpath() doesn't return a boolean). You either have to explicitely cast the return of tree.xpath() to a boolean (which is quite verbose, totally useless and definitly unpythonic) or just let Python do the right thing by removing the == True part of your test.
As a side note: calling tree.xpath twice in a row with the same argument is a waste of processor cycle (both calls will return the same value), so use a variable instead - it will also make your code much more readable and maintainable. The Pythonic version of your code would look something like:
path = '//*#id="page"]/div[1]/div/main/div/article/div/div[1]/section[2]/p[1]/span/text()'
found = tree.xpath(path)
value = found if found else ''
or even more simply:
path = '//*#id="page"]/div[1]/div/main/div/article/div/div[1]/section[2]/p[1]/span/text()'
value = tree.xpath(path) or ''
since the or operator will not yield a boolean value but either the first of it's operand that has a true value or the last operand if none has a true value.
#No need to test == if value is bool. and you not check, you assign value with one =
if anything:
#Then do this
else:
#Do this

Python 3.3 string errors

I'm trying to make a very basic calculator to familiarize myself with the basics of python. Part of the code involves asking for inputs and setting those as different variables, but the variables put in as inputs are stored as strings, even though they're entered as numbers:
def change_x_a():
velocity_i = input("Initial Velocity?")
velocity_f = input("Final Velocity?")
time = input("Time?")
float(velocity_i)
float(velocity_f)
float(time)
answer = (0.5*(velocity_i+velocity_f)*time)
print(answer)
Is there a fix for this?
float() doesn't modify the variable you pass it. Instead, it converts the value you give it and returns a float.
So
float(velocity_i)
by itself does nothing, where
velocity_i = float(velocity_i)
will give the behavior you're looking for.
Keep in mind that float() (and the other type-conversion functions) will throw an exception if you pass them something they're not expecting. For a better user experience, you should handle these exceptions1. Typically, one does this in a loop:
while True:
try:
velocity_i = float(input("Initial Velocity?"))
break # Valid input - stop asking
except ValueError:
pass # Ignore the exception, and ask again
We can wrap this behavior up into a nice little function to make it more re-usable:
def get_input(prompt, exptype):
while True:
try:
return exptype( input(prompt) )
except ValueError:
pass # Ignore the exception, and ask again
and call it like this:
val_f = get_input('Give me a floating-point value:', float)
val_i = get_input('Give me an integer value:', int)
1 - Wow, I just realized that I independently wrote almost the exact same code as the Python tutorial, which I linked to, after the fact.
You can convert the inputs to float when you take them from the user.
Try
velocity_i = float(input("Initial Velocity?")
And so on.
Yes. Simply convert it to a float:
velocity_i = float(input("Initial Velocity?"))
or an integer:
velocity_f = int(input("Final velocity?"))

How to Check if request.GET var is None?

I'm getting into django and this is getting me a headache. I'm trying to get a simple GET variable. URL is site.com/search/?q=search-term
My view is:
def search(request):
if request.method == 'GET' and 'q' in request.GET:
q = request.GET.get('q', None)
if q is not None:
results = Task.objects.filter(
Q(title__contains=q)
|
Q(description__contains=q),
)
...return...
else:
...
else:
...
Search queries like mysite.com/search/? (without q) get through the first if correctly.
The problem is in queries like mysite.com/search/?q=. They don't get caught by if q is not None:
So, the short answer would be How can I check q == None? (I've already tried '', None, etc, to no avail.)
First, check if the request.GET dict contains a parameter named q. You're doing this properly already:
if request.method == 'GET' and 'q' in request.GET:
Next, check if the value of q is either None or the empty string. To do that, you can write this:
q = request.GET['q']
if q is not None and q != '':
# Do processing here
Notice that it is not necessary to write request.GET.get('q', None). We've already checked to make sure there is a 'q' key inside the request.GET dict, so we can grab the value directly. The only time you should use the get method is if you're not sure a dict has a certain key and want to avoid raising a KeyError exception.
However, there is an even better solution based on the following facts:
The value None evaluates to False
The empty string '' also evaluates to False
Any non-empty string evaluates to True.
So now you can write:
q = request.GET['q']
if q:
# Do processing here
See these other resources for more details:
Python: Truth Value Testing
Python: dict.get
Thanks for the clarification by #Ned.
Found a complete explanation here.
Basically:
'==' can be thought of as "value equality", that is, if two things look
the same, == should return a true value. (For those with a Java
background, Python's == is actually doing something akin to an equals()
method.)
'is' can be thought of as 'object
identity', that is, if the two things
actually are the same object.

Categories

Resources