TicketQuery Wiki Macro

The TicketQuery macro lets you display ticket information anywhere that accepts WikiFormatting. The query language used by the [[TicketQuery]] macro is described in the TracQuery page.

Usage

[[TicketQuery]]

Wiki macro listing tickets that match certain criteria.

This macro accepts a comma-separated list of keyed parameters, in the form "key=value".

If the key is the name of a field, the value must use the syntax of a filter specifier as defined in TracQuery#QueryLanguage. Note that this is not the same as the simplified URL syntax used for query: links starting with a ? character. Commas (,) can be included in field values by escaping them with a backslash (\).

Groups of field constraints to be OR-ed together can be separated by a literal or argument.

In addition to filters, several other named parameters can be used to control how the results are presented. All of them are optional.

The format parameter determines how the list of tickets is presented:

  • list -- the default presentation is to list the ticket ID next to the summary, with each ticket on a separate line.
  • compact -- the tickets are presented as a comma-separated list of ticket IDs.
  • count -- only the count of matching tickets is displayed
  • rawcount -- only the count of matching tickets is displayed, not even with a link to the corresponding query (since 1.1.1)
  • table -- a view similar to the custom query view (but without the controls)
  • progress -- a view similar to the milestone progress bars

The max parameter can be used to limit the number of tickets shown (defaults to 0, i.e. no maximum).

The order parameter sets the field used for ordering tickets (defaults to id).

The desc parameter indicates whether the order of the tickets should be reversed (defaults to false).

The group parameter sets the field used for grouping tickets (defaults to not being set).

The groupdesc parameter indicates whether the natural display order of the groups should be reversed (defaults to false).

The verbose parameter can be set to a true value in order to get the description for the listed tickets. For table format only. deprecated in favor of the rows parameter

The rows parameter can be used to specify which field(s) should be viewed as a row, e.g. rows=description|summary

The col parameter can be used to specify which fields should be viewed as columns. For table format only.

For compatibility with Trac 0.10, if there's a last positional parameter given to the macro, it will be used to specify the format. Also, using "&" as a field separator still works (except for order) but is deprecated.

Examples

Example Result Macro
Number of Triage tickets: 592 [[TicketQuery(status=new&milestone=,count)]]
Number of new tickets: 592 [[TicketQuery(status=new,count)]]
Number of reopened tickets: 0 [[TicketQuery(status=reopened,count)]]
Number of assigned tickets: 468 [[TicketQuery(status=assigned,count)]]
Number of invalid tickets: 5276 [[TicketQuery(status=closed,resolution=invalid,count)]]
Number of worksforme tickets: 1086 [[TicketQuery(status=closed,resolution=worksforme,count)]]
Number of duplicate tickets: 4403 [[TicketQuery(status=closed,resolution=duplicate,count)]]
Number of wontfix tickets: 4230 [[TicketQuery(status=closed,resolution=wontfix,count)]]
Number of fixed tickets: 18992 [[TicketQuery(status=closed,resolution=fixed,count)]]
Number of untriaged tickets (milestone unset): 1060 [[TicketQuery(status!=closed,milestone=,count)]]
Total number of tickets: 36039 [[TicketQuery(count)]]
Number of tickets reported or owned by current user: 1488 [[TicketQuery(reporter=$USER,or,owner=$USER,count)]]
Number of tickets created this month: 67 [[TicketQuery(created=thismonth..,count)]]
Number of closed Firefox tickets: 8 [[TicketQuery(status=closed,keywords~=firefox,count)]]
Number of closed Opera tickets: 25 [[TicketQuery(status=closed,keywords~=opera,count)]]
Number of closed tickets affecting Firefox and Opera: 0 [[TicketQuery(status=closed,keywords~=firefox opera,count)]]
Number of closed tickets affecting Firefox or Opera: 33 [[TicketQuery(status=closed,keywords~=firefox|opera,count)]]
Number of tickets that affect Firefox or are closed and affect Opera: 33 [[TicketQuery(status=closed,keywords~=opera,or,keywords~=firefox,count)]]
Number of closed Firefox tickets that don't affect Opera: 0 [[TicketQuery(status=closed,keywords~=firefox -opera,count)]]
Last 3 modified tickets: #36821, #36639, #36796 [[TicketQuery(max=3,order=modified,desc=1,compact)]]

Details of ticket #1:

[[TicketQuery(id=1,col=id|owner|reporter,rows=summary,table)]]

Ticket Owner Reporter
#1 Jacob Adrian Holovaty
Summary Create architecture for anonymous sessions

Format: list

[[TicketQuery(version=0.6|0.7&resolution=duplicate)]]

This is displayed as:

No results

[[TicketQuery(id=123)]]

This is displayed as:

#123
Typo in the model_api/#field-types

Format: compact

[[TicketQuery(version=0.6|0.7&resolution=duplicate, compact)]]

This is displayed as:

No results

Format: count

[[TicketQuery(version=0.6|0.7&resolution=duplicate, count)]]

This is displayed as:

0

Format: progress

[[TicketQuery(milestone=0.12.8&group=type,format=progress)]]

This is displayed as:

Uncategorized

2031 / 2031

Bug

10462 / 10829

New feature

3837 / 4217

Cleanup/optimization

5434 / 5746

Format: table

You can choose the columns displayed in the table format (format=table) using col=<field>. You can specify multiple fields and the order they are displayed in by placing pipes (|) between the columns:

[[TicketQuery(max=3,status=closed,order=id,desc=1,format=table,col=resolution|summary|owner|reporter)]]

This is displayed as:

Full rows

In table format you can specify full rows using rows=<field>:

[[TicketQuery(max=3,status=closed,order=id,desc=1,format=table,col=resolution|summary|owner|reporter,rows=description)]]

This is displayed as:

Results (1 - 3 of 34979)

1 2 3 4 5 6 7 8 9 10 11
Ticket Resolution Summary Owner Reporter
#36826 duplicate Add "copy to clipboard" button to documentation code blocks VidhiKathiriya05
Description

Added a "copy to clipboard" button to all code blocks in the documentation. This improves the developer experience by allowing users to quickly copy examples. The implementation uses a lightweight JavaScript utility to handle the clipboard interaction and includes CSS styling to ensure the button matches the Django documentation theme.

#36824 wontfix FileField storage parameter should support string references to STORAGES dict keys Petr Dlouhý
Description

Summary

FileField's storage parameter doesn't support string references to STORAGES dict keys, despite Django 4.2+ establishing STORAGES as the standard configuration method. This creates confusion and forces workarounds.

Description

Django 4.2 introduced the STORAGES setting as a centralized dictionary for configuring storage backends, deprecating DEFAULT_FILE_STORAGE. However, FileField and ImageField don't support string references to these storage keys.

Current Behavior

# settings.py
STORAGES = {
    "default": {...},
    "private_assets": {...},
}

# models.py
from django.core.files.storage import storages

# This works - but verbose and requires callable wrapper
def get_private_storage():
    return storages["private_assets"]

class MyModel(models.Model):
    file = models.FileField(storage=get_private_storage)

Expected Behavior

# This should work - consistent with STORAGES design
class MyModel(models.Model):
    file = models.FileField(storage="private_assets")

Problem

When developers try the intuitive approach (storage="private_assets"), Django stores it as a string. This fails silently until runtime when code accesses field.storage, causing:

AttributeError: 'str' object has no attribute 'path'

This is particularly problematic for third-party libraries (like easy-thumbnails) that access field.storage directly and expect a storage object, not a string.

Inconsistency

The STORAGES dict uses string keys everywhere:

  • settings.STORAGES["default"] - configuration
  • storages["private_assets"] - runtime access
  • THUMBNAIL_DEFAULT_STORAGE = "thumbnails" - library settings
  • FileField(storage="name") - doesn't work

This breaks the principle of least surprise. If Django establishes a pattern (string keys for storage), it should work consistently across the framework.

Real-World Impact

I encountered this while implementing Django STORAGES support for easy-thumbnails. Users naturally try storage="name" based on the STORAGES pattern, and it fails with a cryptic error. This forced me to add defensive string resolution in the library.

Proposed Solutions

Option A: Support string storage in FileField (Recommended)

Add string resolution in FileField.__init__():

def __init__(self, ..., storage=None, **kwargs):
    self.storage = storage or default_storage
    
    # Resolve string references to STORAGES dict
    if isinstance(self.storage, str):
        from django.core.files.storage import storages
        self.storage = storages[self.storage]
    
    if callable(self.storage):
        self._storage_callable = self.storage
        self.storage = self.storage()
        ...

Benefits:

  • Consistent with STORAGES design
  • Intuitive for developers
  • Backwards compatible (no breaking changes)
  • ~5 lines of code

Option B: Document that string storage is not supported

If supporting string storage is not desired, clearly document in FileField docs:

Note: The storage parameter does not support string references to STORAGES dict keys. 
Use a callable function to reference configured storages:

def get_my_storage():
    from django.core.files.storage import storages
    return storages["my_storage"]

file = models.FileField(storage=get_my_storage)

This at least prevents confusion and provides a clear workaround.

Migration Behavior

String storage resolution wouldn't create migration issues because:

  • Strings would be resolved at model load time (like callables)
  • Migrations would store the string reference, not the resolved object
  • This mirrors how callable storage already works

Backwards Compatibility

Fully backwards compatible - existing code using storage objects or callables continues working unchanged.

Related Tickets

  • #31941 - FileField with callable storage deconstruction
  • #34192 - Callable storage returning default_storage

Questions

  1. Was excluding string storage from FileField intentional, or an oversight during STORAGES implementation?
  2. If intentional, what's the reasoning? (I'd like to understand the design decision)
  3. If not desired as a feature, can we at least improve documentation to prevent this confusion?
#36823 duplicate Data loss using `bulk_create()` on Django 5.2 due to Postgres `UNNEST` and explicit cast truncating James Beith
Description

In Django 5.2, bulk_create() can use a faster strategy that inserts rows via UNNEST of typed arrays (feature ticket). That strategy typically involves explicitly casting the arrays to the destination column types (e.g. varchar(8)[]). So if we've a model field models.CharField(max_length=8) then PostgreSQL explicitly casts to varchar(n) which is a silent truncate to length n.

Previously, in Django 5.1 which doesn't use UNNEST, if we use bulk_create() passing an instance that has a value longer than 8 characters (e.g. "AAAABBBBC") for the field models.CharField(max_length=8) we'd get a DataError raised and no database row persisted. On Django 5.2, the value is truncated to "AAAABBBB" and the row is persisted in the database.

This truncation behaviour is a desired SQL behaviour:

However, if one explicitly casts a value to character varying(n) or character(n), then an over-length value will be truncated to n characters without raising an error. (This too is required by the SQL standard.)

Further examples can be seen here.

1 2 3 4 5 6 7 8 9 10 11


See also: TracQuery, TracTickets, TracReports

Last modified 2 years ago Last modified on Jan 24, 2024, 9:58:09 AM
Note: See TracWiki for help on using the wiki.
Back to Top