I am trying to pass an argument to a method with a key to get a Django queryset. The key will be dependent on whatever the user passes through.
Here's an example:
The initial value for filter will be id=1 (a string), I am including a split based on commas in case the user passes in additional filters, such as, title=blahblahblah
filter_split = filters.split(",")
itemFilter = Items.objects # from Django
for f in filter_split:
itemFilter = itemFilter.filter(f)
I have also tried splitting the leftover string as two separate values (key and value) and passing them as such:
itemFilter = itemFilter.filter(key = value)
With no luck.
How can I pass programmatic arguments to a method in Python? Or is there another way to programmatically filter the queryset with Django?
You can pass programmatic arguments with *list and **dict in the argument list.
a = [2,3,4]
function(1, *a) # equal to function(1,2,3,4)
b = {'x':42, 'y':None}
function(1, **b) # equal to function(1, x=42, y=None)
In your case just create a dictionary, assign the key-value pairs from your user input and call itemFilter.filter(**your_dict).
It's not possible to pass a string e.g. "id=1" to filter.
You can create a dictionary dynamically, then pass it to filter using ** unpacking.
key = "id"
value = 1
kwargs = {key: value}
MyModel.objects.filter(**kwargs)
Your other approach to try MyModel.objects.filter(key=value) doesn't work, because it doesn't use the variable key, it tries to filter on the field 'key'
Related
I want to filter a model with a field but I want to pass the field as a string variable. How can I do it?
For example:
the_field = 'name'
TheModel.objects.filter(the_field='Gazelle')
What should I replace the_field with?
You can use dictionary unpacking:
the_field = 'name'
TheModel.objects.filter(**{the_field: 'Gazelle'})
Notice the two asterisks (**) in front of the dictionary. If you call a function with f(**{'a': 4}), that is equivalent to calling it with f(a=4).
or you can make use of a Q object, and pass it a 2-tuple that represents the key and value:
from django.db.models import Q
the_field = 'name'
TheModel.objects.filter(Q((the_field, 'Gazelle')))
I have a code which pass variable into a method if this variable exists in property file.
if all(hasattr(globals().get('properties'), var) for var in ['NAME','VALUE']):
return reader.get_smth(name=properties.NAME, value=properties.VALUE)
else:
return reader.get_smth()
it's obvious that method get_smth() has default values for every passed parameter.
So how can i pass only existing parameters (reader.get_smth(name=properties.NAME) or reader.get_smth(value=properties.VALUE)) avoiding large number of elif's
P.S. Parameters which have to be passed more that 2.
You can use named keywords **kwargs here. First we construct a dictionary that maps the names of the parameters of the get_smth function (e.g. name) to the names of the properties (e.g. NAME):
prop_dict = {'name': 'NAME', 'value': 'VALUE'}
next we can use the following approach:
reader.get_smth(**{k: getattr(properties, v)
for k,v in prop_dict.items()
if hasattr(properties, v)})
Look into star expressions.
Try the following:
reader.get_smth(**properties)
This will unpack key-value pairs from a dictionary into arguments for the function.
The property names will have to be the same as the argument names though (it seems the properties are uppercase and args lowercase in your program).
Let's take as an example the following code :
ALL = "everything"
my_dict = {"random":"values"}
def get_values(keys):
if keys is None:
return {}
if keys is ALL:
return my_dict
if not hasattr(keys, '__iter__')
keys = [keys]
return {key: my_dict[key] for key in keys}
The function get_values returns a dict with the given key, or keys if the parameter is an iterable, an empty dictionary if the parameter is None or the whole dictionary if the parameter is the constant ALL.
The problem with this happens when you would want to return a key called "everything". Python might use the same reference for ALL and the parameter (since they're both the same immutable), which would make the keys is ALL expression True. The function will therefore return the whole dict, so not the intended behavior.
It would be possible to assign ALL to an instance object of a class defined specifically for that purpose, or to use the type method to generate an object inline, which would make ALL a unique reference. Both solutions seem a little overkill though.
I could also use a flag in the function declaration (i.e. : def get_values(keys, all=False)), but then I can always derive the value of a parameter from the other (if all is True, then keys is None, if keys is not None, then All is not False), so it seems overly verbose.
What is your opinion on the previously mentioned techniques, and do you see other possible ways of fixing this ?
Don't use a value that could be (without extreme effort) a valid key as the sentinel.
ALL = object()
However, it seems much simpler to define the function to take a (possibly empty) sequence of keys.
def get_values(keys=None):
if keys is None:
keys = []
rv = {}
for key in keys:
# Keep in mind, this is a reference to
# an object in my_dict, not a copy. Also,
# you may want to handle keys not found in my_dict:
# ignore them, or set rv[key] to None?
rv[key] = my_dict[key]
return rv
d1 = get_all_values() # Empty dict
d2 = get_all_values([]) # Explicitly empty dict
d3 = get_all_values(["foo", "bar"]) # (Sub)set of values
d4 = get_all_values(my_dict) # A copy of my_dict
In the last case, we take advantage of the fact that get_all_values can take any iterable, and an iterator over a dict iterates over its keys.
Have a requirement in dynamic querying where i would like to compare 2 columns of a table say "column_a" and "column_b" (all columns are strings). The actual columns to compare are decided at run-time.
I'm using kwargs to create a dictionary. But Django assumes that RHS is an absolute value & not a column of the same table. Using F() is an option, but i cant find any documentation of using F() in kwargs.
if i use kwargs = {'predicted_value':'actual_value'}
'actual_value' is used as a literal string instead of column name
How do i use something like:
kwargs = {'predicted_value':F('actual_value')} and pass it as Model.objects.filter(**kwargs)
Alternately, is there a way to use F('column') in LHS ?
e.g. Model.objects.filter(F(column1_name) = F(column2_name))
For a non-dynamic filter field, I would use:
from django.db.models import F
Model.objects.filter(some_col=F(kwargs.get('predicted_value')))
But if you need it all dynamically, you can try with:
kwargs = {'predicted_value':F('actual_value')}
Model.objects.filter(**kwargs)
You can even access related fields:
kwargs = {'fk_field__somefield':F('actual_value')}
Model.objects.filter(**kwargs)
I have a following structure of QueryDict:
QueryDict: {u'tab[1][val1]': [u'val1'], u'tab[1][val2]': [u'val2'], u'tab[0][val1]': [u'val1'], u'tab[1][val2]': [u'val2']}
I want to store it in an iterable variable so I can do something like this:
for x in xs:
do_something(x.get('val1'))
where x is tab[0] etc
I tried:
dict(request.POST._iteritems())
but it doesn't return tab[0] but tab[0][val1] as an element.
Is it possible to store entire tab[idx] in variable?
Django's QueryDict has a few additional methods to deal with multiple values per key compared to the traditional dict; useful for your purposes are:
QueryDict.iterlists() Like QueryDict.iteritems() except it includes
all values, as a list, for each member of the dictionary.
QueryDict.getlist(key, default)
Returns the data with the requested key, as a Python list. Returns an empty list if the key doesn’t exist and no default value was provided. It’s guaranteed to return a list of some sort unless the default value was no list.
QueryDict.lists()
Like items(), except it includes all values, as a list, for each member of the dictionary.
So you can do something like:
qd = QueryDict(...)
for values in qd.lists():
for value in values:
do_something(value)
Also note that the "normal" dict methods like get always return only a single value (the last value for that key).