django,split the query parameter and pass the value in IN cluase - python

i have written a native sql query in django, now i need to pass filter condition in where clause.
i am passing the URL as list of values like (a,b,c,d) and in database i need to compare and these with a column and filter the data.
Example URL:
(//10.100.212.16:8000/test/&param1=a,b,c,d)
example sql:
select * from test where test like(%a%) or like(%b%) or like(%c%) or like(%d%)
how can write this in django using native sql.
i am using postgres as db
thanks

Given the URL as presented, but assuming you're using the correct ? character rather than & to mark the beginning of the querystring:
import operator
from django.db.models import Q
param1_raw_string = request.GET.get('param1')
if param1_raw_string:
param1_values = param1_raw_string.split(',')
tests = Test.objects.filter(reduce(operator.or_, (Q(test__contains=param1) for param1 in param1_values)))
else:
# do something reasonable when param1 is missing
If you want case-insensitive comparison, use __icontains instead. Composing multiple Q objects using operator.or_ is the main point.
If you use ?param1=a&param1=b... you can skip the split and just write param1_values = request.GET.getlist('param1').

Related

FastAPI in-memory filtering

I'm following the tutorial here: https://github.com/Jastor11/phresh-tutorial/tree/tutorial-part-11-marketplace-functionality-in-fastapi/backend/app and I had a question: I want to filter a model by different parameters so how would I do that?
The current situation is that I have a list of doctors and so I get all of them. Then depending on the filter query parameters, I filter doctors. I can't just do it all in one go because these query parameters are optional.
so I was thinking something like (psuedocode):
all_doctors = await self.db.fetch_all(query=GET_ALL_DOCTORS)
if language_id:
all_doctors = all_doctors.filter(d => doctor.language_id = language_id)
if area:
all_doctors = all_doctors.xyzabc
I'm trying out FastAPI according to that tutorial and couldn't figure out how to do this.
I have defined a model file for different models and am using SQLAlchemy.
One way I thought of is just getting the ids of all the doctors then at each filtering step, passing in the doctor ids from the last step and funneling them through different sql queries but this is filtering using the database and would result in one more query per filter parameter. I want to know how to use the ORM to filter in memory.
EDIT: So basically, in the tutorial I was following, no SQLAlchemy models were defined. The tutorial was using SQL statements. Anyways, to answer my own question: I would first need to define SQLAlchemy models before I can use them.
The SQLAlchemy query object (and its operations) returns itself, so you can keep building out the query conditionally inside if-statements:
query = db_session.query(Doctor)
if language_id:
query = query.filter(Doctor.language_id == language_id)
if area_id:
query = query.filter(Doctor.area_id == area_id)
return query.all()
The query doesn't run before you call all at the end. If neither argument is given, you'll get all the doctors.

How to AND chain filters in a django queryset?

This question makes clear how chaining and multiple argument filters are different but it doesn't specify how to make them chained filters equivalent.
For example, given the code:
query = mymodel.filter(name="Foo",foreignkey_property1="Bar",foreignkey_property2="Zap")
Is it possible to get an and version of this from a chained queryset and have the query above and the query below be equivalent:
query = mymodel.filter(name="Foo",foreignkey_property1="Bar")
query = query.filter(foreignkey_property2="Zap",???)
I'm certain I've read how this is possible, but can't find it.
Try this:
from django.db.models import Q
query = mymodel.filter(Q(name="Foo",foreignkey_property1="Bar") && Q(foreignkey_property2="Zap"))

How to get peewee result length

I use peewee orm in python.
I have a query that :
userOrganizations = (UserOrganization
.select(UserOrganization,Organization)
.join(Organization)
.where(UserOrganization.user==user.user_id)
.aggregate_rows()
)
I want to get length of userOrganizations variable. Is there any method like userOrganizations.length() ?
According to the peewee documentation you can use the count() function, i.e.:
userOrganizations.count()
If you're worried about maybe running extra DB queries, you can convert your result to a list and get the length, like:
len(list(userOrganizations))
Source for second technique: this question.

Django OR query using Extra and Filter

I am trying to use Django's ORM to generate a query using both extra and filter methods. Something like this:
Model.objects.filter(clauseA).extra(clauseB).all()
This generates a query, but the issue is that everything in the filter clause is AND'd with everything in the extra clause, so the sql looks like:
SELECT * FROM model WHERE clauseA AND clauseB.
My question is, is there a way to change the default combination operator for a query in Django such that the query generated will be:
SELECT * FROM model WHERE clauseA OR clauseB.
Try Q object
Model.objects.filter(Q(clauseA) | ~Q(clauseB))
EDIT
try this
Model.objects.filter(clauseA) | Model.objects.extra(clauseB)
It might be easier if you just get rid of the filter clause, and include that filter directly into extra OR'd with your Postgres specific function. I think it is already a limitation of the Django ORM.
You can attempt to create your own Func expression though. Once you have created one for your Postgres specific function, you might be able to use a combination of Func(), F(), and Q() objects to get rid of that nasty .extra() function and chain them nicely.

Filtering with joined tables

I'm trying to get some query performance improved, but the generated query does not look the way I expect it to.
The results are retrieved using:
query = session.query(SomeModel).
options(joinedload_all('foo.bar')).
options(joinedload_all('foo.baz')).
options(joinedload('quux.other'))
What I want to do is filter on the table joined via 'first', but this way doesn't work:
query = query.filter(FooModel.address == '1.2.3.4')
It results in a clause like this attached to the query:
WHERE foos.address = '1.2.3.4'
Which doesn't do the filtering in a proper way, since the generated joins attach tables foos_1 and foos_2. If I try that query manually but change the filtering clause to:
WHERE foos_1.address = '1.2.3.4' AND foos_2.address = '1.2.3.4'
It works fine. The question is of course - how can I achieve this with sqlalchemy itself?
If you want to filter on joins, you use join():
session.query(SomeModel).join(SomeModel.foos).filter(Foo.something=='bar')
joinedload() and joinedload_all() are used only as a means to load related collections in one pass, not used for filtering/ordering!. Please read:
http://docs.sqlalchemy.org/en/latest/orm/tutorial.html#joined-load - the note on "joinedload() is not a replacement for join()", as well as :
http://docs.sqlalchemy.org/en/latest/orm/loading.html#the-zen-of-eager-loading

Categories

Resources