Querying DB for users when not all given parameters are filled - python

Sorry about the title being confusing it was hard to figure out how to word the question.
Currently I have a sqllite db with some users in it they have a first name, last name, dob, high school, and high school class. The db is connected to flask using sqlalchemy. What I'm wondering is for my search function I have 4 inputs and I want to have it so if an input isn't used then it won't be used in the search query. Say the person searches for the last name and high school I want it to search just using those parameters. I've tried doing this using a bunch of if statements but it seems messy there must be a better way. Below is the query that I use but it only works if all 4 are filled. Is there a better way than a bunch of if statements with different queries? I've looked around and haven't found anything.
userq=User.query.filter_by(first_name=fname_strip,last_name=lname_strip,hs_class=hs_class_strip).all()

You can try if/else statements like the following:
q = User.query.filter_by(first_name=first_name)
if lname_strip:
q = q.filter_by(last_name=lname_strip)
if hs_class_strip:
q= q.filter_by(hs_class=hs_class_strip)
# Execute the query
q.all()
Updated needs the q to be an assignment.

Okay so what I did was go through and make an if statement like you said but made them into different vars. Then check to see if they where none or not correct and if they were good then they queryied correctly if not then the queried for everything not null. Then changed them to be a set then did set intersection to see what was the same through all of them. Thank you for ionheart for helping me through this and providing the information this is the complete answer using his partial solution.
userf=set()
userl=set()
userc=set()
userh=set()
if fname_strip!='':
userf = User.query.filter_by(first_name=fname_strip).all()
print(userf)
else:
userf = User.query.filter(User.first_name.isnot(None))
if lname_strip!='':
userl = User.query.filter_by(last_name=lname_strip).all()
print(userl)
else:
userl = User.query.filter(User.last_name.isnot(None))
try:
int(hs_class_strip)
userc = User.query.filter_by(hs_class=hs_class_strip).all()
print(userc)
except:
userc = User.query.filter(User.hs_class.isnot(None))
if hs_strip!='':
userh = User.query.filter_by(hs=hs_strip).all()
print(userh)
else:
userh = User.query.filter(User.hs.isnot(None))
userq=[]
common=set(userf) & set(userl) & set(userc) & set(userh)
print(common)

If you pass the arguments to your search function as keyword arguments you can change the signature to accept kwargs and pass those on to the filter query
def search(**kwargs):
userq = User.query.filter_by(**kwargs).all()
This way any arguments you don't specify when calling search will not be passed onto the query, for example calling search(first_name='bob', last_name='fossil') will only add first name and surname arguments to the query

Related

Django `assertNumQueries` showing duplicate queries on deferred field

I am having a strange behaviour that I cannot find out why it's happening.
I have a simple queryset with a deferred field, for example Person.objects.filter(id=4).defer('phone') and then I have a test that asserts this:
with self.assertNumQueries(2):
p = Person.objects.filter(id=4).defer('phone').first() # 1 query
p.phone # 1 query
It fails, because it seems to run three queries on that block: the first one when filtering, and two more duplicate queries that come from the p.phone statement (SELECT phone FROM ...).
Does anyone have any idea why this is happening?
Note: i'm using Django 2.0. And it also happens using only(), the counterpart of defer().
I can't reproduce, it's something related to your case. I wrote this test case with default Django user that passes. Provide more info if you need a better answer.
class TestDefer(APITestCase):
def test_defer(self):
u = User.objects.create(email='aaa#bbb.com', is_staff=True)
with self.assertNumQueries(1):
p = User.objects.defer('is_staff').get(id=u.id)
with self.assertNumQueries(1):
print(p.is_staff)
with self.assertNumQueries(1):
p = User.objects.defer('email').get(id=u.id)
with self.assertNumQueries(1):
print(p.email)

injecting code inside of code python django and q objects

This question gets me close to what I want to do but I am still in need of further understanding. Django. Q objects dynamicaly generate
I have a view in django that looks to see if any query params have been sent to the url. I am expecting some query objects to have multipule values.
ie. domain.com/?neighborhood=Logan Square&neighborhood=River North
I grab queryparams and put them in a list. I am now trying to iterate through that list and filter through the query params using or logic.
https://docs.djangoproject.com/en/1.11/topics/db/queries/#complex-lookups-with-q
for this I know I need to use Q objects.
the proper code for this is:
Q(neighborhood='Logan Square') | Q(neighborhood='River North')
so what I need to do is
1 adding a query Q object dynamically and then also adding the | operator dynamically for all objects in the for loop.
You don't need this at all. You can simply use __in:
MyModel.objects.filter(neighborhood__in=request.GET.getlist('neighborhood'))
If I understood your question correctly.
"You may, or may NOT get the query params."?
query = ModelName.objects.none() # setting a Q() instance (maybe skippable)
for a_item in neighbourhood_list:
query |= (Q(neighborhood = a_item))
query = ModelName.objects.filter(query)
You might have to test it, and edit this a little bit, but will do the trick you want.

Building Django Q() objects from other Q() objects, but with relation crossing context

I commonly find myself writing the same criteria in my Django application(s) more than once. I'll usually encapsulate it in a function that returns a Django Q() object, so that I can maintain the criteria in just one place.
I will do something like this in my code:
def CurrentAgentAgreementCriteria(useraccountid):
'''Returns Q that finds agent agreements that gives the useraccountid account current delegated permissions.'''
AgentAccountMatch = Q(agent__account__id=useraccountid)
StartBeforeNow = Q(start__lte=timezone.now())
EndAfterNow = Q(end__gte=timezone.now())
NoEnd = Q(end=None)
# Now put the criteria together
AgentAgreementCriteria = AgentAccountMatch & StartBeforeNow & (NoEnd | EndAfterNow)
return AgentAgreementCriteria
This makes it so that I don't have to think through the DB model more than once, and I can combine the return values from these functions to build more complex criterion. That works well so far, and has saved me time already when the DB model changes.
Something I have realized as I start to combine the criterion from these functions that is that a Q() object is inherently tied to the type of object .filter() is being called on. That is what I would expect.
I occasionally find myself wanting to use a Q() object from one of my functions to construct another Q object that is designed to filter a different, but related, model's instances.
Let's use a simple/contrived example to show what I mean. (It's simple enough that normally this would not be worth the overhead, but remember that I'm using a simple example here to illustrate what is more complicated in my app.)
Say I have a function that returns a Q() object that finds all Django users, whose username starts with an 'a':
def UsernameStartsWithAaccount():
return Q(username__startswith='a')
Say that I have a related model that is a user profile with settings including whether they want emails from us:
class UserProfile(models.Model):
account = models.OneToOneField(User, unique=True, related_name='azendalesappprofile')
emailMe = models.BooleanField(default=False)
Say I want to find all UserProfiles which have a username starting with 'a' AND want use to send them some email newsletter. I can easily write a Q() object for the latter:
wantsEmails = Q(emailMe=True)
but find myself wanting to something to do something like this for the former:
startsWithA = Q(account=UsernameStartsWithAaccount())
# And then
UserProfile.objects.filter(startsWithA & wantsEmails)
Unfortunately, that doesn't work (it generates invalid PSQL syntax when I tried it).
To put it another way, I'm looking for a syntax along the lines of Q(account=Q(id=9)) that would return the same results as Q(account__id=9).
So, a few questions arise from this:
Is there a syntax with Django Q() objects that allows you to add "context" to them to allow them to cross relational boundaries from the model you are running .filter() on?
If not, is this logically possible? (Since I can write Q(account__id=9) when I want to do something like Q(account=Q(id=9)) it seems like it would).
Maybe someone suggests something better, but I ended up passing the context manually to such functions. I don't think there is an easy solution, as you might need to call a whole chain of related tables to get to your field, like table1__table2__table3__profile__user__username, how would you guess that? User table could be linked to table2 too, but you don't need it in this case, so I think you can't avoid setting the path manually.
Also you can pass a dictionary to Q() and a list or a dictionary to filter() functions which is much easier to work with than using keyword parameters and applying &.
def UsernameStartsWithAaccount(context=''):
field = 'username__startswith'
if context:
field = context + '__' + field
return Q(**{field: 'a'})
Then if you simply need to AND your conditions you can combine them into a list and pass to filter:
UserProfile.objects.filter(*[startsWithA, wantsEmails])

check if query exists using peewee

I am using the Peewee library in Python and I want to check if a query exists. I do not want to create a record if it doesn't exist, so I don't want to use get_or_create. There must be a better solution than to use try/except with get but I don't see anything. Please let me know if there is a better way. Thanks.
You can use .exists():
query = User.select().where(User.username == 'charlie')
if query.exists():
# A user named "charlie" exists.
cool()
http://docs.peewee-orm.com/en/latest/peewee/api.html?highlight=exists#SelectBase.exists
If you just need to check existence use the accepted answer.
If you are going to use the record if it exists you can make use of Model.get_or_none() as this removes the need to use a try/catch and will not create a record if the record doesn't exist.
class User(peewee.Model):
username = peewee.CharField(unique=True)
user = User.get_or_none(username='charlie')
if user is not None:
# found user, do something with it
pass
Alternatively, if you want to check if e.g. some other table refers this record, you can use WHERE EXISTS (subquery) clause. It is not supported natively by PeeWee, but it can be easily constructed:
subquery = Child.select(Param('1')).where(Child.parent == Parent.id)
parents_with_children = Parent.select().where(
Clause(SQL('EXISTS'), subquery))
It is equivalent to the following SQL:
SELECT * FROM parent
WHERE EXISTS (SELECT 1 FROM child
WHERE child.parent_id = parent.id);
Here I used SELECT 1 for subquery to avoid fetching unneeded information (like child.id). Not sure if such optimization is actually required.
UPD (Feb 2022)
After more than 5 years of peewee evolution, it looks like the Clause class is gone.
The following code may work (I didn't have a chance to test it though):
subquery = Child.select(Param('1')).where(Child.parent == Parent.id)
parents_with_children = Parent.select().where(
NodeList((SQL('EXISTS'), subquery)))

How to check the existance of single Entity? Google App Engine, Python

Sorry for noobster question again.
But I'm trying to do some very easy stuff here, and I don't know how. Documentation gives me hints which do not work, or apply.
I recieve a POST request and grab a variable out of it. It says "name".
I have to search all over my entities Object (for example) and find out if there's one that has the same name. Is there's none, I must create a new Entity with this name. Easy it may look, but I keep Failing.
Would really appreciate any help.
My code currently is this one:
objects_qry = Object.query(Object.name == data["name"])
if (not objects_qry ):
obj = Object()
obj .name = data["name"]
obj .put()
class Object(ndb.Model):
name = ndb.StringProperty()
Using a query to perform this operation is really inefficient.
In addition your code is possibly unreliable, if name doesn't exist and you have two requests at the same time for name you could end up with two records. And you can't tell because your query only returns the first entity with the name property equal to some value.
Because you expect only one entity for name a query is expensive and inefficient.
So you have two choices you can use get_or_insert or just do a get, and if you have now value create a new entity.
Any way here is a couple of code samples using the name as part of the key.
name = data['name']
entity = Object.get_or_insert(name)
or
entity = Object.get_by_id(name)
if not entity:
entity = Object(id=name)
entity.put()
Calling .query just creates a query object, it doesn't execute it, so trying to evaluate is as a boolean is wrong. Query object have methods, fetch and get that, respectively, return a list of matching entities, or just one entity.
So your code could be re-written:
objects_qry = Object.query(Object.name == data["name"])
existing_object = objects_qry.get()
if not existing_object:
obj = Object()
obj.name = data["name"]
obj.put()
That said, Tim's point in the comments about using the ID instead of a property makes sense if you really care about names being unique - the code above wouldn't stop two simultaneous requests from creating entities with the same name.

Categories