{"id":16026953,"url":"https://github.com/panos-stavrianos/py-directus","last_synced_at":"2025-06-13T04:06:58.852Z","repository":{"id":192634511,"uuid":"687096878","full_name":"panos-stavrianos/py-directus","owner":"panos-stavrianos","description":"py-directus is a Python wrapper for asynchronous interaction with the Directus headless CMS API. It provides a convenient and easy-to-use interface for performing CRUD operations, querying data, and managing resources in Directus.","archived":false,"fork":false,"pushed_at":"2025-02-06T16:03:37.000Z","size":822,"stargazers_count":19,"open_issues_count":6,"forks_count":4,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-05-06T22:16:16.196Z","etag":null,"topics":["async","directus","fastapi","pydantic","python","sdk","wrapper"],"latest_commit_sha":null,"homepage":"https://panos-stavrianos.github.io/py-directus/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/panos-stavrianos.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-09-04T15:49:26.000Z","updated_at":"2025-04-04T16:41:24.000Z","dependencies_parsed_at":null,"dependency_job_id":"fe1f1522-1d17-45cf-88b5-9089bedcecda","html_url":"https://github.com/panos-stavrianos/py-directus","commit_stats":null,"previous_names":["panos-stavrianos/py-directus"],"tags_count":30,"template":false,"template_full_name":null,"purl":"pkg:github/panos-stavrianos/py-directus","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/panos-stavrianos%2Fpy-directus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/panos-stavrianos%2Fpy-directus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/panos-stavrianos%2Fpy-directus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/panos-stavrianos%2Fpy-directus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/panos-stavrianos","download_url":"https://codeload.github.com/panos-stavrianos/py-directus/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/panos-stavrianos%2Fpy-directus/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259578215,"owners_count":22879215,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["async","directus","fastapi","pydantic","python","sdk","wrapper"],"created_at":"2024-10-08T20:04:18.068Z","updated_at":"2025-06-13T04:06:58.825Z","avatar_url":"https://github.com/panos-stavrianos.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# This project is on hold for now due to time constraints.\n\n# py-directus\n\n## Disclaimer: Under development\n\n\u003e This is very early in development and the API is subject to change.\n\u003e\n\u003e If you intend to use this library in a production environment, expect undocumented changes and bugs until the first\n\u003e stable release.\n\u003e\n\u003e If you find any issues or have any suggestions, please open an issue or a pull request.\n\nDocumentation [here](https://panos-stavrianos.github.io/py-directus/)\n\npy-directus is a Python wrapper for asynchronous interaction with the Directus headless CMS API. It provides a convenient and\neasy-to-use interface for performing CRUD operations, querying data, and managing resources in Directus.\n\n## Features\n\n- Asynchronous\n- Login and authentication handling\n- Reading and writing data from Directus collections\n- Filtering, sorting, and searching data\n- Aggregating data using aggregation operators\n- Creating, updating, and deleting items in Directus collections\n- Handling multiple users in the same session\n\nDependencies:\n- [Pydantic](https://pydantic-docs.helpmanual.io/): This library leverages Pydantic for data validation and parsing. Pydantic is a powerful tool in Python for ensuring data integrity and handling data validation with ease.\n\n- [HTTPX](https://www.python-httpx.org/): The library utilizes HTTPX, a fully featured HTTP client for Python 3, which provides sync and async APIs, and support for both HTTP/1.1 and HTTP/2.\n\n\u003e Directus API:\n\u003e This library interacts with the [Directus API](https://docs.directus.io/reference/introduction.html).\n\u003e \n\u003e To make the most of this library, it is highly recommended to familiarize yourself with the Directus API documentation. Understanding the API's capabilities and endpoints will help you effectively utilize this library for seamless integration with Directus.\n\n## Installation\n\nYou can install the library directly from [pypi](https://pypi.org/project/py-directus/) using pip:\n\n```shell\n$ pip install py-directus\n```\n\n\u003e FastAPI support requires additional dependencies installation. \n\u003e You can install them along others like this:\n\n```shell\n$ pip install py-directus[FastAPI]\n```\n\n## Authentication and Session Handling\n\n### Login\n\nCreate a Directus instance using email and password\n\n```python\nfrom py_directus import Directus\n\ndirectus = await Directus(\"https://example.com\", email=\"user@example.com\", password=\"secret\")\n```\n\nAlternatively create a Directus instance using the static token\n\n```python\nfrom py_directus import Directus\n\ndirectus = await Directus(\"https://example.com\", token=\"static_token\")\n```\n\nAnother way is to use the `with` statement to automatically logout when the session ends\n\n```python\nasync with Directus(url, email, password) as directus:\n    # Manually login\n    await directus.login()\n    # Manually start cache\n    await directus.start_cache()\n    # do stuff\n\n# OR\n\nasync with await Directus(url, email, password) as directus:\n    # do stuff\n```\n\n### Refresh Token\n\nIf you want to refresh the token you can use the `refresh` method\n\n```python\nawait directus.refresh()\n```\n\n### Logout\n\nLogout from Directus\n\n```python\nawait directus.logout()\n```\n\n### Multiple Users in the Same Session\n\nYou can use multiple users in the same session by creating a new Directus instance by passing the client object\n\n```python\nconnection = httpx.AsyncClient()\ndirectus1 = await Directus(url, token=token, connection=connection)\ndirectus2 = await Directus(url, email=email, password=password, connection=connection)\n```\n\n## Collections\n\nThere are two ways to set a collection, either by passing the collection name as a string\nor by passing the collection as a Pydantic model.\n\nUsing the `collection` method you can pass the collection name as a string\n\n```python\ndirectus.collection(\"directus_users\")\n```\n\nOr you can pass the collection as a `Pydantic` model\n\n```python\nfrom typing import Optional\n\nfrom pydantic import ConfigDict\n\nfrom py_directus.models import DirectusModel\n\n\nclass User(DirectusModel):\n    id: Optional[str]\n    first_name: Optional[str]\n    last_name: Optional[str]\n    avatar: Optional[str]\n    description: Optional[str]\n    email: Optional[str]\n    role: Optional[str] | Optional[Role]\n    status: Optional[str]\n    title: Optional[str]\n    token: Optional[str]\n\n    model_config = ConfigDict(collection=\"directus_users\")\n\n\ndirectus.collection(User)\n```\n\n\u003e Don't forget to set the `collection` attribute in the `model_config` attribute\n\nIf you go with the second option, you will get the responses as `Pydantic` models (auto parsing)\n\n\u003e The `collection` method returns a `DirectusRequest` object which is used to perform READ, CREATE,\n\u003e UPDATE and DELETE operations\n\n## Reading Data\n\nWhen you have the `DirectusRequest` object you can use the `read` method to get the data.\nThis will return a `DirectusResponse` object which contains the data.\n\n\u003e Imporatnt note: The `read` method must be awaited\n\n```python\nawait directus.collection(\"directus_users\").read()\n```\n\n### Filtering\n\nFor an easy equality filter you can pass the field name and the value\n\n```python\nawait directus.collection(\"directus_users\").filter(first_name=\"John\").read()\n```\n\nTo add multiple equality filters you can chain the `filter` method\n\n```python\nawait directus.collection(\"directus_users\")\n.filter(first_name=\"John\")\n.filter(last_name=\"Doe\").read()\n```\n\nUsing it like this you chain the filters with `AND` operator\n\n#### F objects\n\nTo define complex logic in filters, use the `F` object\n\n```python\nfrom py_directus import F\n\nawait directus.collection(\"directus_users\")\n.filter(\n    (F(first_name=\"John\") | F(first_name=\"Jane\")) \n    \u0026 F(last_name=\"Doe\")\n).read()\n```\n\n\u003e Important note: The `F` object does not support negation\n\n### Sorting\n\nYou can sort the data by passing the field name to the `sort` method\n\n```python\nawait directus.collection(\"directus_users\").sort(\"first_name\", asc=True).read()\n```\n\nTo add multiple sorting fields you can chain the `sort` method\n\n```python\nawait directus.collection(\"directus_users\")\n.sort(\"first_name\", asc=True)\n.sort(\"last_name\", asc=False).read()\n```\n\n### Limiting\n\nYou can limit the data by passing the limit to the `limit` method\n\n```python\nawait directus.collection(\"directus_users\").limit(10).read()\n```\n\n### Aggregation\n\nAggregate the number of records in the query\n\n```python\nawait directus.collection(\"directus_users\").aggregate().read()\n\n# OR\n\nawait directus.collection(\"directus_users\").aggregate(count=\"*\").read()\n```\n\nTo add multiple aggregates you can chain the `aggregate` method\n\n```python\nawait directus.collection(\"products\")\n.aggregate(countDistinct=\"id\")\n.aggregate(sum=\"price\").read()\n```\n\n#### Agg objects\n\nYou can aggregate the data by defining the needed aggregation with the `Agg` class and passing it to the `aggregate` method\n\n```python\nfrom py_directus.aggregator import Agg\n\nagg_obj = Agg(operator=AggregationOperators.Count)\n\nawait directus.collection(\"directus_users\").aggregate(agg_obj).read()\n```\n\nIn case you need only certain fields\n\n```python\nfrom py_directus.aggregator import Agg\n\namount_agg = Agg(operator=AggregationOperators.Sum, fields=\"amount\")\n\nawait directus.collection(\"transactions\").aggregate(amount_agg).read()\n```\n\nThe available aggregation operators are:\n\n- Count\n- CountDistinct\n- CountAll (Only in GraphQL)\n- Sum\n- SumDistinct\n- Average\n- AverageDistinct\n- Minimum\n- Maximum\n\n### Grouping\n\nYou can group the data by passing the field names to the `group_by` method\n\n```python\nawait directus.collection(\"directus_users\").group_by(\"first_name\", \"last_name\").read()\n```\n\n### Searching\n\nYou can search the data by passing the search term to the `search` method\n\n```python\nawait directus.collection(\"directus_users\").search(\"John\").read()\n```\n\n### Selecting Fields\n\nYou can select the fields you want to get by passing the field names to the `fields` method\n\n```python\nawait directus.collection(\"directus_users\").fields(\"first_name\", \"last_name\").read()\n```\n\n### Getting the Count Metadata\n\nYou can get the count of the data (total count and filtered count) calling `include_count`\n\n```python\nawait directus.collection(\"directus_users\").include_count().read()\n```\n\n## CRUD\n\n### Retrieving items\n\nAfter you call `read()` you get a `DirectusResponse` object which contains the data.\n\n- `item` for single item\n- `items` for multiple items\n\nGetting the data as a dictionary or a list of dictionaries\n\n```python\nresponse = await directus.collection(\"directus_users\").read()\nprint(response.item[\"first_name\"])\nprint(response.items)\n```\n\nIf you provide the `collection` method a `Pydantic` model you will get the data as a `Pydantic` object or a list of `Pydantic` objects\n\n```python\nresponse = await directus.collection(User).read()\nprint(response.item.first_name)\nprint(response.items)\n```\n\n### Converting to Models (pydantic) or to Dictionary\n\nApart from the auto parsing, you can manually convert the data to a `Pydantic` model instance or to a dictionary using:\n\n- `item_as(User)` or `items_as(User)`\n- `item_as_dict()` or `items_as_dict()`\n\n```python\nresponse = await directus.collection(\"directus_users\").read()\nprint(response.item_as(User))\n\nresponse = await directus.collection(User).read()\nprint(response.item_as_dict())\n```\n\n### Creating Items\n\nThe library does not support `Pydantic` models for creation, you have to pass a dictionary\n\n- create(items: dict|List[dict])\n\n```python\nawait directus.collection(\"directus_users\").create({\n    \"first_name\": \"John\", \"last_name\": \"Doe\"\n})\n\n# OR\n\nawait directus.collection(\"directus_users\").create(\n    [\n        {\"first_name\": \"John\", \"last_name\": \"Doe\"},\n        {\"first_name\": \"Jane\", \"last_name\": \"Doe\"}\n    ]\n)\n```\n\n### Updating Items\n\nThe library do not support `Pydantic` models for updating, you have to pass a dictionary\n\n- `update(ids: str|int, items: dict)`\n- `update(ids: List[str|int], items: List[dict])`\n\n```python\nawait directus.collection(\"directus_users\").update(1, {\n    \"first_name\": \"Red\",\n    \"last_name\": \"John\"\n})\n\n# OR\n\nawait directus.collection(\"directus_users\").update(\n    [1, 2],\n    [\n        {\"first_name\": \"Jean-Luc\"},\n        {\"first_name\": \"Jane\", \"last_name\": \"Doe\"}\n    ]\n)\n```\n\n### Deleting Items\n\n- `delete(ids: str|int|List[str|int])`\n\n```python\nawait directus.collection(\"directus_users\").delete(1)\n\n# OR\n\nawait directus.collection(\"directus_users\").delete([1, 2])\n```\n\n\u003e Supporting `Pydantic` models for `create`/`update`/`delete` item operations is shortly coming.\n\n## Examples\n\n\u003e Examples are not included with the `pypi` package, so you will have to download them separately and execute in a virtual environment.\n\nRun individual examples as such:\n\n```shell\npython -m examples.\u003cexample_file_name\u003e\n```\n\n## Tests\n\nRun tests as such:\n\n```shell\n# All unit tests\n\npython -m unittest discover -s tests/unit\n\n# All integration tests\n\npython -m unittest discover -s tests/integration\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpanos-stavrianos%2Fpy-directus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpanos-stavrianos%2Fpy-directus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpanos-stavrianos%2Fpy-directus/lists"}