Django querying using array for column value - python

I'm making a search function for my website that breaks the entered text by spaces and then checks each work with __contains. I want to expand this so that I can pass through what columns I want it to check __contains with such as "First name", "Last Name"... ect.
What I have now:
def getSearchQuery(search,list,columns=None):
"""
Breaks up the search string and makes a query list
Filters the given list based on the query list
"""
if not columns:
columns = { name }
search = search.strip('\'"').split(" ")
for col in columns:
queries = [Q(col__contains=value) for value in search]
query = queries.pop()
for item in queries:
query |= item
return list.filter(query)
Issue is Q(col__contains=value) doesnt work as "col" is not a column. Is there some way to tell django that that is a variable and not the actual column? I have tried googling this but honestly dont know how to phrase it without putting all my code.

Do it this way:
import operator
from functools import reduce
def getSearchQuery(search, list, columns=None):
"""
Breaks up the search string and makes a query list
Filters the given list based on the query list
"""
if not columns:
return list
search = search.strip('\'"').split(" ")
queries = []
for col in columns:
queries.extend([Q((col+'__icontains', value)) for value in search])
return list.filter(reduce(operator.or_, queries))

Related

How can I add two or more elements to a list from a single input in Python?

What my script is doing now is adding elements to a list. For example, if the user types "JO", I will add "John" to the list. What I want to do now is that, if the user types "2 JO", I add two elements to the list: "John" and "John".
This is how the database looks like now:
Sample database copy.png
This is the code now:
import pandas
data = pandas.read_excel("Sample database copy.xlsx")
name = dict(zip(data["Abbreviation"],data["Name"]))
list1 = []
incoming_msg = input(Please type what you want to add: )
list1.append(name[incoming_msg])
I need to do it all from the same input, I cannot ask separately for quantity and abbreviation. I wanted to know if there is any library that can do this somehow easily because I am a beginner coder. If there is no library but you have any idea how I could solve it, it would be awesome as well.
Thank you so much in advance!
you can use string.split() to split the string by space into a list then use the first element to multiply a list that contains the value from the dictionary and increment it to the result list. see the code
name = dict(zip(data["Abbreviation"],data["Name"]))
list1 = []
incoming_msg = input('Please type what you want to add: ')
incoming_msg = incoming_msg.split() # split the string by space
if len(incoming_msg) == 2: # if there are two elements in the list (number and name)
list1 += [name[incoming_msg[1]]] * int(incoming_msg[0])
else:
list1.append(name[incoming_msg[0]])

Django using icontains filter with multiple values from dictionary

Hi i'm trying to run a model search query through a dictionary data which i got like so:
{
"city":5,
"direction":"ne",
..other data that can be dynamic...
"address__icontains" = ["word1", "word2", "word3"],
}
My search query:
Models.objects.filter(**query_dict)
since the other data are dynamic that why i use filter with dictionary.And i'm using __icontains to search up field address(string value) that contains those 3 words in that string, so the problem right now is since __icontains doesn't accept array like so in the query set:
Models.objects.filter(other keys and values from dictionary, address__icontains= ["word1", "word2", "word3"])
How would i make this work with the dictionary filter search ?
my data in dict has 3 types string, int and list(1 for range search the other for icontains search) i would like to combine dictionary search with icontains AND search
I also tried changing the dictionary to
"address__icontains" = "word1 word2 word3"
but it also doesn't work
Example data:
what im doing is find a Property that has an address field that has dynamic data like city, street, ward and district
For example:
Đường ĐT 9(street), Xã Mỹ Hạnh Nam(ward), Đức Hòa(district), Long
An(city)
and it also has other data for example like direction="ne" and specials one that search between range so has key like "size__range": [0,1000] in the dict
for example if "address__icontains" = ["Long An", "Đức Hòa", "Xã Mỹ Hạnh Nam"] then it should return the above Property item with that address, direction="ne" and size has value between 0 and 1000
Thank for reading
This should do the trick:
from operator import or_
from django.db.models import Q
from functools import reduce
instance = Model.objects.all()
def queryset_filter(instance, kwargs):
for key, value in kwargs.items():
if isinstance(value, list):
instance.filter(reduce(or_, (Q(key=x) for x in value))
else:
instance.filter(key=value)
return instance
You do a bit of extra iterating this way, but if your code requires more complex filtering (like using querysets from forms), then you will need to iterate in this manner anyways.

Web2py comparing part of a request.vars element

I have a form with a table with rows containing SELECTs with _names with IDs attached, like this:
TD_list.append(TD(SELECT(lesson_reg_list, _name='lesson_reg_' + str(student[4]))))
When the form is submitted I want to extract both the student[4] value and the value held by request.vars.lesson_reg_student[4].
I've tried something like:
for item in request.vars:
if item[0:9] == "lesson_reg":
enrolment_id = int(item[10:])
code = request.vars.item
I also tried treating request.vars like a dictionary by using:
for key, value in request.vars:
if key[0:9] == "lesson_reg":
enrolment_id = int(key[10:])
code = value
but then I got 'too many values to unpack'. How do I retrieve the value of a request.vars item when the last part of its name could be any number, plus a substring of the item name itself?
Thanks in advance for helping me.
In Python, when slicing, the ending index is excluded, so your two slices should be 0:10 and 0:11. To simplify, you can also use .startswith for the first one:
for item in request.vars:
if item.startswith('lesson_reg'):
enrolment_id = int(item[11:])
code = request.vars.item

Python/SQL - How the cursor functions

In my code I have a function that needs to return either a string or None depending on what is present in the database. However at the moment the result is a list with the string answer inside, or None. Is there any change that could be made that would result in just a string or None being returned, rather than having to index the list?
Here is the code:
def retrieve_player_name(username):
param = [(username)]
command = ("""
SELECT username FROM players
WHERE username = ?
""")
result = cur.execute(command, param).fetchone()
if result is not None:
return result[0]
Thanks in advance.
A database cursors fetches entire rows, not values.
Even a row with a single value inside is still a row.
If you don't want to write row[0] multiple times, create a helper function execute_and_return_a_single_value_from_query().

Combining two lists and sorting through reference to dictionary Python

I have (what seems to me is) a pretty convoluted problem. I'm going to try to be as succinct as possible - though in order to understand the issue fully, you might have to click on my profile and look at the (only other) two questions I've posted on StackOverflow. In short: I have two lists -- one is comprised of email strings that contain a facility name, and a date of incident. The other is comprised of the facility ids for each email (I use one of the following regex functions to get this list). I've used Regex to be able to search each string for these pieces of information. The 3 Regex functions are:
def find_facility_name(incident):
pattern = re.compile(r'Subject:.*?for\s(.+?)\n')
findPat1 = re.search(pattern, incident)
facility_name = findPat1.group(1)
return facility_name
def find_date_of_incident(incident):
pattern = re.compile(r'Date of Incident:\s(.+?)\n')
findPat2 = re.search(pattern, incident)
incident_date = findPat2.group(1)
return incident_date
def find_facility_id(incident):
pattern = re.compile('(\d{3})\n')
findPat3 = re.search(pattern, incident)
f_id = findPat3.group(1)
return f_id
I also have a dictionary that is formatted like this:
d = {'001' : 'Facility #1', '002' : 'Another Facility'...etc.}
I'm trying to COMBINE the two lists and sort by the Key values in the dictionary, followed by the Date of Incident. Since the key values are attached to the facility name, this should automatically caused emails from the same facilities to be grouped together. In order to do that, I've tried to use these two functions:
def get_facility_ids(incident_list):
'''(lst) -> lst
Return a new list from incident_list that inserts the facility IDs from the
get_facilities dictionary into each incident.
'''
f_id = []
for incident in incident_list:
find_facility_name(incident)
for k in d:
if find_facility_name(incident) == d[k]:
f_id.append(k)
return f_id
id_list = get_facility_ids(incident_list)
def combine_lists(L1, L2):
combo_list = []
for i in range(len(L1)):
combo_list.append(L1[i] + L2[i])
return combo_list
combination = combine_lists(id_list, incident_list)
def get_sort_key(incident):
'''(str) -> tup
Return a tuple from incident containing the facility id as the first
value and the date of the incident as the second value.
'''
return (find_facility_id(incident), find_date_of_incident(incident))
final_list = sorted(combination, key=get_sort_key)
Here is an example of what my input might be and the desired output:
d = {'001' : 'Facility #1', '002' : 'Another Facility'...etc.}
input: first_list = ['email_1', 'email_2', etc.]
first output: next_list = ['facility_id_for_1+email_1', 'facility_id_for_2 + email_2', etc.]
DESIRED OUTPUT: FINAL_LIST = sorted(next_list, key=facility_id, date of incident)
The only problem is, the key values are not matching properly with what's found in each individual email string. Some DO, others are completely random. I have no idea why this is happening, but I have a feeling it has something to do with the way I'm combining the two lists. Can anyone help this lowly n00b? Thanks!!!
First off, I would suggest reversing your ID-to-name dictionary. Looking up a value by key is very fast but finding a key by value is very slow.
rd = { name: id_num for id_num, name in d.items() }
Then your first function can be replaced by a list comprehension:
id_list = [rd[find_facility_name(incident)] for incident in incident_list]
This might also expose why you're getting messed up values in your results. If an incident has a facility name that's not in your dictionary, this code will raise a KeyError (whereas your old function would just skip it).
Your combine function is very similar to Python's built in zip function. I'd replace it with:
combination = [id+incident for id, incident in zip(id_list, incident_list)]
However, since you're building the first list from the second one, it might make sense to build the combined version directly, rather than making separate lists and then combining them in a separate step. Here's an update to the list comprehension above that goes right to the combination result:
combination = [rd[find_facility_name(incident)] + incident
for incident in incident_list]
To do the sort, you can use the ID string that we just prepended to the email message, rather than parsing to find the ID again:
combination.sort(key=lambda x: (x[0:3], get_date_of_incident(x)))
The 3 in the slice is based off of your example of "001" and "002" as the id values. If the actual ids are longer or shorter you'll need to adjust that.
So, here is what I think is going on. Please correct me if possible.
The 'incident_list' is a list of email strings. You go in and find the facility names in each email because you have an external dictionary that has the (key:value)=(facility id: facility name). From the dictionary, you can extract the facility id in this 'id_list'.
You combine the lists so that you get a list of strings [facility id + email,...]
Then you want it to sort by a tuple( facility id, date of incidence ).
It looks like you are searching for the facility id and the facility name twice. You can skip a step if they are the same. Then, the best way is to do it all at once with tuples:
incident_list = ['email1', 'email2',...]
unsorted_list = []
for email in incident list:
id = find_facility_id(email)
date = find_date_of_incident(email)
mytuple = ( id, date, id + email )
unsorted_list.append(mytuple)
final_list = sorted(unsorted_list, key=lambda mytup:(mytup[0], mytup[1]))
Then you get an easy list of tuples sorted by first element (id as a string), and then second element (date as a string). If you just need a list of strings ( id + email ), then you need a list with the last element of each tuple part
FINALLIST = [ tup[-1] for tup in final_list ]

Categories

Resources