query
Module¶
Rom - the Redis object mapper for Python
Copyright 2013-2016 Josiah Carlson
Released under the LGPL license version 2.1 and version 3 (you can choose which you’d like to be bound under).
- class rom.query.Query(model, filters=(), order_by=None, limit=None, select=None)¶
Bases:
object
This is a query object. It behaves a lot like other query objects. Every operation performed on Query objects returns a new Query object. The old Query object does not have any updated filters.
- all()¶
Alias for
execute()
.
- cached_result(timeout)¶
This will execute the query, returning the key where a ZSET of your results will be stored for pagination, further operations, etc.
The timeout must be a positive integer number of seconds for which to set the expiration time on the key (this is to ensure that any cached query results are eventually deleted, unless you make the explicit step to use the PERSIST command).
Note
Limit clauses are ignored and not passed.
Usage:
ukey = User.query.endswith(email='@gmail.com').cached_result(30) for i in xrange(0, conn.zcard(ukey), 100): # refresh the expiration conn.expire(ukey, 30) users = User.get(conn.zrange(ukey, i, i+99)) ...
- count()¶
Will return the total count of the objects that match the specified filters.:
# counts the number of users created in the last 24 hours User.query.filter(created_at=(time.time()-86400, time.time())).count()
- delete(blocksize=100)¶
Will delete the entities that match at the time the query is executed.
Used like:
MyModel.query.filter(email=...).delete() MyModel.query.endswith(email='@host.com').delete()
Warning
can’t be used on models on either side of a
OneToMany
,ManyToOne
, orOneToOne
relationship.
- endswith(**kwargs)¶
When provided with keyword arguments of the form
col=suffix
, this will limit the entities returned to those that have a word with the provided suffix in the specified column(s). This requires that thesuffix=True
option was provided during column definition.Usage:
User.query.endswith(email='@gmail.com').execute()
- execute()¶
Actually executes the query, returning any entities that match the filters, ordered by the specified ordering (if any), limited by any earlier limit calls.
- filter(**kwargs)¶
Only columns/attributes that have been specified as having an index with the
index=True
option on the column definition can be filtered with this method. Prefix, suffix, and pattern match filters must be provided using the.startswith()
,.endswith()
, and the.like()
methods on the query object, respectively. Geo location queries should be performed using the.near()
method.Filters should be of the form:
# for numeric ranges, use None for open-ended ranges attribute=(min, max) # you can also query for equality by passing a single number attribute=value # for string searches, passing a plain string will require that # string to be in the index as a literal attribute=string # to perform an 'or' query on strings, you can pass a list of # strings attribute=[string1, string2]
As an example, the following will return entities that have both
hello
andworld
in theString
columnscol
and has aNumeric
columnncol
with value between 2 and 10 (including the endpoints):results = MyModel.query \ .filter(scol='hello') \ .filter(scol='world') \ .filter(ncol=(2, 10)) \ .all()
If you only want to match a single value as part of your range query, you can pass an integer, float, or Decimal object by itself, similar to the
Model.get_by()
method:results = MyModel.query \ .filter(ncol=5) \ .execute()
Note
Trying to use a range query attribute=(min, max) on indexed string columns won’t return any results.
Note
This method only filters columns that have been defined with
index=True
.
- first()¶
Returns only the first result from the query, if any.
- iter_result(timeout=30, pagesize=100, no_hscan=False)¶
Iterate over the results of your query instead of getting them all with .all(). Will only perform a single query. If you expect that your processing will take more than 30 seconds to process 100 items, you should pass timeout and pagesize to reflect an appropriate timeout and page size to fetch at once.
Usage:
for user in User.query.endswith(email='@gmail.com').iter_result(): # do something with user ...
- like(**kwargs)¶
When provided with keyword arguments of the form
col=pattern
, this will limit the entities returned to those that include the provided pattern. Note that ‘like’ queries require that theprefix=True
option must have been provided as part of the column definition.Patterns allow for 4 wildcard characters, whose semantics are as follows:
? - will match 0 or 1 of any character
* - will match 0 or more of any character
+ - will match 1 or more of any character
! - will match exactly 1 of any character
As an example, imagine that you have enabled the required prefix matching on your
User.email
column. And lets say that you want to find everyone with an email address that contains the name ‘frank’ before the@
sign. You can use either of the following patterns to discover those users.*frank*@
*frank*@
Note
Like queries implicitly start at the beginning of strings checked, so if you want to match a pattern that doesn’t start at the beginning of a string, you should prefix it with one of the wildcard characters (like
*
as we did with the ‘frank’ pattern).
- limit(offset, count)¶
Will limit the number of results returned from a query:
# returns the most recent 25 users User.query.order_by('-created_at').limit(0, 25).execute()
- near(name, lon, lat, distance, measure, count=None)¶
- order_by(column)¶
When provided with a column name, will sort the results of your query:
# returns all users, ordered by the created_at column in # descending order User.query.order_by('-created_at').execute()
- replace(**kwargs)¶
Copy the Query object, optionally replacing the filters, order_by, or limit information on the copy. This is mostly an internal detail that you can ignore.
- select(*column_names, **kwargs)¶
Select the provided column names from the model, do not return an entity, do not involve the rom session, just get the raw and/or processed column data from Redis.
Keyword-only arguments:
- include_pk=False - whether to include the primary key in the
returned data (we need to get this in some cases, so we fetch it anyway; if you want it, we can return it to you - just be careful with the namedtuple option - see the warning below)
- decode=True - whether to take a pass through normal data
decoding in the model (will not return an entity/model)
- ff=_dict_data_factory - the type of data to return from the
select after all filters/limits/order_by are applied
Warning
If
include_pk = True
and if you don’t provide the primary key column, it will be appended to your list of columns.Note
if you want to provide a new factory function for the returned data, it must be of the form (below is the actual dict factory function)
def _dict_data_factory(columns): _dict = dict _zip = zip def make(data): # do whatever you need to turn your tuple of columns plus # your list of data into whatever you want: return _dict(_zip(columns, data)) return make
Available factory functions:
``rom.query._dict_data_factory`` - default
``rom.query._list_data_factory`` - lowest overhead, as the
data
passed in above is a list that you can do anything to``rom.query._tuple_data_factory`` - when you want tuples instead
``rom.query._namedtuple_data_factory`` - get namedtuples, see see warning below
Warning
If you use the
_namedtuple_data_factory
, and your columns include underscore prefixes, they will be stripped. If this results in a name collision, you will get an exception. If you want different behavior, write your own 20 line factory function that does exactly what you want, and pass it; they are really easy!
- startswith(**kwargs)¶
When provided with keyword arguments of the form
col=prefix
, this will limit the entities returned to those that have a word with the provided prefix in the specified column(s). This requires that theprefix=True
option was provided during column definition.Usage:
User.query.startswith(email='user@').execute()