{
  "name": "django-search-query",
  "url": "https://django-search-query.git-pull.com",
  "description": "A reusable, Lucene-inspired search query language for Django – and an optional Django admin integration built on top of it.",
  "sourceRepository": "https://github.com/tony/django-search-query/",
  "agentEntrypoints": {
    "manifest": "/docs.json",
    "llms": "/llms.txt",
    "llmsFull": "/llms-full.txt"
  },
  "pages": [
    {
      "title": "API reference",
      "description": "The public surface is small: one call for the common case, parse()/build_q() when you want the AST in between, a field registry, and one exception. The optional admin integration adds a single mixi...",
      "section": "Documentation",
      "url": "/api/",
      "markdownUrl": "/api.md",
      "headings": [
        {
          "id": "",
          "level": 1,
          "text": "API reference"
        },
        {
          "id": "core",
          "level": 2,
          "text": "Core"
        },
        {
          "id": "django_search_query.search_query_to_q",
          "level": 3,
          "text": "search_query_to_q()"
        },
        {
          "id": "django_search_query.parse",
          "level": 3,
          "text": "parse()"
        },
        {
          "id": "django_search_query.build_q",
          "level": 3,
          "text": "build_q()"
        },
        {
          "id": "django_search_query.registry.FieldRegistry",
          "level": 3,
          "text": "FieldRegistry"
        },
        {
          "id": "django_search_query.registry.FieldRegistry.specs",
          "level": 4,
          "text": "specs"
        },
        {
          "id": "django_search_query.registry.FieldRegistry.get",
          "level": 4,
          "text": "get()"
        },
        {
          "id": "django_search_query.registry.FieldRegistry.known_names",
          "level": 4,
          "text": "known_names()"
        },
        {
          "id": "django_search_query.registry.FieldRegistry.__init__",
          "level": 4,
          "text": "__init__()"
        },
        {
          "id": "django_search_query.registry.FieldSpec",
          "level": 3,
          "text": "FieldSpec"
        },
        {
          "id": "django_search_query.registry.FieldSpec.name",
          "level": 4,
          "text": "name"
        },
        {
          "id": "django_search_query.registry.FieldSpec.kind",
          "level": 4,
          "text": "kind"
        },
        {
          "id": "django_search_query.registry.FieldSpec.path",
          "level": 4,
          "text": "path"
        },
        {
          "id": "django_search_query.registry.FieldSpec.enum_values",
          "level": 4,
          "text": "enum_values"
        },
        {
          "id": "django_search_query.registry.FieldSpec.aliases",
          "level": 4,
          "text": "aliases"
        },
        {
          "id": "django_search_query.registry.FieldSpec.supports_comparison",
          "level": 4,
          "text": "supports_comparison"
        },
        {
          "id": "django_search_query.registry.FieldSpec.supports_range",
          "level": 4,
          "text": "supports_range"
        },
        {
          "id": "django_search_query.registry.FieldSpec.__init__",
          "level": 4,
          "text": "__init__()"
        },
        {
          "id": "django_search_query.errors.QueryParseError",
          "level": 3,
          "text": "QueryParseError"
        },
        {
          "id": "django_search_query.errors.QueryParseError.__init__",
          "level": 4,
          "text": "__init__()"
        },
        {
          "id": "highlighting",
          "level": 3,
          "text": "Highlighting"
        },
        {
          "id": "django_search_query.highlight.highlight_query_spans",
          "level": 4,
          "text": "highlight_query_spans()"
        },
        {
          "id": "django_search_query.highlight.apply_registry_errors",
          "level": 4,
          "text": "apply_registry_errors()"
        },
        {
          "id": "django_search_query.highlight.Span",
          "level": 4,
          "text": "Span"
        },
        {
          "id": "django_search_query.highlight.Span.start",
          "level": 5,
          "text": "start"
        },
        {
          "id": "django_search_query.highlight.Span.role",
          "level": 5,
          "text": "role"
        },
        {
          "id": "django_search_query.highlight.Span.text",
          "level": 5,
          "text": "text"
        },
        {
          "id": "django_search_query.highlight.Span.__new__",
          "level": 5,
          "text": "__new__()"
        },
        {
          "id": "django_search_query.highlight.Span._asdict",
          "level": 5,
          "text": "_asdict()"
        },
        {
          "id": "django_search_query.highlight.Span._field_defaults",
          "level": 5,
          "text": "_field_defaults"
        },
        {
          "id": "django_search_query.highlight.Span._fields",
          "level": 5,
          "text": "_fields"
        },
        {
          "id": "django_search_query.highlight.Span._make",
          "level": 5,
          "text": "_make()"
        },
        {
          "id": "django_search_query.highlight.Span._replace",
          "level": 5,
          "text": "_replace()"
        },
        {
          "id": "django_search_query.highlight.HIGHLIGHT_ROLES",
          "level": 4,
          "text": "HIGHLIGHT_ROLES"
        },
        {
          "id": "admin",
          "level": 2,
          "text": "Admin"
        },
        {
          "id": "django_admin_search_query.mixin.SearchQueryAdminMixin",
          "level": 3,
          "text": "SearchQueryAdminMixin"
        },
        {
          "id": "django_admin_search_query.mixin.SearchQueryAdminMixin.search_query_registry",
          "level": 4,
          "text": "search_query_registry"
        },
        {
          "id": "django_admin_search_query.mixin.SearchQueryAdminMixin.search_query_field_map",
          "level": 4,
          "text": "search_query_field_map"
        },
        {
          "id": "django_admin_search_query.mixin.SearchQueryAdminMixin.search_query_default_fields",
          "level": 4,
          "text": "search_query_default_fields"
        },
        {
          "id": "django_admin_search_query.mixin.SearchQueryAdminMixin.change_list_template",
          "level": 4,
          "text": "change_list_template"
        },
        {
          "id": "django_admin_search_query.mixin.SearchQueryAdminMixin.Media",
          "level": 4,
          "text": "Media"
        },
        {
          "id": "django_admin_search_query.mixin.SearchQueryAdminMixin.Media.js",
          "level": 5,
          "text": "js"
        },
        {
          "id": "django_admin_search_query.mixin.SearchQueryAdminMixin.Media.css",
          "level": 5,
          "text": "css"
        },
        {
          "id": "django_admin_search_query.mixin.SearchQueryAdminMixin.get_search_query_registry",
          "level": 4,
          "text": "get_search_query_registry()"
        },
        {
          "id": "django_admin_search_query.mixin.SearchQueryAdminMixin.get_search_query_field_map",
          "level": 4,
          "text": "get_search_query_field_map()"
        },
        {
          "id": "django_admin_search_query.mixin.SearchQueryAdminMixin.get_search_query_default_fields",
          "level": 4,
          "text": "get_search_query_default_fields()"
        },
        {
          "id": "django_admin_search_query.mixin.SearchQueryAdminMixin.get_search_results",
          "level": 4,
          "text": "get_search_results()"
        },
        {
          "id": "django_admin_search_query.mixin.SearchQueryAdminMixin.get_urls",
          "level": 4,
          "text": "get_urls()"
        },
        {
          "id": "django_admin_search_query.mixin.SearchQueryAdminMixin.search_tokens_view",
          "level": 4,
          "text": "search_tokens_view()"
        },
        {
          "id": "django_admin_search_query.mixin.SearchQueryAdminMixin.search_highlight_view",
          "level": 4,
          "text": "search_highlight_view()"
        },
        {
          "id": "django_admin_search_query.mixin.SearchQueryAdminMixin.changelist_view",
          "level": 4,
          "text": "changelist_view()"
        },
        {
          "id": "hook-contracts",
          "level": 3,
          "text": "Hook contracts"
        },
        {
          "id": "json-endpoints",
          "level": 3,
          "text": "JSON endpoints"
        }
      ]
    },
    {
      "title": "Changelog",
      "description": "To install unreleased versions of a workspace package, see developmental releases.",
      "section": "Documentation",
      "url": "/history/",
      "markdownUrl": "/history.md",
      "headings": [
        {
          "id": "",
          "level": 1,
          "text": "Changelog"
        },
        {
          "id": "django-search-query-0-1-0a1-unreleased",
          "level": 2,
          "text": "django-search-query 0.1.0a1 (unreleased)"
        },
        {
          "id": "documentation",
          "level": 3,
          "text": "Documentation"
        },
        {
          "id": "tutorials-reference-and-highlighted-query-examples-4",
          "level": 4,
          "text": "Tutorials, reference, and highlighted query examples (#4)"
        },
        {
          "id": "a-dedicated-query-language-page-with-worked-examples-6",
          "level": 4,
          "text": "A dedicated query-language page with worked examples (#6)"
        },
        {
          "id": "django-search-query-0-1-0a0-2026-07-19",
          "level": 2,
          "text": "django-search-query 0.1.0a0 (2026-07-19)"
        },
        {
          "id": "what-s-new",
          "level": 3,
          "text": "What’s new"
        },
        {
          "id": "structured-search-query-language-1",
          "level": 4,
          "text": "Structured search query language (#1)"
        },
        {
          "id": "searchable-field-registry-1",
          "level": 4,
          "text": "Searchable-field registry (#1)"
        },
        {
          "id": "query-highlighting-2",
          "level": 4,
          "text": "Query highlighting (#2)"
        },
        {
          "id": "django-admin-search-query-structured-search-in-the-changelist-1",
          "level": 4,
          "text": "django-admin-search-query: Structured search in the changelist (#1)"
        },
        {
          "id": "django-admin-search-query-colored-autocompleting-search-input-2",
          "level": 4,
          "text": "django-admin-search-query: Colored, autocompleting search input (#2)"
        },
        {
          "id": "development",
          "level": 3,
          "text": "Development"
        },
        {
          "id": "automated-documentation-publishing-3",
          "level": 4,
          "text": "Automated documentation publishing (#3)"
        }
      ]
    },
    {
      "title": "django-search-query",
      "description": "A reusable, Lucene-inspired search query language for Django – and an optional Django admin integration built on top of it.",
      "section": "",
      "url": "/",
      "markdownUrl": "/index.md",
      "headings": [
        {
          "id": "",
          "level": 1,
          "text": "django-search-query"
        },
        {
          "id": "install",
          "level": 2,
          "text": "Install"
        },
        {
          "id": "what-this-is",
          "level": 2,
          "text": "What this is"
        }
      ]
    },
    {
      "title": "Install",
      "description": "django-search-query is the core query language, independent of any particular UI, admin integration, or search backend; add it to any Django project’s environment. django-admin-search-query is the ...",
      "section": "Documentation",
      "url": "/install/",
      "markdownUrl": "/install.md",
      "headings": [
        {
          "id": "",
          "level": 1,
          "text": "Install"
        },
        {
          "id": "developmental-releases",
          "level": 2,
          "text": "Developmental releases"
        }
      ]
    },
    {
      "title": "Colored search input",
      "description": "The colored input is a progressive enhancement of the Django admin changelist search box. Highlighting is client-side: search-lexer.js is a faithful JavaScript port of the Python highlighter, so th...",
      "section": "Documentation",
      "url": "/packages/django-admin-search-query/colored-input/",
      "markdownUrl": "/packages/django-admin-search-query/colored-input.md",
      "headings": [
        {
          "id": "",
          "level": 1,
          "text": "Colored search input"
        },
        {
          "id": "how-it-works",
          "level": 2,
          "text": "How it works"
        },
        {
          "id": "python-javascript-parity",
          "level": 2,
          "text": "Python <-> JavaScript parity"
        },
        {
          "id": "endpoints",
          "level": 2,
          "text": "Endpoints"
        },
        {
          "id": "search-tokens",
          "level": 3,
          "text": "search-tokens/"
        },
        {
          "id": "search-highlight",
          "level": 3,
          "text": "search-highlight/"
        },
        {
          "id": "roles",
          "level": 2,
          "text": "Roles"
        },
        {
          "id": "autocomplete",
          "level": 2,
          "text": "Autocomplete"
        },
        {
          "id": "resilience",
          "level": 2,
          "text": "Resilience"
        },
        {
          "id": "development-server",
          "level": 2,
          "text": "Development server"
        }
      ]
    },
    {
      "title": "Explanation",
      "description": "django-admin-search-query depends on django-search-query through an ordinary version floor in its pyproject.toml (django-search-query>=0.1.0a0), the same way any other consumer of the query languag...",
      "section": "Documentation",
      "url": "/packages/django-admin-search-query/explanation/",
      "markdownUrl": "/packages/django-admin-search-query/explanation.md",
      "headings": [
        {
          "id": "",
          "level": 1,
          "text": "Explanation"
        },
        {
          "id": "loose-coupling-to-the-core-package",
          "level": 2,
          "text": "Loose coupling to the core package"
        },
        {
          "id": "no-javascript-degradation",
          "level": 2,
          "text": "No-JavaScript degradation"
        }
      ]
    },
    {
      "title": "How-to guides",
      "description": "SearchQueryAdminMixin is opt-in – drop it in front of a ModelAdmin on the changelists that need structured search, and leave every other admin untouched.",
      "section": "Documentation",
      "url": "/packages/django-admin-search-query/how-to/",
      "markdownUrl": "/packages/django-admin-search-query/how-to.md",
      "headings": [
        {
          "id": "",
          "level": 1,
          "text": "How-to guides"
        },
        {
          "id": "add-structured-search-to-a-modeladmin",
          "level": 2,
          "text": "Add structured search to a ModelAdmin"
        }
      ]
    },
    {
      "title": "django-admin-search-query",
      "description": "An optional Django admin integration for django-search-query – reach for it when you want a changelist search box that understands the structured query language; the core package works without it.",
      "section": "Documentation",
      "url": "/packages/django-admin-search-query/",
      "markdownUrl": "/packages/django-admin-search-query/index.md",
      "headings": [
        {
          "id": "",
          "level": 1,
          "text": "django-admin-search-query"
        }
      ]
    },
    {
      "title": "Explanation",
      "description": "A search string becomes a Q through three stages, each owned by one module. The tokenizer classifies characters into a token stream and records their source offsets, deferring every grammar decisio...",
      "section": "Documentation",
      "url": "/packages/django-search-query/explanation/",
      "markdownUrl": "/packages/django-search-query/explanation.md",
      "headings": [
        {
          "id": "",
          "level": 1,
          "text": "Explanation"
        },
        {
          "id": "the-pipeline",
          "level": 2,
          "text": "The pipeline"
        },
        {
          "id": "why-two-lexers-exist",
          "level": 2,
          "text": "Why two lexers exist"
        },
        {
          "id": "lucene-inspired-not-lucene-compatible",
          "level": 2,
          "text": "Lucene-inspired, not Lucene-compatible"
        }
      ]
    },
    {
      "title": "How-to guides",
      "description": "Task recipes for tuning search_query_to_q() beyond the tutorial’s defaults: which ORM path a field name resolves to, which fields a query may touch at all, how wildcards and ranges compile, and how...",
      "section": "Documentation",
      "url": "/packages/django-search-query/how-to/",
      "markdownUrl": "/packages/django-search-query/how-to.md",
      "headings": [
        {
          "id": "",
          "level": 1,
          "text": "How-to guides"
        },
        {
          "id": "map-field-names-to-orm-paths",
          "level": 2,
          "text": "Map field names to ORM paths"
        },
        {
          "id": "restrict-which-fields-a-query-can-touch",
          "level": 2,
          "text": "Restrict which fields a query can touch"
        },
        {
          "id": "wildcards-and-ranges",
          "level": 2,
          "text": "Wildcards and ranges"
        },
        {
          "id": "catch-parse-errors-and-fall-back",
          "level": 2,
          "text": "Catch parse errors and fall back"
        }
      ]
    },
    {
      "title": "django-search-query",
      "description": "A Lucene-inspired search query language that compiles to Django Q objects.",
      "section": "Documentation",
      "url": "/packages/django-search-query/",
      "markdownUrl": "/packages/django-search-query/index.md",
      "headings": [
        {
          "id": "",
          "level": 1,
          "text": "django-search-query"
        }
      ]
    },
    {
      "title": "Packages",
      "description": "The workspace ships two independently-installable, independently-versioned packages. The core query language stands on its own; the admin integration is opt-in and depends on it through a loose ver...",
      "section": "Documentation",
      "url": "/packages/",
      "markdownUrl": "/packages/index.md",
      "headings": [
        {
          "id": "",
          "level": 1,
          "text": "Packages"
        }
      ]
    },
    {
      "title": "Contributing",
      "description": "All shared tooling – ruff, ty, pytest, coverage – is configured once in the root pyproject.toml and applies to every package.",
      "section": "Documentation",
      "url": "/project/contributing/",
      "markdownUrl": "/project/contributing.md",
      "headings": [
        {
          "id": "",
          "level": 1,
          "text": "Contributing"
        },
        {
          "id": "workspace-layout",
          "level": 2,
          "text": "Workspace layout"
        },
        {
          "id": "standards",
          "level": 2,
          "text": "Standards"
        }
      ]
    },
    {
      "title": "Project",
      "description": "Development happens in a single uv workspace: one lockfile, one virtual environment, two publishable packages under packages/.",
      "section": "Documentation",
      "url": "/project/",
      "markdownUrl": "/project/index.md",
      "headings": [
        {
          "id": "",
          "level": 1,
          "text": "Project"
        },
        {
          "id": "set-up",
          "level": 2,
          "text": "Set up"
        },
        {
          "id": "development-loop",
          "level": 2,
          "text": "Development loop"
        }
      ]
    },
    {
      "title": "Releasing",
      "description": "Each package is versioned and released independently. A release bumps one package’s version and records its changes in the shared root changelog – which consolidates both packages under one set of ...",
      "section": "Documentation",
      "url": "/project/releasing/",
      "markdownUrl": "/project/releasing.md",
      "headings": [
        {
          "id": "",
          "level": 1,
          "text": "Releasing"
        }
      ]
    },
    {
      "title": "Query language",
      "description": "You give your users a real search box – field-scoped terms, quoted phrases, boolean logic – and search_query_to_q() turns what they type into a Django Q. Pass that to any QuerySet and the ORM does ...",
      "section": "Documentation",
      "url": "/query/",
      "markdownUrl": "/query.md",
      "headings": [
        {
          "id": "",
          "level": 1,
          "text": "Query language"
        },
        {
          "id": "see-it-work",
          "level": 2,
          "text": "See it work"
        },
        {
          "id": "syntax",
          "level": 2,
          "text": "Syntax"
        },
        {
          "id": "next",
          "level": 2,
          "text": "Next"
        }
      ]
    },
    {
      "title": "Tutorial",
      "description": "This tutorial builds one search-enabled queryset from a raw string. You describe which fields a query is allowed to touch, compile a query string into a Django Q, and run it against a real QuerySet...",
      "section": "Documentation",
      "url": "/tutorial/",
      "markdownUrl": "/tutorial.md",
      "headings": [
        {
          "id": "",
          "level": 1,
          "text": "Tutorial"
        },
        {
          "id": "describe-your-searchable-fields",
          "level": 2,
          "text": "Describe your searchable fields"
        },
        {
          "id": "compile-a-query",
          "level": 2,
          "text": "Compile a query"
        },
        {
          "id": "run-it-against-a-queryset",
          "level": 2,
          "text": "Run it against a queryset"
        },
        {
          "id": "where-to-go-next",
          "level": 2,
          "text": "Where to go next"
        }
      ]
    }
  ]
}
