Query
Query
Query builds a filtered request for the entries of a single content type. Use this class to
- narrow entries by field value, tag, or referenced entry
- choose which fields, references, and embedded items the response carries
- paginate and sort the result
- run the request with find or find_one
| Name | Type | Description |
| --- | --- | --- |
| content_type_uid | str | UID of the content type whose entries the query returns. |
stack.content_type('<CONTENT_TYPE_UID>').query() is the only way to get an instance. query() itself takes no arguments, so the content type UID comes from the content_type call before it. Passing no UID raises PermissionError with the message Content type UID is required. Provide a UID and try again.
Warning stack.content_type('').query() does not raise. The constructor rejects None and nothing else, so an empty string builds a query against the URL path /content_types//entries. A variable that is unexpectedly empty therefore produces a request the SDK never questions. Guard the UID before you build the query.
| Name | Type | Description |
|---|---|---|
| content_type_uid | str | |
| base_url | str |
add_param
add_param adds one arbitrary entry option to the request.
| Name | Type | Description |
|---|---|---|
| key (required) | str | Entry option name to send. |
| value (required) | str | Value for that entry option. |
The same query, for chaining.
Validation
- There is no client-side validation, and no raise. add_param records whatever it receives.
- Passing None as either argument makes add_param a no-op. It records nothing and returns the query, so the option disappears without any error. This is the difference from param, which raises KeyError on a null argument.
- An empty string passes as well, so add_param('', '') records an option with no name.
- Omitting either argument raises TypeError immediately, because both are positional parameters with no default.
- Errors that do occur come from the find() call that follows, not from add_param().
- find() raises an exception only for network failures (timeout, DNS error, dropped connection).
- An API-level rejection (for example, an option name the API does not recognize) returns as a normal result with an error key. It does not raise an exception.
- Check the result for an error key even inside a try block.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. add_param records the pair in the entry option store and makes no request.
- Writes the same store as locale, only, excepts, and include_reference, so it can set those parameters directly. find copies that store over the URL query parameters, which is why an add_param key wins over the same key from param or add_params. See Three stores on the Query class page.
- Keeps the value as it is, with no string conversion, so a list survives and find sends one parameter per element. This is what makes it the route to a multi-field only[BASE][] or except[BASE][] value.
- Calling add_param twice with the same key replaces the first value. The SDK records it under that key.
- remove_param cannot delete what add_param records, because that method reaches the URL query parameters only.
- Prefer the dedicated method when one exists. Use add_param for an entry option the SDK exposes no method for, or when a dedicated method rejects the value shape you need.
Example
Basic usage: set an entry option the SDK has no method for
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
result = stack.content_type('blog_post').query() \
.add_param('include_dimension', 'true') \
.find()
except Exception as error:
# Raised only for network failures (timeout, DNS error, dropped connection)
print('Request failed:', error)
else:
if 'error' in result:
# The Delivery API rejected the request and returned the error body
print('Delivery API error:', result['error'])
else:
print('entries:', len(result.get('entries', [])))All parameters: both arguments, with a list value
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
# key and value both passed to add_param. A list survives here, and only() rejects one.
result = stack.content_type('blog_post').query() \
.add_param('only[BASE][]', ['title', 'url']) \
.find()
print('returned', len(result.get('entries', [])), 'entries')
except Exception as error:
print('Request failed:', error)Edge case: a null key disappears without an error
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
option_name = None
try:
# No exception here, and no option reaches the API. Guard the value instead.
result = stack.content_type('blog_post').query() \
.add_param(option_name, 'true') \
.find()
print('returned', len(result.get('entries', [])), 'entries')
except Exception as error:
print('Request failed:', error)add_params
add_params merges a dictionary of URL query parameters into the request.
| Name | Type | Description |
|---|---|---|
| param (required) | dict | Query parameter names and values to merge. |
The same query, for chaining.
Validation
- There is no client-side validation of the contents. add_params merges an unrecognized parameter name or a value of any type as given.
- Passing None raises TypeError with the message "'NoneType' object is not iterable", because the merge needs something to read pairs from. The same happens for an integer or any other value that is not iterable.
- Passing a string raises ValueError, because the merge reads each character as a key and value pair and a single character supplies only one of the two.
- Passing an empty dictionary is valid and changes nothing.
- Omitting the argument raises TypeError immediately, because param is a positional parameter with no default.
- Errors that do occur come from the find() call that follows, not from add_params().
- find() raises an exception only for network failures (timeout, DNS error, dropped connection).
- An API-level rejection returns as a normal result with an error key. It does not raise an exception.
- Check the result for an error key even inside a try block.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. add_params merges the pairs into the URL query parameters and makes no request.
- Keeps every value as it is, unlike param, which converts the value to a string. A list value therefore survives and find sends one parameter per element.
- Overwrites a key that a dedicated modifier already recorded, so a dictionary carrying limit replaces the value that limit set. Calling add_params twice merges both dictionaries, and the later call wins on a shared key.
- Loses to the entry option store. A key that locale, only, or add_param wrote overwrites the same key here when find assembles the request. See Three stores on the Query class page.
- Accepts anything a dictionary merge accepts, so a list of two-item tuples works as well as a dictionary.
- Use it when the parameter set comes from configuration or from a request the calling code received. Use param for a single hard-coded pair.
Example
Basic usage: merge two query parameters at once
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
result = stack.content_type('blog_post').query() \
.add_params({'include_publish_details': 'true', 'limit': '10'}) \
.find()
except Exception as error:
# Raised only for network failures (timeout, DNS error, dropped connection)
print('Request failed:', error)
else:
if 'error' in result:
# The Delivery API rejected the request and returned the error body
print('Delivery API error:', result['error'])
else:
print('entries:', len(result.get('entries', [])))All parameters: the single dictionary argument, built from configuration
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
extra_params = {'include_publish_details': 'true', 'only[BASE][]': ['title', 'url']}
try:
# param passed directly to add_params. The list value stays a list.
result = stack.content_type('blog_post').query().add_params(extra_params).find()
print('returned', len(result.get('entries', [])), 'entries')
except Exception as error:
print('Request failed:', error)Error handling: a null dictionary raises at the call site
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
extra_params = None
try:
result = stack.content_type('blog_post').query().add_params(extra_params).find()
except TypeError as error:
# Fires on add_params itself, before any request goes out.
print('Pass a dictionary:', error)Edge case: the merge overwrites a dedicated modifier
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
# limit(10) runs first and the merge replaces it, so this sends limit=25.
result = stack.content_type('blog_post').query() \
.limit(10) \
.add_params({'limit': '25'}) \
.find()
except Exception as error:
print('Request failed:', error)asset_fields
asset_fields adds optional asset field groups to the assets the response carries.
| Name | Type | Description |
|---|---|---|
| field_names (required) | str | Asset field group to include, passed as separate arguments. |
The same query, for chaining.
Validation
- There is no client-side validation of the names. asset_fields converts every argument to a string and records it, including a misspelled group name, so a typo surfaces as an API rejection rather than a local error.
- Calling asset_fields() with no arguments makes it a no-op. It records nothing, raises nothing, and returns the query.
- The four names the SDK documents are user_defined_fields, embedded_metadata, ai_generated_metadata, and visual_markups.
- Errors that do occur come from the find() call that follows, not from asset_fields().
- find() raises an exception only for network failures (timeout, DNS error, dropped connection).
- An API-level rejection (for example, an unrecognized field group) returns as a normal result with an error key. It does not raise an exception.
- Check the result for an error key even inside a try block.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. asset_fields records the asset_fields[] entry option and makes no request. find sends one asset_fields[] parameter per recorded name on that call.
- Accumulates instead of replacing, unlike every other modifier on this class. A second call adds to the list the first one recorded, so three separate calls and one call with three arguments produce the same request.
- Flattens a list or a tuple you pass as one argument, so asset_fields(['user_defined_fields', 'visual_markups']) records both names.
- Keeps duplicates. Calling the same name twice records it twice and sends it twice, so guard the list when it comes from user input.
- Applies to the assets inside the entries the query returns. It has no effect on a query whose entries carry no asset fields.
Example
Basic usage: add one asset field group
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
result = stack.content_type('blog_post').query() \
.asset_fields('user_defined_fields') \
.find()
except Exception as error:
# Raised only for network failures (timeout, DNS error, dropped connection)
print('Request failed:', error)
else:
if 'error' in result:
# The Delivery API rejected the request and returned the error body
print('Delivery API error:', result['error'])
else:
for entry in result.get('entries', []):
print(entry['uid'], entry.get('featured_image'))All parameters: every documented field group in one call
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
# All four names passed to asset_fields as separate arguments.
result = stack.content_type('blog_post').query() \
.asset_fields(
'user_defined_fields',
'embedded_metadata',
'ai_generated_metadata',
'visual_markups',
) \
.find()
print('returned', len(result.get('entries', [])), 'entries')
except Exception as error:
print('Request failed:', error)Edge case: repeated calls add up instead of replacing
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
# Two calls, and the request carries both names. A third call adding
# user_defined_fields again would send it twice.
result = stack.content_type('blog_post').query() \
.asset_fields('user_defined_fields') \
.asset_fields('visual_markups') \
.find()
except Exception as error:
print('Request failed:', error)excepts
excepts removes one top-level field of the content type from the response.
| Name | Type | Description |
|---|---|---|
| field_uid (required) | str | Top-level field UID to drop from the response. |
The same query, for chaining.
Validation
- excepts rejects a value that is not a string. It raises KeyError with the message "Invalid field UID. Provide a valid UID and try again." because the parameter holds one field name, so a list or an integer cannot serve as one.
- Passing None makes excepts a no-op. It records nothing and returns the query, so the response carries every field instead of raising.
- There is no check on the field name itself. excepts records an unknown field UID or an empty string as given.
- Omitting the argument raises TypeError immediately, because field_uid is a positional parameter with no default.
- Any remaining errors come from the find() call that follows, not from excepts().
- find() raises an exception only for network failures (timeout, DNS error, dropped connection).
- An API-level rejection returns as a normal result with an error key. It does not raise an exception.
- Check the result for an error key even inside a try block.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. excepts records the except[BASE][] entry option and makes no request. find sends the value on that call.
- Applies to the top-level fields of the schema. A nested field inside a group or a modular block is out of reach of this parameter.
- Calling excepts twice replaces the first field name. The SDK records it under a single key, so the second call wins rather than dropping a second field.
- Chaining only as well sends both parameters. The SDK writes each under its own key and does not reconcile them, so chain one or the other.
- Use excepts to trim one large field, such as a rich text body, out of a listing response. Use only instead when the response should carry a short allowed set.
Limitations
- Does not accept a list of field names. Pass a list through the add_param method as add_param('except[BASE][]', ['body', 'seo']) to drop more than one field, as the last example shows.
Example
Basic usage: drop one field from a listing
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
result = stack.content_type('blog_post').query().excepts('body').find()
except Exception as error:
# Raised only for network failures (timeout, DNS error, dropped connection)
print('Request failed:', error)
else:
if 'error' in result:
# The Delivery API rejected the request and returned the error body
print('Delivery API error:', result['error'])
else:
for entry in result.get('entries', []):
print(entry['uid'], 'body' in entry)All parameters: the single field UID argument
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
field_uid = 'body'
try:
# field_uid passed directly to excepts.
result = stack.content_type('blog_post').query().excepts(field_uid).limit(10).find()
print('returned', len(result.get('entries', [])), 'entries')
except Exception as error:
print('Request failed:', error)Error handling: a list raises at the call site
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
result = stack.content_type('blog_post').query().excepts(['body', 'seo']).find()
except KeyError as error:
# Fires on excepts itself, before any request goes out.
print('Pass one field name as a string:', error)Edge case: drop several fields through add_param
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
# add_param writes the same parameter and accepts a list.
result = stack.content_type('blog_post').query() \
.add_param('except[BASE][]', ['body', 'seo']) \
.find()
except Exception as error:
print('Request failed:', error)find
find runs the query and retrieves the entries that match it.
The entries matching the query.
Validation
- find validates nothing. It serializes whatever the query holds, including a negative page size or a condition on a field that does not exist, and sends it.
- find raises an exception only for network failures (timeout, DNS error, dropped connection). The exception type is RequestError.
- An API-level rejection, including a content type UID that names no content type, returns as a normal result with an error key. It does not raise an exception.
- Check the result for an error key even inside a try block.
- find always raises when the Stack carries a live_preview dictionary, because the merge never completes. It raises TypeError with the message "Invalid input. entry_response and lp_response must be lists of dictionaries. Update the values and try again." when the draft request returned an entry, and ValueError with the message "Missing required keys in live preview data. Provide all required keys and try again." when it returned none. See Live preview on the Query class page for the configuration that triggers each one.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Calls GET /content_types/{content_type_uid}/entries and makes one HTTP request per call.
- Returns the raw parsed API response as a dictionary. The entries key holds the matching entries, and count holds the total when you chain include_count.
- Assembles the request from the three stores the chained methods write, then adds the environment value from the Stack headers. See Three stores on the Query class page for which method writes which store.
- Keeps the accumulated state after the call. Calling find a second time on the same instance repeats the request with everything chained so far, so build a fresh query for an unrelated request.
- Parses the body itself when the response arrives as a JSON string. A parse failure prints the error and returns {'error': 'Invalid JSON response'}.
- Returns nothing when the Stack carries a live_preview dictionary. find takes the merge path and raises TypeError or ValueError there, as the Validation section above describes.
Limitations
- Does not paginate. One call reads one page. See Pagination on the Query class page for how to read the rest.
- Does not return typed Entry objects. Read the dictionary keys directly.
- Does not clear the query between calls. Use remove_param to drop a URL parameter you no longer want.
Example
Basic usage: read the entries of a content type
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
result = stack.content_type('blog_post').query().find()
except Exception as error:
# Raised only for network failures (timeout, DNS error, dropped connection)
print('Request failed:', error)
else:
if 'error' in result:
# The Delivery API rejected the request and returned the error body
print('Delivery API error:', result['error'])
else:
for entry in result.get('entries', []):
print(entry['uid'], entry.get('title'))Filtering and pagination: everything the query holds reaches this call
import contentstack
from contentstack.basequery import QueryOperation
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
result = stack.content_type('blog_post').query() \
.where('price', QueryOperation.IS_LESS_THAN, fields=90) \
.order_by_descending('price') \
.skip(10) \
.limit(10) \
.include_count() \
.find()
print('total matches:', result.get('count'))
except Exception as error:
print('Request failed:', error)Error handling: an unknown content type does not raise
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
result = stack.content_type('no_such_content_type').query().find()
except Exception as error:
print('Request failed:', error)
else:
# A missing content type arrives as an ordinary return value, not an exception.
if 'error' in result:
print('code:', result.get('error_code'), 'message:', result.get('error_message'))Edge case: a reused instance keeps every earlier modifier
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
query = stack.content_type('blog_post').query()
try:
first_page = query.limit(10).find()
# limit(10) still applies here, and skip(10) is added to it.
second_page = query.skip(10).find()
except Exception as error:
print('Request failed:', error)find_one
find_one runs the query with the page size fixed at one and retrieves the single entry that comes back.
At most one matching entry, in the standard entries list.
Validation
- find_one validates nothing. It serializes whatever the query holds and sends it.
- find_one raises an exception only for network failures (timeout, DNS error, dropped connection). The exception type is RequestError.
- An API-level rejection, including a content type UID that names no content type, returns as a normal result with an error key. It does not raise an exception.
- Check the result for an error key even inside a try block.
- A query that matches nothing is not an error. The response carries an empty entries list, so test the list length before you index into it.
- find_one always raises when the Stack carries a live_preview dictionary, because the merge never completes. It raises TypeError with the message "Invalid input. entry_response and lp_response must be lists of dictionaries. Update the values and try again." when the draft request returned an entry, and ValueError with the message "Missing required keys in live preview data. Provide all required keys and try again." when it returned none. See Live preview on the Query class page for the configuration that triggers each one.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Calls the same endpoint as find, GET /content_types/{content_type_uid}/entries, and makes one HTTP request per call.
- Writes limit=1 before sending the request, so a limit call chained earlier has no effect and a limit call after find_one applies to the next terminal call instead.
- Returns the same response shape as find. The entries key holds a list rather than a bare entry, so read result['entries'][0] to reach the entry itself.
- Leaves limit=1 on the instance. A later find call on the same query therefore returns one entry as well until you chain a new limit.
- Selects the first entry of the page the API returns. Chain order_by_ascending or order_by_descending when you need a defined first entry rather than whichever entry the API orders first.
Limitations
- Does not report whether other entries matched. Chain include_count to read the total.
- Does not return typed Entry objects. Read the dictionary keys directly.
Example
Basic usage: read the first matching entry
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
result = stack.content_type('blog_post').query().find_one()
except Exception as error:
# Raised only for network failures (timeout, DNS error, dropped connection)
print('Request failed:', error)
else:
if 'error' in result:
# The Delivery API rejected the request and returned the error body
print('Delivery API error:', result['error'])
else:
entries = result.get('entries', [])
print(entries[0]['title'] if entries else 'no match')Sorted lookup: make the first entry deterministic
import contentstack
from contentstack.basequery import QueryOperation
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
result = stack.content_type('blog_post').query() \
.where('category', QueryOperation.EQUALS, fields='release_notes') \
.order_by_descending('published_at') \
.find_one()
print('newest release note:', result['entries'][0]['title'])
except Exception as error:
print('Request failed:', error)Edge case: the page size stays at one afterwards
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
query = stack.content_type('blog_post').query()
try:
single = query.find_one()
# This still returns one entry, because find_one left limit=1 behind.
everything = query.find()
# Chain limit again to widen the page.
ten = query.limit(10).find()
except Exception as error:
print('Request failed:', error)include_branch
include_branch adds the _branch field to every entry in the response.
The same query, for chaining.
Validation
- There is nothing to validate. include_branch takes no arguments, so it cannot fail at the call site.
- Errors that do occur come from the find() call that follows, not from include_branch().
- find() raises an exception only for network failures (timeout, DNS error, dropped connection).
- An API-level rejection returns as a normal result with an error key. It does not raise an exception.
- Check the result for an error key even inside a try block.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. include_branch records include_branch=true as a URL query parameter and makes no request. find sends the flag on that call.
- Reports which branch served the entry. It does not choose the branch. Pass branch to Stack to select one, and use this flag to confirm the selection took effect.
- Calling it twice changes nothing. The flag holds a single value.
- Adds one field per entry, so the response size grows by the branch name for each result.
Example
Basic usage: confirm which branch served the entries
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
result = stack.content_type('blog_post').query().include_branch().find()
except Exception as error:
# Raised only for network failures (timeout, DNS error, dropped connection)
print('Request failed:', error)
else:
if 'error' in result:
# The Delivery API rejected the request and returned the error body
print('Delivery API error:', result['error'])
else:
for entry in result.get('entries', []):
print(entry['uid'], entry.get('_branch'))Combined usage: read a named branch and verify the response
import contentstack
stack = contentstack.Stack(
'<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>', branch='<BRANCH_UID>'
)
try:
result = stack.content_type('blog_post').query() \
.include_branch() \
.limit(10) \
.find()
except Exception as error:
print('Request failed:', error)include_content_type
include_content_type adds the content type schema to the response alongside the entries.
The same query, for chaining.
Validation
- There is nothing to validate. include_content_type takes no arguments, so it cannot fail at the call site.
- Errors that do occur come from the find() call that follows, not from include_content_type().
- find() raises an exception only for network failures (timeout, DNS error, dropped connection).
- An API-level rejection returns as a normal result with an error key. It does not raise an exception.
- Check the result for an error key even inside a try block.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. include_content_type records two entry options, include_content_type=true and include_global_field_schema=true, and makes no request. find sends both flags on that call.
- Sends the global field schema whether you want it or not, because the two flags travel together. There is no argument that separates them.
- Calling it twice changes nothing. Both flags hold a single value.
- Adds a request flag and nothing else. The SDK does not read or reshape the schema the API returns.
- Use it when the calling code renders fields generically and needs the field definitions along with the values. Fetch the schema through the ContentType class instead when you need it without the entries.
Example
Basic usage: read the entries together with their schema
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
result = stack.content_type('blog_post').query().include_content_type().find()
except Exception as error:
# Raised only for network failures (timeout, DNS error, dropped connection)
print('Request failed:', error)
else:
if 'error' in result:
# The Delivery API rejected the request and returned the error body
print('Delivery API error:', result['error'])
else:
# The schema arrives in the same response body as the entries.
print('response keys:', list(result.keys()))
print('entries:', len(result.get('entries', [])))Combined usage: a schema-driven listing on one request
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
result = stack.content_type('blog_post').query() \
.include_content_type() \
.limit(10) \
.include_count() \
.find()
print('total entries:', result.get('count'))
except Exception as error:
print('Request failed:', error)include_count
include_count adds the total number of matching entries to the response.
The same query, for chaining.
Validation
- There is nothing to validate. include_count takes no arguments, so it cannot fail at the call site.
- Errors that do occur come from the find() call that follows, not from include_count().
- find() raises an exception only for network failures (timeout, DNS error, dropped connection).
- An API-level rejection returns as a normal result with an error key. It does not raise an exception.
- Check the result for an error key even inside a try block.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. include_count records include_count=true as a URL query parameter and makes no request. find sends the flag on that call.
- Adds a count key next to entries in the response. The count covers every entry the conditions match, not the number on the page.
- Reports the total the limit and skip values do not tell you. Compare count against the length of entries to find out whether more pages remain.
- Calling it twice changes nothing. The flag holds a single value.
- Writes the URL query parameters, so remove_param can delete the flag again before you call find.
Example
Basic usage: read the first page and the total
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
result = stack.content_type('blog_post').query().limit(10).include_count().find()
except Exception as error:
# Raised only for network failures (timeout, DNS error, dropped connection)
print('Request failed:', error)
else:
if 'error' in result:
# The Delivery API rejected the request and returned the error body
print('Delivery API error:', result['error'])
else:
print('total entries:', result.get('count'))
print('on this page:', len(result.get('entries', [])))Combined usage: decide whether another page exists
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
page_size = 10
try:
result = stack.content_type('blog_post').query() \
.order_by_ascending('title') \
.limit(page_size) \
.include_count() \
.find()
total = result.get('count', 0)
print('more pages:', total > page_size)
except Exception as error:
print('Request failed:', error)include_embedded_items
include_embedded_items resolves the entries and assets embedded in rich text fields.
The same query, for chaining.
Validation
- There is nothing to validate. include_embedded_items takes no arguments, so it cannot fail at the call site.
- Errors that do occur come from the find() call that follows, not from include_embedded_items().
- find() raises an exception only for network failures (timeout, DNS error, dropped connection).
- An API-level rejection returns as a normal result with an error key. It does not raise an exception.
- Check the result for an error key even inside a try block.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. include_embedded_items records include_embedded_items[]=BASE as a URL query parameter and makes no request. find sends the value on that call.
- Sends the fixed value BASE, which covers the top-level fields of the entry. The method takes no argument, so there is no way to name a different scope through it. Use the param method to send a different value under the same key.
- Calling it twice changes nothing. The parameter holds a single value.
- Covers items embedded in a rich text field, which is a different mechanism from a reference field. Use the include_reference method for reference fields.
- Increases the response size for every entry whose rich text carries embedded items. Combine it with limit when the listing is large.
Example
Basic usage: resolve the embedded items in a rich text listing
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
result = stack.content_type('blog_post').query().include_embedded_items().find()
except Exception as error:
# Raised only for network failures (timeout, DNS error, dropped connection)
print('Request failed:', error)
else:
if 'error' in result:
# The Delivery API rejected the request and returned the error body
print('Delivery API error:', result['error'])
else:
for entry in result.get('entries', []):
# The resolved items arrive inside the same entry dictionary.
print(entry['uid'], list(entry.keys()))Combined usage: embedded items alongside resolved references
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
result = stack.content_type('blog_post').query() \
.include_embedded_items() \
.include_reference('brand') \
.limit(10) \
.find()
except Exception as error:
print('Request failed:', error)include_fallback
include_fallback returns an earlier locale in the hierarchy for an entry that has no localization in the requested locale.
The same query, for chaining.
Validation
- There is nothing to validate. include_fallback takes no arguments, so it cannot fail at the call site.
- Errors that do occur come from the find() call that follows, not from include_fallback().
- find() raises an exception only for network failures (timeout, DNS error, dropped connection).
- An API-level rejection returns as a normal result with an error key. It does not raise an exception.
- Check the result for an error key even inside a try block.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. include_fallback records include_fallback=true as a URL query parameter and makes no request. find sends the flag on that call.
- Pairs with locale. Without a locale the request has nothing to fall back from, so chain both.
- Changes the size of the result rather than the shape of an entry. Entries that would otherwise be absent appear in the list.
- Calling it twice changes nothing. The flag holds a single value.
- Read the locale field on each entry to detect a fallback. The response does not flag which entries came from the requested locale and which came from an earlier one.
Example
Basic usage: fill the gaps in a localized listing
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
result = stack.content_type('blog_post').query() \
.locale('fr-fr') \
.include_fallback() \
.find()
except Exception as error:
# Raised only for network failures (timeout, DNS error, dropped connection)
print('Request failed:', error)
else:
if 'error' in result:
# The Delivery API rejected the request and returned the error body
print('Delivery API error:', result['error'])
else:
for entry in result.get('entries', []):
# A locale other than fr-fr marks a fallback.
print(entry['uid'], entry.get('locale'))Edge case: the flag has no effect without a locale
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
# No locale, so there is nothing to fall back from.
ignored = stack.content_type('blog_post').query().include_fallback().find()
# Chain locale as well for the flag to matter.
localized = stack.content_type('blog_post').query() \
.locale('fr-fr') \
.include_fallback() \
.find()
except Exception as error:
print('Request failed:', error)include_metadata
include_metadata adds entry and asset metadata to the response.
The same query, for chaining.
Validation
- There is nothing to validate. include_metadata takes no arguments, so it cannot fail at the call site.
- Errors that do occur come from the find() call that follows, not from include_metadata().
- find() raises an exception only for network failures (timeout, DNS error, dropped connection).
- An API-level rejection returns as a normal result with an error key. It does not raise an exception.
- Check the result for an error key even inside a try block.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. include_metadata records include_metadata=true as a URL query parameter and makes no request. find sends the flag on that call.
- Calling it twice changes nothing. The flag holds a single value.
- Writes the URL query parameters rather than the entry option store, so remove_param can delete the flag again before you call find. See Three stores on the Query class page.
- Covers metadata on the entries and on the assets the response carries. Use asset_fields when you need a specific asset field group rather than the metadata block.
Example
Basic usage: add metadata to a listing
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
result = stack.content_type('blog_post').query().include_metadata().find()
except Exception as error:
# Raised only for network failures (timeout, DNS error, dropped connection)
print('Request failed:', error)
else:
if 'error' in result:
# The Delivery API rejected the request and returned the error body
print('Delivery API error:', result['error'])
else:
for entry in result.get('entries', []):
# The metadata arrives inside the same entry dictionary.
print(entry['uid'], list(entry.keys()))Edge case: remove the flag again before running the query
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
want_metadata = False
try:
query = stack.content_type('blog_post').query().include_metadata()
if not want_metadata:
query = query.remove_param('include_metadata')
result = query.find()
except Exception as error:
print('Request failed:', error)include_reference
include_reference resolves the named reference fields inline instead of returning only the referenced UIDs.
| Name | Type | Description |
|---|---|---|
| field_uid (required) | str or list | Reference field UID, or a list of them, to resolve. |
The same query, for chaining.
Validation
- There is no client-side validation of the field names. include_reference records an unknown field UID or an empty string as given.
- Passing None, or any value that is not a string or a list, makes include_reference a no-op. It records nothing, raises nothing, and returns the query, so the response still carries bare UIDs. A tuple falls into this case, so convert it to a list first.
- Omitting the argument raises TypeError immediately, because field_uid is a positional parameter with no default.
- Errors that do occur come from the find() call that follows, not from include_reference().
- find() raises an exception only for network failures (timeout, DNS error, dropped connection).
- An API-level rejection returns as a normal result with an error key. It does not raise an exception.
- Check the result for an error key even inside a try block.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. include_reference records the include[] entry option and makes no request. find sends the value on that call.
- Accepts a list, unlike only and excepts. A list sends one include[] parameter per element, so one call covers every reference field you name.
- Calling include_reference twice replaces the first value. The SDK records it under a single key, so pass every reference field in one list rather than in separate calls.
- Resolves the named field only. A reference inside a resolved entry stays a bare UID unless you name its path as well.
- Increases the response size for every entry on the page. Combine it with limit when the listing is large.
Limitations
- Does not resolve more than three levels of references. The Delivery API stops at that depth for a reference field that points at multiple content types.
- Does not resolve embedded entries inside rich text. Use the include_embedded_items method for those.
Example
Basic usage: resolve one reference field
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
result = stack.content_type('blog_post').query().include_reference('brand').find()
except Exception as error:
# Raised only for network failures (timeout, DNS error, dropped connection)
print('Request failed:', error)
else:
if 'error' in result:
# The Delivery API rejected the request and returned the error body
print('Delivery API error:', result['error'])
else:
for entry in result.get('entries', []):
print(entry['title'], entry.get('brand'))All parameters: the field UID argument as a list
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
# field_uid passed to include_reference as a list of two reference fields.
result = stack.content_type('blog_post').query() \
.include_reference(['categories', 'brand']) \
.limit(10) \
.find()
print('returned', len(result.get('entries', [])), 'entries')
except Exception as error:
print('Request failed:', error)Edge case: a tuple never reaches the API
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
reference_fields = ('categories', 'brand')
try:
# Wrong. A tuple is neither a string nor a list, so nothing reaches the API.
ignored = stack.content_type('blog_post').query() \
.include_reference(reference_fields) \
.find()
# Correct. Convert to a list first.
resolved = stack.content_type('blog_post').query() \
.include_reference(list(reference_fields)) \
.find()
except Exception as error:
print('Request failed:', error)include_reference_content_type_uid
include_reference_content_type_uid adds the content type UID of every referenced entry to the response.
The same query, for chaining.
Validation
- There is nothing to validate. include_reference_content_type_uid takes no arguments, so it cannot fail at the call site.
- Errors that do occur come from the find() call that follows, not from include_reference_content_type_uid().
- find() raises an exception only for network failures (timeout, DNS error, dropped connection).
- An API-level rejection returns as a normal result with an error key. It does not raise an exception.
- Check the result for an error key even inside a try block.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. include_reference_content_type_uid records include_reference_content_type_uid=true as an entry option and makes no request. find sends the flag on that call.
- Calling it twice changes nothing. The flag holds a single value.
- Pair it with include_reference when a reference field points at more than one content type. The code reading the response can then tell which schema each resolved entry follows.
- Adds a field per referenced entry rather than an entry. The response size grows by the UID strings only.
Example
Basic usage: label each resolved reference with its content type
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
result = stack.content_type('blog_post').query() \
.include_reference_content_type_uid() \
.find()
except Exception as error:
# Raised only for network failures (timeout, DNS error, dropped connection)
print('Request failed:', error)
else:
if 'error' in result:
# The Delivery API rejected the request and returned the error body
print('Delivery API error:', result['error'])
else:
for entry in result.get('entries', []):
print(entry['title'], entry.get('brand'))Combined usage: resolve a multi-type reference and identify each schema
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
result = stack.content_type('blog_post').query() \
.include_reference('related_content') \
.include_reference_content_type_uid() \
.limit(10) \
.find()
except Exception as error:
print('Request failed:', error)limit
limit caps the number of entries the response contains.
| Name | Type | Description |
|---|---|---|
| limit_count (required) | int | Maximum number of entries to return. |
The same query, for chaining.
Validation
- There is no client-side validation. limit converts the argument to a string and sends a negative number, a zero, or a non-integer as given.
- Passing None sends the literal text limit=None, because the conversion happens without a null check. Guard the value before you chain the call.
- Omitting the argument raises TypeError immediately, because limit_count is a positional parameter with no default.
- Errors that do occur come from the find() call that follows, not from limit().
- find() raises an exception only for network failures (timeout, DNS error, dropped connection).
- An API-level rejection (for example, a page size above the maximum the API accepts) returns as a normal result with an error key. It does not raise an exception.
- Check the result for an error key even inside a try block.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. limit records the limit query parameter and makes no request. find sends the value on that call.
- Omitting limit does not return every entry. The SDK sets no default, so the API applies its own page size. See Pagination on the Query class page for how to detect a truncated page and read the rest.
- Calling limit twice replaces the first value. The SDK records it under a single key.
- find_one overwrites the value with 1. A limit call before find_one therefore has no effect on that call.
- Pair it with skip to move through the result one page at a time, and with include_count to learn the total.
Example
Basic usage: return at most ten entries
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
result = stack.content_type('blog_post').query().limit(10).find()
except Exception as error:
# Raised only for network failures (timeout, DNS error, dropped connection)
print('Request failed:', error)
else:
if 'error' in result:
# The Delivery API rejected the request and returned the error body
print('Delivery API error:', result['error'])
else:
print('returned', len(result.get('entries', [])), 'entries')All parameters: the single page size argument, alongside an offset
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
page_size = 10
try:
# limit_count passed directly to limit, with skip setting the offset.
result = stack.content_type('blog_post').query() \
.skip(20) \
.limit(page_size) \
.include_count() \
.find()
print('total entries:', result.get('count'))
except Exception as error:
print('Request failed:', error)Edge case: find_one ignores the page size
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
# This returns up to ten entries.
capped = stack.content_type('blog_post').query().limit(10).find()
# This returns one entry. find_one writes limit=1 over the value above.
single = stack.content_type('blog_post').query().limit(10).find_one()
except Exception as error:
print('Request failed:', error)locale
locale restricts the query to the entries published in one locale.
| Name | Type | Description |
|---|---|---|
| locale (required) | str | Locale code the query reads entries from. |
The same query, for chaining.
Validation
- There is no client-side validation. locale records an unknown locale code, an empty string, or a value of the wrong type as given.
- Passing None records the value without a null check, so find sends the literal text locale=None as the locale code. Guard the value before you chain the call.
- Omitting the argument raises TypeError immediately, because locale is a positional parameter with no default.
- Errors that do occur come from the find() call that follows, not from locale().
- find() raises an exception only for network failures (timeout, DNS error, dropped connection).
- An API-level rejection, including a locale code the stack does not define, returns as a normal result with an error key. It does not raise an exception.
- Check the result for an error key even inside a try block.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. locale records the locale entry option and makes no request. find sends the value on that call.
- Omitting locale leaves the parameter off the request. The SDK sets no default, so the API applies its own.
- Returns only the entries published in the locale you name. Chain include_fallback to fill the gaps from an earlier locale in the hierarchy.
- Calling locale twice replaces the first value. The SDK records it under a single key.
- Writes the entry option store rather than the URL query parameters, so remove_param cannot delete it again. See Three stores on the Query class page.
Example
Basic usage: read the entries of one locale
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
result = stack.content_type('blog_post').query().locale('fr-fr').find()
except Exception as error:
# Raised only for network failures (timeout, DNS error, dropped connection)
print('Request failed:', error)
else:
if 'error' in result:
# The Delivery API rejected the request and returned the error body
print('Delivery API error:', result['error'])
else:
for entry in result.get('entries', []):
print(entry['uid'], entry.get('locale'))All parameters: the single locale code argument
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
locale_code = 'fr-fr'
try:
# locale passed directly, with a fallback for unlocalized entries.
result = stack.content_type('blog_post').query() \
.locale(locale_code) \
.include_fallback() \
.find()
print('returned', len(result.get('entries', [])), 'entries')
except Exception as error:
print('Request failed:', error)Edge case: a null locale reaches the API as text
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
locale_code = None
try:
# Guard the value. Without the check this sends locale=None.
query = stack.content_type('blog_post').query()
if locale_code:
query = query.locale(locale_code)
result = query.find()
except Exception as error:
print('Request failed:', error)only
only restricts the response to one top-level field of the content type.
| Name | Type | Description |
|---|---|---|
| field_uid (required) | str | Top-level field UID to keep in the response. |
The same query, for chaining.
Validation
- only rejects a value that is not a string. It raises KeyError with the message "Invalid field UID. Provide a valid UID and try again." because the parameter holds one field name, so a list or an integer cannot serve as one.
- Passing None makes only a no-op. It records nothing and returns the query, so the response carries every field instead of raising.
- There is no check on the field name itself. only records an unknown field UID or an empty string as given.
- Omitting the argument raises TypeError immediately, because field_uid is a positional parameter with no default.
- Any remaining errors come from the find() call that follows, not from only().
- find() raises an exception only for network failures (timeout, DNS error, dropped connection).
- An API-level rejection returns as a normal result with an error key. It does not raise an exception.
- Check the result for an error key even inside a try block.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. only records the only[BASE][] entry option and makes no request. find sends the value on that call.
- Applies to the top-level fields of the schema. A nested field inside a group or a modular block is out of reach of this parameter.
- Calling only twice replaces the first field name. The SDK records it under a single key, so the second call wins rather than adding a field.
- Chaining excepts as well sends both parameters. The SDK writes each under its own key and does not reconcile them, so chain one or the other.
Limitations
- Does not accept a list of field names. Pass a list through the add_param method as add_param('only[BASE][]', ['title', 'url']) to keep more than one field, as the second example shows.
Example
Basic usage: return one field per entry
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
result = stack.content_type('blog_post').query().only('title').find()
except Exception as error:
# Raised only for network failures (timeout, DNS error, dropped connection)
print('Request failed:', error)
else:
if 'error' in result:
# The Delivery API rejected the request and returned the error body
print('Delivery API error:', result['error'])
else:
for entry in result.get('entries', []):
print(entry['uid'], entry.get('title'))All parameters: the single field UID argument
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
field_uid = 'title'
try:
# field_uid passed directly to only.
result = stack.content_type('blog_post').query().only(field_uid).limit(10).find()
print('returned', len(result.get('entries', [])), 'entries')
except Exception as error:
print('Request failed:', error)Error handling: a list raises at the call site
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
result = stack.content_type('blog_post').query().only(['title', 'url']).find()
except KeyError as error:
# Fires on only itself, before any request goes out.
print('Pass one field name as a string:', error)Edge case: keep several fields through add_param
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
# add_param writes the same parameter and accepts a list.
result = stack.content_type('blog_post').query() \
.add_param('only[BASE][]', ['title', 'url']) \
.find()
except Exception as error:
print('Request failed:', error)order_by_ascending
order_by_ascending sorts the entries by one field, lowest value first.
| Name | Type | Description |
|---|---|---|
| key (required) | str | Field UID the sort applies to. |
The same query, for chaining.
Validation
- There is no client-side validation. order_by_ascending converts the argument to a string and sends an unknown field UID or an empty string as given.
- Passing None sends the literal text asc=None, because the conversion happens without a null check. Guard the value before you chain the call.
- Omitting the argument raises TypeError immediately, because key is a positional parameter with no default.
- Errors that do occur come from the find() call that follows, not from order_by_ascending().
- find() raises an exception only for network failures (timeout, DNS error, dropped connection).
- An API-level rejection (for example, a field the API cannot sort on) returns as a normal result with an error key. It does not raise an exception.
- Check the result for an error key even inside a try block.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. order_by_ascending records the asc query parameter and makes no request. find sends the value on that call.
- Sorts on one field. Calling it twice replaces the first field name, because the SDK records it under a single key.
- Chaining order_by_descending as well sends both asc and desc. The SDK writes each under its own key and does not reconcile them, so chain one or the other.
- Omitting a sort leaves both parameters off the request, and the API makes no promise that two calls return the same order. Chain a sort before skip so that consecutive pages do not repeat or drop an entry.
Example
Basic usage: sort a listing by title
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
result = stack.content_type('blog_post').query().order_by_ascending('title').find()
except Exception as error:
# Raised only for network failures (timeout, DNS error, dropped connection)
print('Request failed:', error)
else:
if 'error' in result:
# The Delivery API rejected the request and returned the error body
print('Delivery API error:', result['error'])
else:
for entry in result.get('entries', []):
print(entry.get('title'))All parameters: the single field UID argument, with pagination
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
sort_field = 'title'
try:
# key passed directly to order_by_ascending, so the two pages line up.
result = stack.content_type('blog_post').query() \
.order_by_ascending(sort_field) \
.skip(10) \
.limit(10) \
.find()
print('returned', len(result.get('entries', [])), 'entries')
except Exception as error:
print('Request failed:', error)Edge case: two sorts on one query
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
# Both asc and desc reach the API, and the SDK does not choose between them.
ambiguous = stack.content_type('blog_post').query() \
.order_by_ascending('title') \
.order_by_descending('price') \
.find()
# Chain one sort instead.
sorted_by_title = stack.content_type('blog_post').query() \
.order_by_ascending('title') \
.find()
except Exception as error:
print('Request failed:', error)order_by_descending
order_by_descending sorts the entries by one field, highest value first.
| Name | Type | Description |
|---|---|---|
| key (required) | str | Field UID the sort applies to. |
The same query, for chaining.
Validation
- There is no client-side validation. order_by_descending converts the argument to a string and sends an unknown field UID or an empty string as given.
- Passing None sends the literal text desc=None, because the conversion happens without a null check. Guard the value before you chain the call.
- Omitting the argument raises TypeError immediately, because key is a positional parameter with no default.
- Errors that do occur come from the find() call that follows, not from order_by_descending().
- find() raises an exception only for network failures (timeout, DNS error, dropped connection).
- An API-level rejection (for example, a field the API cannot sort on) returns as a normal result with an error key. It does not raise an exception.
- Check the result for an error key even inside a try block.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. order_by_descending records the desc query parameter and makes no request. find sends the value on that call.
- Sorts on one field. Calling it twice replaces the first field name, because the SDK records it under a single key.
- Chaining order_by_ascending as well sends both asc and desc. The SDK writes each under its own key and does not reconcile them, so chain one or the other.
- Use it with a date field to put the newest entries first, which is the common pairing with find_one for a single latest record.
Example
Basic usage: newest entries first
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
result = stack.content_type('blog_post').query() \
.order_by_descending('published_at') \
.find()
except Exception as error:
# Raised only for network failures (timeout, DNS error, dropped connection)
print('Request failed:', error)
else:
if 'error' in result:
# The Delivery API rejected the request and returned the error body
print('Delivery API error:', result['error'])
else:
for entry in result.get('entries', []):
print(entry.get('published_at'), entry.get('title'))All parameters: the single field UID argument, with a page size
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
sort_field = 'published_at'
try:
# key passed directly to order_by_descending.
result = stack.content_type('blog_post').query() \
.order_by_descending(sort_field) \
.limit(5) \
.find()
print('returned', len(result.get('entries', [])), 'entries')
except Exception as error:
print('Request failed:', error)Combined usage: the single most recent entry
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
result = stack.content_type('blog_post').query() \
.order_by_descending('published_at') \
.find_one()
entries = result.get('entries', [])
print(entries[0]['title'] if entries else 'no entries')
except Exception as error:
print('Request failed:', error)param
param adds one arbitrary URL query parameter to the request.
| Name | Type | Description |
|---|---|---|
| key (required) | str | Query parameter name to send. |
| value (required) | Any | Value for that query parameter. |
The same query, for chaining.
Validation
- Passing None as either argument raises KeyError. A null key or value would produce a malformed query string. The message is "Invalid key. Provide a valid key and try again." for the key and "Invalid value. Provide a valid value and try again." for the value.
- The raise happens on the call itself, not on the terminal call that follows. Wrap param in its own try when the key or value comes from user input.
- An empty string passes the check. None is the only rejected value, so param('', '') records a parameter with no name.
- Omitting either argument raises TypeError immediately, because both are positional parameters with no default.
- Any remaining errors come from the find() call that follows, not from param().
- find() raises an exception only for network failures (timeout, DNS error, dropped connection).
- An API-level rejection (for example, a parameter name the API does not recognize) returns as a normal result with an error key. It does not raise an exception.
- Check the result for an error key even inside a try block.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. param records the pair in the URL query parameters and makes no request.
- Converts value to a string before recording it, so a list arrives as the Python text of that list. Use add_param or add_params when the value has to stay a list.
- Shares one namespace with the dedicated modifiers. param('limit', 5) and limit(5) write the same place, so whichever call comes last wins.
- Loses to the entry option store. A key that locale, only, or add_param wrote overwrites the same key here when find assembles the request. See Three stores on the Query class page.
- The SDK encodes the parameters before sending them, so a value containing a space or an ampersand needs no encoding from you.
- Use param to reach a Delivery API query parameter the SDK exposes no method for, including the query parameter itself when a reference condition needs the JSON form. Prefer the dedicated method when one exists, because it documents the intent.
Example
Basic usage: send a query parameter the SDK has no method for
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
result = stack.content_type('blog_post').query() \
.param('include_publish_details', 'true') \
.find()
except Exception as error:
# Raised only for network failures (timeout, DNS error, dropped connection)
print('Request failed:', error)
else:
if 'error' in result:
# The Delivery API rejected the request and returned the error body
print('Delivery API error:', result['error'])
else:
print('entries:', len(result.get('entries', [])))All parameters: both arguments, with a numeric value
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
# key and value both passed to param. The value becomes the text "5".
result = stack.content_type('blog_post').query().param('limit', 5).find()
print('returned', len(result.get('entries', [])), 'entries')
except Exception as error:
print('Request failed:', error)Error handling: a null key raises at the call site
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
user_supplied_key = None
try:
result = stack.content_type('blog_post').query() \
.param(user_supplied_key, 'true') \
.find()
except KeyError as error:
# Fires on param itself, before any request goes out.
print('Invalid query parameter:', error)Edge case: a dedicated method and param collide
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
# Both write the limit key, so the later call wins and this sends limit=5.
result = stack.content_type('blog_post').query().limit(10).param('limit', 5).find()
except Exception as error:
print('Request failed:', error)query
query adds one raw key and value to the condition object the request carries.
| Name | Type | Description |
|---|---|---|
| key (required) | str | Field UID or operator name for the condition. |
| value (required) | Any | Value the SDK converts to a string and stores. |
The same query, for chaining.
Validation
- Passing None as either argument raises KeyError. A null key gives the condition no name, and a null value gives it nothing to compare against. The message is "Invalid key. Provide a valid key and try again." for the key and "Invalid value. Provide a valid value and try again." for the value.
- The raise happens on the call itself, not on the terminal call that follows. Wrap query in its own try when the key or value comes from user input.
- An empty string passes the check. None is the only rejected value, so query('', '') records a condition with no field name.
- Omitting either argument raises TypeError immediately, because both are positional parameters with no default.
- Any remaining errors come from the find() call that follows, not from query().
- find() raises an exception only for network failures (timeout, DNS error, dropped connection).
- An API-level rejection (for example, a condition the API cannot parse) returns as a normal result with an error key. It does not raise an exception.
- Check the result for an error key even inside a try block.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. query records the pair and makes no request. find serializes the whole condition object into the query parameter on that call.
- Converts value to a string before recording it. A nested operator dictionary therefore arrives at the API as the Python text of that dictionary rather than as JSON. Pass string and number values only, and use where for operator conditions.
- Writes the same condition object as where, keyed the same way, so a query call and a where call on one field UID overwrite each other.
- Do not confuse this method with the query() factory on ContentType. stack.content_type('<CONTENT_TYPE_UID>').query() takes no arguments and creates the query. This method takes two arguments and adds a condition to a query that already exists.
- Use query to send a condition key the SDK exposes no operator for. Prefer where when a QueryOperation member covers the comparison, because the enum documents the intent.
Example
Basic usage: match entries on a field the operators do not cover
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
result = stack.content_type('blog_post').query() \
.query('category', 'release_notes') \
.find()
except Exception as error:
# Raised only for network failures (timeout, DNS error, dropped connection)
print('Request failed:', error)
else:
if 'error' in result:
# The Delivery API rejected the request and returned the error body
print('Delivery API error:', result['error'])
else:
for entry in result.get('entries', []):
print(entry['title'])All parameters: both arguments, alongside a chained operator condition
import contentstack
from contentstack.basequery import QueryOperation
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
# key and value both passed to query, on a different field from where.
result = stack.content_type('blog_post').query() \
.query('category', 'release_notes') \
.where('price', QueryOperation.IS_LESS_THAN, fields=90) \
.find()
print('matches:', len(result.get('entries', [])))
except Exception as error:
print('Request failed:', error)Error handling: a null value raises at the call site
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
user_supplied_value = None
try:
result = stack.content_type('blog_post').query() \
.query('category', user_supplied_value) \
.find()
except KeyError as error:
# Fires on query itself, before any request goes out.
print('Invalid condition:', error)Edge case: an operator dictionary does not survive the conversion
import contentstack
from contentstack.basequery import QueryOperation
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
query = stack.content_type('blog_post').query()
try:
# Wrong. The dictionary becomes the text "{'$lt': 90}" and the API cannot read it.
broken = query.query('price', {'$lt': 90})
# Correct. where writes the operator as JSON.
fixed = stack.content_type('blog_post').query() \
.where('price', QueryOperation.IS_LESS_THAN, fields=90) \
.find()
except Exception as error:
print('Request failed:', error)query_operator
query_operator combines the conditions of other queries under a single $and or $or operator.
| Name | Type | Description |
|---|---|---|
| query_type (required) | QueryType | Operator that joins the conditions, AND or OR. |
| query_objects (required) | Query | Queries whose conditions to combine, passed as separate arguments. |
The same query, for chaining.
Validation
- There is no client-side validation. query_operator reads the conditions off each query it receives and records them as given.
- Passing anything other than a QueryType member as query_type raises AttributeError, because query_operator reads the operator string off the enum member.
- Passing anything without a condition object, such as a plain string or a Stack, raises AttributeError on that argument.
- Passing no queries is valid and records an empty operator, so query_operator(QueryType.AND) sends {"$and": []} and matches nothing useful. Guard the list before you spread it into the call.
- Omitting query_type raises TypeError immediately, because it is a positional parameter with no default.
- Errors that do occur come from the find() call that follows, not from query_operator().
- find() raises an exception only for network failures (timeout, DNS error, dropped connection).
- An API-level rejection (for example, an operator condition the API cannot parse) returns as a normal result with an error key. It does not raise an exception.
- Check the result for an error key even inside a try block.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. query_operator records the combined condition and makes no request.
- Import the operator enum from the query module, with from contentstack.query import QueryType. QueryType.AND sends $and and QueryType.OR sends $or.
- Reads only the condition object of each query it receives, so the conditions those queries hold come from their own where and query calls. A pagination or field modifier chained on a sub-query never reaches the request.
- Ignores the content type of each sub-query. Only this query's content type decides which entries the request reads, so building the sub-queries from the same content type keeps the code honest.
- Empties this query's own condition object before recording the operator. A where call chained before query_operator therefore disappears, and a where call chained after it replaces the whole operator condition. See One condition survives on the Query class page.
- Calling query_operator twice replaces the first operator condition. The SDK records it under a single key.
Example
Basic usage: match entries satisfying either of two conditions
import contentstack
from contentstack.query import QueryType
from contentstack.basequery import QueryOperation
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
content_type = stack.content_type('blog_post')
cheap = content_type.query().where('price', QueryOperation.IS_LESS_THAN, fields=90)
discounted = content_type.query().where('discount', QueryOperation.INCLUDES, fields=[20, 45])
try:
result = content_type.query().query_operator(QueryType.OR, cheap, discounted).find()
except Exception as error:
# Raised only for network failures (timeout, DNS error, dropped connection)
print('Request failed:', error)
else:
if 'error' in result:
# The Delivery API rejected the request and returned the error body
print('Delivery API error:', result['error'])
else:
for entry in result.get('entries', []):
print(entry['title'])All parameters: the operator plus three queries as separate arguments
import contentstack
from contentstack.query import QueryType
from contentstack.basequery import QueryOperation
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
content_type = stack.content_type('blog_post')
in_stock = content_type.query().where('in_stock', QueryOperation.EQUALS, fields=True)
under_ninety = content_type.query().where('price', QueryOperation.IS_LESS_THAN, fields=90)
named = content_type.query().where('title', QueryOperation.MATCHES, fields='^Release')
try:
# query_type plus three query_objects, all passed to query_operator.
result = content_type.query() \
.query_operator(QueryType.AND, in_stock, under_ninety, named) \
.find()
print('matches:', len(result.get('entries', [])))
except Exception as error:
print('Request failed:', error)Error handling: a missing operator raises at the call site
import contentstack
from contentstack.basequery import QueryOperation
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
content_type = stack.content_type('blog_post')
cheap = content_type.query().where('price', QueryOperation.IS_LESS_THAN, fields=90)
try:
# Wrong. The first argument has to be a QueryType member, not a query.
result = content_type.query().query_operator(cheap).find()
except AttributeError as error:
# Fires on query_operator itself, before any request goes out.
print('Pass QueryType.AND or QueryType.OR first:', error)Edge case: a chained where replaces the operator condition
import contentstack
from contentstack.query import QueryType
from contentstack.basequery import QueryOperation
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
content_type = stack.content_type('blog_post')
cheap = content_type.query().where('price', QueryOperation.IS_LESS_THAN, fields=90)
try:
# Only the title condition reaches the API. The $or condition is gone.
result = content_type.query() \
.query_operator(QueryType.OR, cheap) \
.where('title', QueryOperation.MATCHES, fields='^Release') \
.find()
except Exception as error:
print('Request failed:', error)remove_param
remove_param deletes one URL query parameter from the request.
| Name | Type | Description |
|---|---|---|
| key (required) | str | Query parameter name to delete. |
The same query, for chaining.
Validation
- Passing None raises ValueError with the message "Invalid key. Provide a valid key and try again." A null key names no parameter, so there is nothing to delete.
- The raise happens on the call itself, not on the terminal call that follows. Wrap remove_param in its own try when the key comes from user input.
- A key the query does not hold is not an error. remove_param checks before deleting and returns the query unchanged.
- Omitting the argument raises TypeError immediately, because key is a positional parameter with no default.
- Any remaining errors come from the find() call that follows, not from remove_param().
- find() raises an exception only for network failures (timeout, DNS error, dropped connection).
- An API-level rejection returns as a normal result with an error key. It does not raise an exception.
- Check the result for an error key even inside a try block.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. remove_param deletes from the URL query parameters and makes no request.
- Reaches the URL query parameters only. It cannot delete a condition that where or query recorded, and it cannot delete an entry option that locale, only, or add_param recorded. See Three stores on the Query class page.
- Removing a value that the entry option store also holds looks successful and changes nothing, because find copies that store over the URL query parameters afterwards.
- Useful on a reused query instance. The SDK never clears the query between find calls, so remove_param is the way to drop a parameter an earlier call recorded.
Limitations
- Does not reset the query. Build a fresh query with stack.content_type('<CONTENT_TYPE_UID>').query() when you want an empty starting point.
- Does not remove a locale or a field selection. Those live in the entry option store.
Example
Basic usage: drop a parameter from a reused query
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
query = stack.content_type('blog_post').query().limit(10).include_count()
try:
result = query.remove_param('include_count').find()
except Exception as error:
# Raised only for network failures (timeout, DNS error, dropped connection)
print('Request failed:', error)
else:
if 'error' in result:
# The Delivery API rejected the request and returned the error body
print('Delivery API error:', result['error'])
else:
# The count key is absent, because the flag no longer reaches the API.
print('count present:', 'count' in result)All parameters: the single key argument, chosen at runtime
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
parameter_name = 'limit'
try:
# key passed directly to remove_param.
result = stack.content_type('blog_post').query() \
.limit(10) \
.remove_param(parameter_name) \
.find()
print('returned', len(result.get('entries', [])), 'entries')
except Exception as error:
print('Request failed:', error)Error handling: a null key raises at the call site
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
parameter_name = None
try:
result = stack.content_type('blog_post').query() \
.limit(10) \
.remove_param(parameter_name) \
.find()
except ValueError as error:
# Fires on remove_param itself, before any request goes out.
print('Name the parameter to delete:', error)Edge case: a locale survives the removal
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
# locale=fr-fr still reaches the API. locale writes the entry option store.
result = stack.content_type('blog_post').query() \
.locale('fr-fr') \
.remove_param('locale') \
.find()
except Exception as error:
print('Request failed:', error)search
search matches entries against a free-text value.
| Name | Type | Description |
|---|---|---|
| value (required) | str | Free-text value to match entries against. |
The same query, for chaining.
Validation
- There is no client-side validation of the value. search records an empty string or a value of the wrong type as given.
- Passing None makes search a no-op for the parameter. It still raises the deprecation warning, records nothing, and returns the query.
- Omitting the argument raises TypeError immediately, because value is a positional parameter with no default.
- The UserWarning is a warning, not an exception, so it does not stop the call. Run Python with -W error::UserWarning to turn it into a failure while you migrate away from this method.
- Errors that do occur come from the find() call that follows, not from search().
- find() raises an exception only for network failures (timeout, DNS error, dropped connection).
- An API-level rejection returns as a normal result with an error key. It does not raise an exception.
- Check the result for an error key even inside a try block.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. search records the typeahead query parameter and makes no request. find sends the value on that call.
- Searches across the entry rather than one named field, which is what makes where with QueryOperation.MATCHES the narrower replacement.
- Calling search twice replaces the first value. The SDK records it under a single key.
- Writes a URL query parameter rather than a condition, so it survives alongside a where condition instead of competing with it.
Limitations
- Does not restrict the search to one field. Use the where method with QueryOperation.MATCHES when you know which field to match.
Example
Basic usage: free-text search across a content type
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
result = stack.content_type('blog_post').query().search('release notes').find()
except Exception as error:
# Raised only for network failures (timeout, DNS error, dropped connection)
print('Request failed:', error)
else:
if 'error' in result:
# The Delivery API rejected the request and returned the error body
print('Delivery API error:', result['error'])
else:
for entry in result.get('entries', []):
print(entry['title'])All parameters: the single value argument, with the warning suppressed
import warnings
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
with warnings.catch_warnings():
warnings.simplefilter('ignore', UserWarning)
result = stack.content_type('blog_post').query().search('release notes').find()
print('matches:', len(result.get('entries', [])))
except Exception as error:
print('Request failed:', error)Migration: the supported replacement for a pattern match
import contentstack
from contentstack.basequery import QueryOperation
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
# Matches the title field only, and raises no deprecation warning.
result = stack.content_type('blog_post').query() \
.where('title', QueryOperation.MATCHES, fields='^Release') \
.find()
except Exception as error:
print('Request failed:', error)Edge case: a null value warns but sends nothing
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
user_input = None
try:
# The deprecation warning still fires. No typeahead parameter reaches the API.
result = stack.content_type('blog_post').query().search(user_input).find()
print('returned', len(result.get('entries', [])), 'entries')
except Exception as error:
print('Request failed:', error)skip
skip sets the offset, so the response starts after a number of entries.
| Name | Type | Description |
|---|---|---|
| skip_count (required) | int | Number of entries to skip before the first result. |
The same query, for chaining.
Validation
- There is no client-side validation. skip converts the argument to a string and sends a negative number or a non-integer as given.
- Passing None sends the literal text skip=None, because the conversion happens without a null check. Guard the value before you chain the call.
- Omitting the argument raises TypeError immediately, because skip_count is a positional parameter with no default.
- Errors that do occur come from the find() call that follows, not from skip().
- find() raises an exception only for network failures (timeout, DNS error, dropped connection).
- An API-level rejection (for example, a negative offset) returns as a normal result with an error key. It does not raise an exception.
- Check the result for an error key even inside a try block.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. skip records the skip query parameter and makes no request. find sends the value on that call.
- Omitting skip leaves the parameter off the request. The SDK sets no default, so the API starts from the first entry.
- Calling skip twice replaces the first value. The SDK records it under a single key, so compute the offset yourself rather than calling skip once per page.
- Needs a page size to be useful. Chain limit as well, or the page size stays at whatever the API applies and the offsets stop lining up.
- Depends on a stable order. Chain order_by_ascending or order_by_descending so that two pages read minutes apart do not repeat or drop an entry.
Example
Basic usage: read the second page of a listing
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
result = stack.content_type('blog_post').query().skip(10).limit(10).find()
except Exception as error:
# Raised only for network failures (timeout, DNS error, dropped connection)
print('Request failed:', error)
else:
if 'error' in result:
# The Delivery API rejected the request and returned the error body
print('Delivery API error:', result['error'])
else:
print('returned', len(result.get('entries', [])), 'entries')All parameters: the single offset argument, computed per page
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
page_size = 10
page_number = 3
try:
# skip_count passed directly to skip.
result = stack.content_type('blog_post').query() \
.order_by_ascending('title') \
.skip(page_size * (page_number - 1)) \
.limit(page_size) \
.include_count() \
.find()
print('total entries:', result.get('count'))
except Exception as error:
print('Request failed:', error)Edge case: paginate to the end of the result
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
page_size = 10
offset = 0
collected = []
try:
while True:
result = stack.content_type('blog_post').query() \
.order_by_ascending('title') \
.skip(offset) \
.limit(page_size) \
.find()
page = result.get('entries', [])
collected.extend(page)
if len(page) < page_size:
break
offset += page_size
except Exception as error:
print('Request failed:', error)tags
tags matches entries carrying the tags you name.
| Name | Type | Description |
|---|---|---|
| tags (required) | str | Tag to match, passed as separate arguments. |
The same query, for chaining.
Validation
- There is no client-side validation of the tag names. tags records an unknown tag or an empty string as given.
- Calling tags() with no arguments records an empty value, so find sends tags= and the API filters on an empty tag list. Guard the list before you spread it into the call.
- Passing a value that is not a string, such as an integer or a list, raises TypeError, because tags joins the arguments into one comma-separated string.
- Errors that do occur come from the find() call that follows, not from tags().
- find() raises an exception only for network failures (timeout, DNS error, dropped connection).
- An API-level rejection returns as a normal result with an error key. It does not raise an exception.
- Check the result for an error key even inside a try block.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. tags records the tags query parameter and makes no request. find sends the value on that call.
- Joins the arguments with commas into a single tags parameter, so tags('black', 'gold') sends tags=black,gold.
- Calling tags twice replaces the first set. The SDK records it under a single key, so pass every tag in one call.
- Spread a list with the asterisk operator when the tags come from a variable, as in query.tags(*tag_list).
- Filters on the entry's own tags, which are separate from taxonomy terms. Use the Taxonomy class to filter entries by taxonomy term instead.
Example
Basic usage: match entries carrying any of three tags
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
result = stack.content_type('blog_post').query() \
.tags('black', 'gold', 'silver') \
.find()
except Exception as error:
# Raised only for network failures (timeout, DNS error, dropped connection)
print('Request failed:', error)
else:
if 'error' in result:
# The Delivery API rejected the request and returned the error body
print('Delivery API error:', result['error'])
else:
for entry in result.get('entries', []):
print(entry['title'], entry.get('tags'))All parameters: a variable number of tags spread from a list
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
tag_list = ['black', 'gold']
try:
# Every positional tag argument comes from one spread list.
result = stack.content_type('blog_post').query().tags(*tag_list).find()
print('matches:', len(result.get('entries', [])))
except Exception as error:
print('Request failed:', error)Edge case: an empty list sends an empty tag filter
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
tag_list = []
try:
# Guard the list. Without the check this sends tags= and filters on nothing.
query = stack.content_type('blog_post').query()
if tag_list:
query = query.tags(*tag_list)
result = query.find()
except Exception as error:
print('Request failed:', error)where
where adds a condition on one field to the query.
| Name | Type | Description |
|---|---|---|
| field_uid (required) | str | Field UID the condition applies to. |
| query_operation (required) | QueryOperation | Comparison operator for the condition. |
| fields | Any | Value or list of values to compare against. |
The same query, for chaining.
Validation
- There is no client-side validation of the field or the value. where stores an unknown field UID, an empty string, or a value of the wrong type as given.
- Passing None for either field_uid or query_operation makes where a no-op. It records nothing and returns the query, so the condition disappears without any error.
- Passing anything other than a QueryOperation member as query_operation raises AttributeError, because where reads the operator name and value off the enum member.
- Omitting field_uid or query_operation raises TypeError immediately, because both are positional parameters with no default.
- Errors that do occur come from the find() call that follows, not from where().
- find() raises an exception only for network failures (timeout, DNS error, dropped connection).
- An API-level rejection (for example, a regular expression the API cannot compile) returns as a normal result with an error key. It does not raise an exception.
- Check the result for an error key even inside a try block.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. where records the condition and makes no request. find serializes the whole condition object into the query parameter on that call.
- Import the operator enum from the same module as the query, with from contentstack.basequery import QueryOperation. The ten members map onto the Delivery API operators as follows.
| Member | Sends | Matches |
| --- | --- | --- |
| EQUALS | the bare value | a field equal to the value |
| NOT_EQUALS | $ne | a field different from the value |
| INCLUDES | $in | a field equal to any value in the list |
| EXCLUDES | $nin | a field equal to none of the values in the list |
| IS_LESS_THAN | $lt | a field below the value |
| IS_LESS_THAN_OR_EQUAL | $lte | a field at or below the value |
| IS_GREATER_THAN | $gt | a field above the value |
| IS_GREATER_THAN_OR_EQUAL | $gte | a field at or above the value |
| EXISTS | $exists | a field present or absent, per the boolean value |
| MATCHES | $regex | a field matching the regular expression |
- EQUALS behaves differently from the other nine. It writes the value straight onto the field UID with no operator wrapper. A single-element list also collapses to its one element, so fields=['red'] and fields='red' produce the same condition.
- Calling where twice on the same field UID replaces the first condition. The SDK keys the condition object on the field UID.
- where and query write the same condition object, so they combine freely across different keys.
- A where condition wins over where_in, where_not_in, and query_operator. See One condition survives on the Query class page.
Limitations
- Does not express two conditions on one field. Use the query_operator method with QueryType.AND to combine separate queries instead.
Example
Basic usage: match entries by an exact field value
import contentstack
from contentstack.basequery import QueryOperation
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
result = stack.content_type('blog_post').query() \
.where('category', QueryOperation.EQUALS, fields='release_notes') \
.find()
except Exception as error:
# Raised only for network failures (timeout, DNS error, dropped connection)
print('Request failed:', error)
else:
if 'error' in result:
# The Delivery API rejected the request and returned the error body
print('Delivery API error:', result['error'])
else:
for entry in result.get('entries', []):
print(entry['title'])All parameters: a field UID, an operator, and a list of values
import contentstack
from contentstack.basequery import QueryOperation
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
# field_uid, query_operation, and fields all passed to where.
result = stack.content_type('blog_post').query() \
.where('category', QueryOperation.INCLUDES, fields=['release_notes', 'tutorials']) \
.find()
print('matches:', len(result.get('entries', [])))
except Exception as error:
print('Request failed:', error)Combining fields: two conditions on two different fields
import contentstack
from contentstack.basequery import QueryOperation
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
result = stack.content_type('blog_post').query() \
.where('price', QueryOperation.IS_LESS_THAN, fields=90) \
.where('title', QueryOperation.MATCHES, fields='^Release') \
.find()
except Exception as error:
print('Request failed:', error)Edge case: a null operator drops the condition silently
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
operator = None
try:
# No exception here. The condition is absent and find returns every entry.
result = stack.content_type('blog_post').query() \
.where('price', operator, fields=90) \
.find()
print('returned', len(result.get('entries', [])), 'entries')
except Exception as error:
print('Request failed:', error)where_in
where_in matches entries whose referenced entries satisfy the conditions of another query.
| Name | Type | Description |
|---|---|---|
| key (required) | str | Reference field UID the condition applies to. |
| query_object (required) | Query | Query the referenced entries must satisfy. |
The same query, for chaining.
Validation
- where_in rejects its own arguments. It raises ValueError when key is not a string or query_object is not a Query. Neither a null field name nor a foreign object can produce a reference condition. The message is "Invalid key or value. Provide valid values and try again."
- The raise happens on the call itself, not on the terminal call that follows. Wrap where_in in its own try when the field name comes from user input.
- An empty string passes the check, because the guard tests the type rather than the content. where_in('', other_query) records a condition with no field name.
- Omitting either argument raises TypeError immediately, because both are positional parameters with no default.
- Any remaining errors come from the find() call that follows, not from where_in().
- find() raises an exception only for network failures (timeout, DNS error, dropped connection).
- An API-level rejection (for example, a field that is not a reference field) returns as a normal result with an error key. It does not raise an exception.
- Check the result for an error key even inside a try block.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. where_in records the condition and makes no request.
- Records the condition as {key: {"$in_query": <conditions of query_object>}} under the query URL parameter, not in the condition object that where writes.
- Reads only the condition object of query_object, so the conditions come from that query's own where and query calls. A pagination or field modifier chained on it never reaches the request.
- Loses the condition on the way out, because the recorded value is a Python dictionary rather than a JSON string. See the Warning on the Query class page for the encoding detail and the working alternative.
- Yields to where and query. A condition from either of those replaces this one when find assembles the request. See One condition survives on the Query class page.
- Calling where_in twice replaces the first condition, and so does a where_not_in call, because both write the same query key.
Limitations
- Does not send a usable condition as written. Build the reference condition yourself and pass it through the param method, as the second example shows.
Example
Basic usage: match entries whose reference satisfies another query
import contentstack
from contentstack.basequery import QueryOperation
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
brands = stack.content_type('brand').query() \
.where('title', QueryOperation.EQUALS, fields='Acme')
try:
result = stack.content_type('blog_post').query() \
.where_in('brand', brands) \
.find()
except Exception as error:
# Raised only for network failures (timeout, DNS error, dropped connection)
print('Request failed:', error)
else:
if 'error' in result:
# The Delivery API rejected the request and returned the error body
print('Delivery API error:', result['error'])
else:
for entry in result.get('entries', []):
print(entry['title'])All parameters: both arguments, with the condition sent as JSON instead
import json
import contentstack
from contentstack.basequery import QueryOperation
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
brands = stack.content_type('brand').query() \
.where('title', QueryOperation.EQUALS, fields='Acme')
try:
# key and query_object both passed to where_in, then param sends the JSON form.
result = stack.content_type('blog_post').query() \
.where_in('brand', brands) \
.param('query', json.dumps({'brand': {'$in_query': {'title': 'Acme'}}})) \
.find()
print('matches:', len(result.get('entries', [])))
except Exception as error:
print('Request failed:', error)Error handling: a non-query second argument raises at the call site
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
try:
result = stack.content_type('blog_post').query() \
.where_in('brand', 'Acme') \
.find()
except ValueError as error:
# Fires on where_in itself, before any request goes out.
print('Pass a Query as the second argument:', error)Edge case: a chained where replaces the reference condition
import contentstack
from contentstack.basequery import QueryOperation
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
brands = stack.content_type('brand').query() \
.where('title', QueryOperation.EQUALS, fields='Acme')
try:
# Only the price condition reaches the API. The reference condition is gone.
result = stack.content_type('blog_post').query() \
.where_in('brand', brands) \
.where('price', QueryOperation.IS_LESS_THAN, fields=90) \
.find()
except Exception as error:
print('Request failed:', error)where_not_in
where_not_in matches entries whose referenced entries fail the conditions of another query.
| Name | Type | Description |
|---|---|---|
| key (required) | str | Reference field UID the condition applies to. |
| query_object (required) | Query | Query the referenced entries must fail. |
The same query, for chaining.
Validation
- where_not_in rejects its own arguments. It raises ValueError when key is not a string or query_object is not a Query. Neither a null field name nor a foreign object can produce a reference condition. The message is "Invalid key or value. Provide valid values and try again."
- The raise happens on the call itself, not on the terminal call that follows. Wrap where_not_in in its own try when the field name comes from user input.
- An empty string passes the check, because the guard tests the type rather than the content. where_not_in('', other_query) records a condition with no field name.
- Omitting either argument raises TypeError immediately, because both are positional parameters with no default.
- Any remaining errors come from the find() call that follows, not from where_not_in().
- find() raises an exception only for network failures (timeout, DNS error, dropped connection).
- An API-level rejection (for example, a field that is not a reference field) returns as a normal result with an error key. It does not raise an exception.
- Check the result for an error key even inside a try block.
Additional Resource Refer to Delivery API Errors for the full error code list.
Behavior
- Client-side only. where_not_in records the condition and makes no request.
- Records the condition as {key: {"$nin_query": <conditions of query_object>}} under the query URL parameter, not in the condition object that where writes. This is the inverse of where_in and matches the entries that method excludes.
- Reads only the condition object of query_object, so the conditions come from that query's own where and query calls. A pagination or field modifier chained on it never reaches the request.
- Loses the condition on the way out, because the recorded value is a Python dictionary rather than a JSON string. See the Warning on the Query class page for the encoding detail and the working alternative.
- Yields to where and query. A condition from either of those replaces this one when find assembles the request. See One condition survives on the Query class page.
- Calling where_not_in twice replaces the first condition, and so does a where_in call, because both write the same query key.
Limitations
- Does not send a usable condition as written. Build the reference condition yourself and pass it through the param method, as the second example shows.
Example
Basic usage: exclude entries whose reference satisfies another query
import contentstack
from contentstack.basequery import QueryOperation
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
brands = stack.content_type('brand').query() \
.where('title', QueryOperation.EQUALS, fields='Acme')
try:
result = stack.content_type('blog_post').query() \
.where_not_in('brand', brands) \
.find()
except Exception as error:
# Raised only for network failures (timeout, DNS error, dropped connection)
print('Request failed:', error)
else:
if 'error' in result:
# The Delivery API rejected the request and returned the error body
print('Delivery API error:', result['error'])
else:
for entry in result.get('entries', []):
print(entry['title'])All parameters: both arguments, with the condition sent as JSON instead
import json
import contentstack
from contentstack.basequery import QueryOperation
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
brands = stack.content_type('brand').query() \
.where('title', QueryOperation.EQUALS, fields='Acme')
try:
# key and query_object both passed to where_not_in, then param sends the JSON form.
result = stack.content_type('blog_post').query() \
.where_not_in('brand', brands) \
.param('query', json.dumps({'brand': {'$nin_query': {'title': 'Acme'}}})) \
.find()
print('matches:', len(result.get('entries', [])))
except Exception as error:
print('Request failed:', error)Error handling: a null second argument raises at the call site
import contentstack
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
excluded_brands = None
try:
result = stack.content_type('blog_post').query() \
.where_not_in('brand', excluded_brands) \
.find()
except ValueError as error:
# Fires on where_not_in itself, before any request goes out.
print('Pass a Query as the second argument:', error)Edge case: where_in and where_not_in overwrite each other
import contentstack
from contentstack.basequery import QueryOperation
stack = contentstack.Stack('<API_KEY>', '<DELIVERY_TOKEN>', '<ENVIRONMENT>')
acme = stack.content_type('brand').query() \
.where('title', QueryOperation.EQUALS, fields='Acme')
globex = stack.content_type('brand').query() \
.where('title', QueryOperation.EQUALS, fields='Globex')
try:
# Only the last call survives. Both write the same query key.
result = stack.content_type('blog_post').query() \
.where_in('brand', acme) \
.where_not_in('brand', globex) \
.find()
except Exception as error:
print('Request failed:', error)