Chaining Filters together - python

Given the following:
instances = Catalog.objects.filter(
Q(imdb_url=imdb_url)
|Q(isan=isan)
|Q(amg_video_id=amg_video_id)
)
How would I do the same in the following format, chaining each together:
instances = Catalog.objects.all()
if imdb_url:
instances = instances.filter(imdb_url = imdb_url) # OR
if isan:
instances = instances.filter(isan = isan) # OR
if amg:
instances = instances.filter(amg = amg) # OR
The above gives me the equivalent of:
instances = Catalog.objects.filter(imdb_url=imdb_url).filter(isan=isan).filter(amg=amg)
How would I do the eqivalent of the Q in the first query?

You can create an empty Q object and OR with others accordingly using |=:
q = Q()
if imdb_url:
q |= Q(imdb_url=imdb_url)
if isan:
q |= Q(isan=isan)
if amg:
q |= Q(amg=amg)
instances = Catalog.objects.filter(q)

The union operator for querysets is |
instances = Catalog.objects.none()
if imdb_url:
instances |= instances.filter(imdb_url=imdb_url)
if isan:
instances |= instances.filter(isan=isan)
if amg:
instances |= instances.filter(amg=amg)

Related

python peewee dynamically or + and clauses

I'd like to do a and clause with two lists of multiple or clauses from the same table.
The problem with the following code is, that the query result is empty. If I just select 'indices' or 'brokers', the result is fine.
...
query = query.join(StockGroupTicker, on=(Ticker.id == StockGroupTicker.ticker))
# indices
if "indices" in filter:
where_indices = []
for f in filter["indices"]:
where_indices.append(StockGroupTicker.stock_index == int(f))
if len(where_indices):
query = query.where(peewee.reduce(peewee.operator.or_, where_indices))
# broker
if "brokers" in filter:
where_broker = []
for f in filter["brokers"]:
where_broker.append(StockGroupTicker.stock_index == int(f))
if len(where_broker):
query = query.where(peewee.reduce(peewee.operator.or_, where_broker))
return query.distinct()
SQL Querie (update)
# index and brocker
SELECT
DISTINCT `t1`.`id`,
`t1`.`symbol`,
`t1`.`type`,
`t1`.`name`,
`t1`.`sector`,
`t1`.`region`,
`t1`.`primary_exchange`,
`t1`.`currency`,
`t1`.`score`,
`t1`.`last_price`,
`t1`.`last_price_date`,
`t1`.`last_price_check`,
`t1`.`last_stock_split`,
`t1`.`next_earning`,
`t1`.`last_earnings_update`,
`t1`.`disused`,
`t1`.`source`,
`t1`.`source_intraday`,
`t1`.`created`,
`t1`.`modified`,
`t2`.`invest_score` AS `invest_score`
FROM
`ticker` AS `t1`
INNER JOIN `tickerstats` AS `t2` ON
(`t1`.`id` = `t2`.`ticker_id`)
INNER JOIN `stockgroupticker` AS `t3` ON
(`t1`.`id` = `t3`.`ticker_id`)
WHERE
(((((`t1`.`disused` IS NULL)
OR (`t1`.`disused` = 0))
AND (`t2`.`volume_mean_5` > 10000.0))
AND (`t3`.`stock_index_id` = 1))
AND (`t3`.`stock_index_id` = 10)
)
Thanks to #coleifer, the peewee solution is quite simple. I had to use an alias.
if "indices" in filter and filter["indices"]:
query = query.join(
StockGroupTicker, peewee.JOIN.INNER, on=(Ticker.id == StockGroupTicker.ticker)
)
where_indices = []
for f in filter["indices"]:
where_indices.append(StockGroupTicker.stock_index == int(f))
if len(where_indices):
query = query.where(peewee.reduce(peewee.operator.or_, where_indices))
if "brokers" in filter and filter["brokers"]:
BrokerGroupTicker = StockGroupTicker.alias()
query = query.join(
BrokerGroupTicker, peewee.JOIN.INNER, on=(Ticker.id == BrokerGroupTicker.ticker)
)
where_broker = []
for f in filter["brokers"]:
where_broker.append(BrokerGroupTicker.stock_index == int(f))
if len(where_broker):
query = query.where(peewee.reduce(peewee.operator.or_, where_broker))
return query.distinct()

Query multiple joins sqlalchemy

I am generating a query with sql alchemy part by part. I have this object that is working very well for a query with only one join:
**I have an ORM model, but I cannot use primary keys setted because are not real.
q = select( self.selectObj._select
).select_from(
self.joinObj._join
).where(
and_(*self.whereObj._where)
).group_by(
*self.selectObj._groupby
).order_by(
self.selectObj._orderby
).limit(
self.selectObj._limit
).having(
self.selectObj._having
)
I have this method for generate the joins:
def get_joins(self, first, leftTable, rightTable, leftTableColumn, rightTableColumn, outer):
if first:
self._join = join(leftTable, rightTable, leftTableColumn == rightTableColumn, full=outer)
first = False
else:
self._join = self._join + join(leftTable, rightTable, leftTableColumn == rightTableColumn, full=outer)
I don´t know, how can I generate, concatenate, get, etc two or more joins for use it in the select_from clause. Any idea?
Thanks a lot in advance :)
The final result should be like this in the from:
SELECT a.dev, b.asha, c.unk
FROM a
FULL OUTER JOIN b ON a.dev = b.devicb
FULL OUTER JOIN c ON a.dev = c.devicc
WHERE
a.cust = 'SNTC' AND
b.cust = 'SNTC' AND
c.cust = 'SNTC' AND
a.invent = '10' AND
b.invent = '10' AND
c.invent = '10'
I solved in this way, just invoquing .join in the previous join but only using right table. self._join.join(rightTable,...)
Complete solution for the method:
def get_joins(self, first, leftTable, rightTable, leftTableColumn, rightTableColumn, outer):
if first:
self._join = join(leftTable, rightTable, leftTableColumn == rightTableColumn, full=outer)
first = False
else:
self._join = self._join.join(rightTable, leftTableColumn == rightTableColumn, full=outer)

Sqlalchemy: How to perform outer join with itself?

I want to perform this SQL query using Sqlalchemy (with model Evaluation):
select e1.user, sum(e1.points) as s from
(select e1.*
from evaluations e1 left outer join evaluations e2
on (e1.user = e2.user and e1.module = e2.module and e1.time < e2.time)
where e2.user is null and e1.module in (__another subquery__))
group by e1.user order by s limit 5
I don't know how to perform left outer join (especialy the renaming and referencing of renamed comlumns). Could you help me?
# sample sub-query for testing
_another_query = session.query(Evaluation.module).filter(Evaluation.module > 3)
# define aliases
E1 = aliased(Evaluation, name="e1")
E2 = aliased(Evaluation, name="e2")
# inner query
sq = (
session
# .query(E1)
# select columns explicitely to control labels
.query(E1.user.label("user"), E1.points.label("points"))
.outerjoin(E2, and_(
E1.user == E2.user,
E1.module == E2.module,
E1.time < E2.time,
))
.filter(E2.user == None)
.filter(E1.module.in_(_another_query))
)
sq = sq.subquery(name="sq")
# now lets group by
q = (
session
.query(sq.c.user, func.sum(sq.c.points))
.group_by(sq.c.user)
.order_by(func.sum(sq.c.points))
.limit(5)
)

ponyORM: trouble with query

I have query with dynamic conditions,i.e.
select (lambda obj:obj.A = 'a' and obj.B = 'b' and ...)
So i write code for this:
def search(self,**kwargs):
q = unicode('lambda obj:', 'utf-8')
for field,value in kwargs.iteritems():
value = unicode(value, 'utf-8')
field = unicode(field, 'utf-8')
q+=u" obj.%s == '%s' and" % (field,value
q = q[0:q.rfind('and')]
res = select(q.encode('utf-8'))[:]
But i have this error during execution of function:
tasks.search(title='Задача 1',url='test.com')
res = select(q.encode('utf-8'))[:]
File "<string>", line 2, in select
File ".../local/lib/python2.7/site-packages/pony/utils.py", line 96, in cut_traceback
return func(*args, **kwargs)
File ".../local/lib/python2.7/site-packages/pony/orm/core.py", line 3844, in select
if not isinstance(tree, ast.GenExpr): throw(TypeError)
File "...local/lib/python2.7/site-packages/pony/utils.py", line 123, in throw
raise exc
TypeError
While it is possible to use strings in order to apply conditions to a query, it can be unsafe, because of the risk of SQL injection. The better way for applying conditions to a query is using the filter() method. You can take the latest version of Pony ORM from https://github.com/ponyorm/pony repository and try a couple of examples provided below.
First we define entities and create a couple of objects:
from decimal import Decimal
from pony.orm import *
db = Database('sqlite', ':memory:')
class Product(db.Entity):
name = Required(unicode)
description = Required(unicode)
price = Required(Decimal)
quantity = Required(int, default=0)
db.generate_mapping(create_tables=True)
with db_session:
Product(name='iPad', description='Air, 16GB', price=Decimal('478.99'), quantity=10)
Product(name='iPad', description='Mini, 16GB', price=Decimal('284.95'), quantity=15)
Product(name='iPad', description='16GB', price=Decimal('299.00'), quantity=10)
Now we'll apply filters passing them as keyword arguments:
def find_by_kwargs(**kwargs):
q = select(p for p in Product)
q = q.filter(**kwargs)
return list(q)
with db_session:
products = find_by_kwargs(name='iPad', quantity=10)
for p in products:
print p.name, p.description, p.price, p.quantity
Another option is to use lambdas in order to specify the conditions:
def find_by_params(name=None, min_price=None, max_price=None):
q = select(p for p in Product)
if name is not None:
q = q.filter(lambda p: p.name.startswith(name))
if min_price is not None:
q = q.filter(lambda p: p.price >= min_price)
if max_price is not None:
q = q.filter(lambda p: p.price <= max_price)
return list(q)
with db_session:
products = find_by_params(name='iPad', max_price=400)
for p in products:
print p.name, p.description, p.price, p.quantity
As you can see filters can be applied dynamically. You can find more information about using filters following by this link: http://doc.ponyorm.com/queries.html#Query.filter
If you still want to filter using strings, you have to apply new filter for each key/value pair.
Something like this:
def search(self,**kwargs):
q = select(m for m in Product)
for field,value in kwargs.iteritems():
value = unicode(value, 'utf-8')
field = unicode(field, 'utf-8')
flt = u"m.{0} == {1}".format(value, field)
q = q.filter(flt)
# return q # return Query which can be further modified (for ex. paging, ordering, etc.)
return q[:] # or return found products
HTH, Tom

Filter django data using Q

category = request.GET.get('cat')
from_p = request.GET.get('from')
to_p = request.GET.get('to')
q = Q()
if category:
q |= Q(category=category)
if from_p:
q |= Q(price__gt=from_p)
if to_p:
q |= Q(price__lt=to_p)
s = Sample.objects.filter(q)
www.example.com/?cat=0&from=300&to=600
If first is category - from_p and to_p criterion not working. How to fix it?
It work only for one criterion. I need if user set (for example) category and from_p search by these criterion.
EDITED
Here it is:
q_cat = Q(category=category) if category else Q()
q_from = Q(price__gt=from_p) if from_p else Q()
q_to = Q(price__lt=to_p) if to_p else Q()
q = q_cat | ( q_from & q_to )
s = Sample.objects.filter( q )

Categories

Resources