Skip to content

Markdown

Queries

Conditions choose which records a query, count, or delete applies to. Build them with F, which escapes values for you, or with where_from_dict for plain data from a model or a web form.

The examples below use tasks, made as shown here, and app, which is qb.app("bq1234567"). Job Tasks has Title, Status, Hours, Due Date, Code, which is unique, and Attachment. It starts with three records, and each example starts from those again. A live test runs every example with both clients and checks its output.

from pyquickbase import Quickbase

with Quickbase(
    realm="acme", token="your_user_token"
) as qb:
    tasks = qb.app("bq1234567").table("Job Tasks")
from pyquickbase import AsyncQuickbase

async with AsyncQuickbase(
    realm="acme", token="your_user_token"
) as qb:
    tasks = qb.app("bq1234567").table("Job Tasks")

Build a condition

For the full picture, see Reading records.

F

A field in a query, named by label (str) or ID (int).

(F("Status") == "Done") & (F("Due Date") < date.today()). Values are escaped for you, so this is the safe way to use text you don't control. == None matches empty fields.

On a user or multiuser field, compare with an email or user ID. On a percent field, a number is a fraction, as it is when writing, so F("Done") >= 0.5 means 50%. On a duration field, a number is milliseconds, or use a timedelta. Text is sent as written, such as F("Budget") > "8 hours".

Parameters

  • field str | int, required
    The field's label or ID.
F(field: str | int)

Example

from pyquickbase import F

where = (F("Status") == "Open") & (F("Hours") >= 10)
for task in tasks.query(where=where, select=["Title"]):
    print(task["Title"])

print(tasks.count(F("Title").contains("wall")))
print(tasks.count(F("Title").starts_with("Pour")))
print(tasks.count(F("Status").is_in(["Open", "Done"])))
print(tasks.count(F("Due Date") == None))
print(tasks.count(F("Title").op("XCT", "wall")))
from pyquickbase import F

where = (F("Status") == "Open") & (F("Hours") >= 10)
async for task in tasks.query(where=where, select=["Title"]):
    print(task["Title"])

print(await tasks.count(F("Title").contains("wall")))
print(await tasks.count(F("Title").starts_with("Pour")))
print(await tasks.count(F("Status").is_in(["Open", "Done"])))
print(await tasks.count(F("Due Date") == None))
print(await tasks.count(F("Title").op("XCT", "wall")))

Output

Frame walls
2
1
3
1
1

Match text that contains

Match records whose value contains this text.

Parameters

  • value Any, required
    The text to look for.

Returns Condition

A condition to pass as where.

contains(value: Any) -> Condition

Match text that doesn't contain

Match records whose value doesn't contain this text.

Parameters

  • value Any, required
    The text to look for.

Returns Condition

A condition to pass as where.

not_contains(value: Any) -> Condition

Match text that starts with

Match records whose value starts with this text.

Parameters

  • value Any, required
    The text to look for.

Returns Condition

A condition to pass as where.

starts_with(value: Any) -> Condition

Match text that doesn't start with

Match records whose value doesn't start with this text.

Parameters

  • value Any, required
    The text to look for.

Returns Condition

A condition to pass as where.

not_starts_with(value: Any) -> Condition

Match one of a field's values

Match records where one of the field's values is exactly this, such as one choice of a multi-select field, or one user of a list-user field.

Parameters

  • value Any, required
    The whole value to look for. Unlike contains, part of a value doesn't match.

Returns Condition

A condition to pass as where.

has(value: Any) -> Condition

Match none of a field's values

Match records where none of the field's values is exactly this.

Parameters

  • value Any, required
    The whole value to look for.

Returns Condition

A condition to pass as where.

not_has(value: Any) -> Condition

Match any of several values

Match any of the values, as a series of EX conditions joined with OR.

Parameters

  • values Iterable[Any], required
    The values to match. There must be at least one.

Returns Expression

A condition to pass as where.

Raises

is_in(values: Iterable[Any]) -> Expression

Use any operator

Use any Quickbase operator directly, such as TV or IR.

Parameters

  • operator str, required
    The operator, in capitals. Quickbase treats a lowercase one as "contains".
  • value Any, required
    The value to compare with.

Returns Condition

A condition to pass as where.

Raises

op(operator: str, value: Any) -> Condition

Expression

A query condition. Combine with & and |, not and and or.

Example

from pyquickbase import F

done_or_long = (F("Status") == "Done") | (F("Hours") > 10)
print(tasks.count(done_or_long))
from pyquickbase import F

done_or_long = (F("Status") == "Done") | (F("Hours") > 10)
print(await tasks.count(done_or_long))

Output

2

Conditions from plain data

For the full picture, see Using pyquickbase from an AI agent.

Build a condition from JSON

Build a condition from plain data, such as the JSON from a model's tool call.

The result works anywhere a condition built with F does, including combined with one, which is how to keep a model inside a scope your code decides:

scope = F("Project") == project
allowed = ["Status", "Due Date"]
where = scope & where_from_dict(
    data, fields=allowed
)

A condition is {"field": "Status", "op": "==", "value": "Open"}, and {"all": [...]} and {"any": [...]} combine them, nested if needed. field is a label or ID. op is ==, !=, <, <=, >, >=, contains, not_contains, starts_with, not_starts_with, has, not_has, in, not_in, or a Quickbase operator such as TV, other than IR and XIR. has matches one of a multi-select field's values exactly.

Spellings a model tends to write are read as the operator they mean: case, spaces, hyphens, and camelCase don't matter, so starts with and startsWith are starts_with, and eq, =, ne, <>, lt, gte, and the like are the matching symbol. and and or are read as all and any. Each of these means exactly one operator, so none can change what a filter means. Labels are never guessed: a label must match exactly.

Values are escaped as they are with F. Unlike F, a value is also checked against the type of its field when the query is built: dates must be YYYY-MM-DD, timestamps need a time zone or to be dates, and numbers and checkboxes must be what they say. So today is refused, as Quickbase matches nothing, with no error, for text it can't read as a date.

This protects a query's shape, not its meaning. A model that chooses the field and operator chooses the result, so a condition can still match every record. See Using pyquickbase from an AI agent.

Parameters

  • data Mapping[str, Any], required
    The condition or group. value is required on every condition, so that a dropped key can't turn into a search for empty fields. Send null to mean that on purpose, which works with ==, !=, in, and not_in.
  • fields Iterable[str | int] | Iterable[Field] | None, optional
    The only fields this filter may use, as labels, IDs, or Field objects, which count by label. Pass the same list as to where_schema. Without this, it may use any field the token can see, and a model could learn a value it can't read by filtering on it. A field listed by label can't be named by its ID.

Returns Expression

A condition to pass as where.

Raises

  • QueryError: The data can't be used, and the message says where. Nothing was sent. One with over 100 conditions, counting each value of in and not_in, or groups over 20 levels deep, is refused too. Type checks raise this when the query is built, not here.
  • UnknownFieldError: The table has no such field, raised when the query is built.
where_from_dict(
    data: Mapping[str, Any],
    *,
    fields: (
        Iterable[str | int] | Iterable[Field] | None
    ) = None,
) -> Expression

Example

from pyquickbase import where_from_dict

data = {
    "all": [
        {"field": "Status", "op": "==", "value": "Open"},
        {"field": "Hours", "op": ">", "value": 10},
    ]
}
where = where_from_dict(data, fields=["Status", "Hours"])
print(tasks.count(where))
from pyquickbase import where_from_dict

data = {
    "all": [
        {"field": "Status", "op": "==", "value": "Open"},
        {"field": "Hours", "op": ">", "value": 10},
    ]
}
where = where_from_dict(data, fields=["Status", "Hours"])
print(await tasks.count(where))

Output

1

Describe conditions as JSON Schema

Describe the format of where_from_dict as JSON Schema, for a tool's input.

The schema is self-contained, with no $ref, so it can go anywhere in a tool's input schema. It's a new dictionary each time, so you can add to it, such as a description.

Parameters

  • fields Iterable[str | int] | Iterable[Field] | None, optional
    The fields to offer, as labels, IDs, or Field objects, so a model can't name one that doesn't exist. Pass the same fields to where_from_dict, by label or ID, to enforce the list, as this only describes it. Field labels can contain any text, and this shows them to the model, so only offer fields from an app you trust. Given Field objects, the description also says what a number means on a percent or duration field.
  • field_descriptions Mapping[str | int, str] | None, optional
    What each field means, as {label or ID: text}, added to the schema's description so the model can choose the right field. Each must be for a field in fields, so a renamed field can't silently keep a description.
  • max_depth int, default 2
    How many levels of all and any to describe, from 0 to 5. The default allows A and (B or C). A tool's schema is sent to the model with every request, so each level has a cost. where_from_dict accepts deeper filters regardless.

Returns dict[str, Any]

The JSON Schema, as a dictionary.

Raises

where_schema(
    *,
    fields: (
        Iterable[str | int] | Iterable[Field] | None
    ) = None,
    field_descriptions: Mapping[str | int, str] | None = None,
    max_depth: int = 2,
) -> dict[str, Any]

Example

from pyquickbase import where_schema

schema = where_schema(fields=["Status", "Hours"], max_depth=1)
print(type(schema).__name__, "$ref" in str(schema))
from pyquickbase import where_schema

schema = where_schema(fields=["Status", "Hours"], max_depth=1)
print(type(schema).__name__, "$ref" in str(schema))

Output

dict False

Check a hand-written condition

For the full picture, see Reading records.

Check a hand-written condition

Check a hand-written where string and return its conditions.

Useful for extra checks of your own, or for finding out which fields a string refers to.

Parameters

  • where str, required
    The string, such as {7.EX.'Open'}.
  • fields Iterable[Field], required
    The table's fields, from Table.fields().

Returns list[ WhereCondition ]

A WhereCondition for each condition in the string.

Raises

parse_where(
    where: str, fields: Iterable[Field]
) -> list[WhereCondition]

Example

from pyquickbase import parse_where

fields = tasks.fields()
where = "{7.EX.'Open'}AND{8.GT.'5'}"
print([c.field_id for c in parse_where(where, fields)])
from pyquickbase import parse_where

fields = await tasks.fields()
where = "{7.EX.'Open'}AND{8.GT.'5'}"
print([c.field_id for c in parse_where(where, fields)])

Output

[7, 8]

WhereCondition

One condition from a where string, with its value unquoted and unescaped.

Attributes

  • field_id int
    The ID of the field it tests.
  • operator str
    Quickbase's operator, such as EX.
  • value str
    The value it compares with, as text.

Example

from pyquickbase import parse_where

fields = tasks.fields()
condition = parse_where("{7.EX.'Open'}", fields)[0]
print(condition.field_id, condition.operator, condition.value)
from pyquickbase import parse_where

fields = await tasks.fields()
condition = parse_where("{7.EX.'Open'}", fields)[0]
print(condition.field_id, condition.operator, condition.value)

Output

7 EX Open

Ways to name a field

For the full picture, see Reading records.

FieldRef

A field, by label (str) or ID (int).

FieldRef = str | int

FieldRefs

One or more fields, by label, ID, or F, as select and order_by take them.

FieldRefs = str | int | F | Sequence[str | int | F]