{"id":29143411,"url":"https://github.com/mrthearman/undine","last_synced_at":"2026-04-02T00:50:13.816Z","repository":{"id":300015885,"uuid":"809948630","full_name":"MrThearMan/undine","owner":"MrThearMan","description":"GraphQL for Django","archived":false,"fork":false,"pushed_at":"2025-06-26T18:18:41.000Z","size":3340,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-26T19:27:22.993Z","etag":null,"topics":["django","framework","graphql"],"latest_commit_sha":null,"homepage":"","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/MrThearMan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"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,"zenodo":null}},"created_at":"2024-06-03T18:57:09.000Z","updated_at":"2025-06-25T11:03:17.000Z","dependencies_parsed_at":"2025-06-26T19:23:10.583Z","dependency_job_id":null,"html_url":"https://github.com/MrThearMan/undine","commit_stats":null,"previous_names":["mrthearman/undine"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/MrThearMan/undine","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MrThearMan%2Fundine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MrThearMan%2Fundine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MrThearMan%2Fundine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MrThearMan%2Fundine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MrThearMan","download_url":"https://codeload.github.com/MrThearMan/undine/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MrThearMan%2Fundine/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262842921,"owners_count":23373167,"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":["django","framework","graphql"],"created_at":"2025-06-30T20:07:18.230Z","updated_at":"2026-04-02T00:50:13.787Z","avatar_url":"https://github.com/MrThearMan.png","language":"Python","readme":"# Undine - GraphQL for Django\n\n[![Coverage Status][coverage-badge]][coverage]\n[![GitHub Workflow Status][status-badge]][status]\n[![PyPI][pypi-badge]][pypi]\n[![GitHub][licence-badge]][licence]\n[![GitHub Last Commit][repo-badge]][repo]\n[![GitHub Issues][issues-badge]][issues]\n[![Downloads][downloads-badge]][pypi]\n[![Python Version][version-badge]][pypi]\n[![Django Version][django-badge]][pypi]\n\n[coverage-badge]: https://coveralls.io/repos/github/MrThearMan/undine/badge.svg?branch=main\n[status-badge]: https://img.shields.io/github/actions/workflow/status/MrThearMan/undine/test.yml?branch=main\n[pypi-badge]: https://img.shields.io/pypi/v/undine\n[licence-badge]: https://img.shields.io/github/license/MrThearMan/undine\n[repo-badge]: https://img.shields.io/github/last-commit/MrThearMan/undine\n[issues-badge]: https://img.shields.io/github/issues-raw/MrThearMan/undine\n[version-badge]: https://img.shields.io/pypi/pyversions/undine\n[downloads-badge]: https://img.shields.io/pypi/dm/undine\n[django-badge]: https://img.shields.io/pypi/djversions/undine\n\n[coverage]: https://coveralls.io/github/MrThearMan/undine?branch=main\n[status]: https://github.com/MrThearMan/undine/actions/workflows/test.yml\n[pypi]: https://pypi.org/project/undine\n[licence]: https://github.com/MrThearMan/undine/blob/main/LICENSE\n[repo]: https://github.com/MrThearMan/undine/commits/main\n[issues]: https://github.com/MrThearMan/undine/issues\n\n```shell\npip install undine\n```\n\n---\n\n**Documentation**: [https://mrthearman.github.io/undine/](https://mrthearman.github.io/undine/)\n\n**Source Code**: [https://github.com/MrThearMan/undine/](https://github.com/MrThearMan/undine/)\n\n**Contributing**: [https://mrthearman.github.io/undine/contributing/](https://mrthearman.github.io/undine/contributing/)\n\n---\n\nUndine is a GraphQL library for Django. It's designed to be easy to use and extend\nwhile providing out-of-the-box solutions for many common issues GraphQL developers face.\n\n**Feature highlights:**\n\n- Automatic generation of GraphQL types from Django models\n- Automatic query optimization\n- Logically composable filtering\n- Ordering based on enums\n- Single and bulk mutations, including relations\n- Hidden and input-only mutation inputs\n- Built-in permission and validation hooks\n- Support for Relay Global object IDs and Connection pagination\n- File uploads based on GraphQL multipart request specification\n- Support for asynchronous execution and DataLoaders\n- Subscriptions with WebSockets, Server-Sent Events, or Multipart HTTP\n- Server-side query caching\n- Optional persisted documents support\n- Lifecycle hooks for customizing the GraphQL request cycle\n- Hiding fields and types from schema (experimental)\n- Incremental delivery (experimental)\n- Built-in testing tools\n\nCheck out the [Tutorial] to get started.\n\n[Tutorial]: https://mrthearman.github.io/undine/tutorial/\n\n```python\nimport asyncio\nfrom collections.abc import AsyncIterator\nfrom typing import Any\n\nfrom undine import (\n    Entrypoint,\n    Field,\n    Filter,\n    FilterSet,\n    GQLInfo,\n    Input,\n    MutationType,\n    Order,\n    OrderSet,\n    QueryType,\n    RootType,\n    create_schema,\n)\nfrom undine.exceptions import GraphQLPermissionError, GraphQLValidationError\nfrom undine.relay import Connection, Node\nfrom undine.subscriptions import ModelCreateSubscription\n\nfrom .models import Task\n\n\nclass TaskFilterSet(FilterSet[Task]):\n    name = Filter(lookup=\"icontains\")\n    done = Filter()\n\n\nclass TaskOrderSet(OrderSet[Task]):\n    id = Order()\n    name = Order(null_placement=\"last\")\n\n\n@Node\n@TaskFilterSet\n@TaskOrderSet\nclass TaskType(QueryType[Task], schema_name=\"Task\"):\n    pk = Field()\n    name = Field()\n\n    @name.permissions\n    def name_permissions(self, instance: Task, info: GQLInfo) -\u003e None:\n        if not info.context.user.is_authenticated:\n            raise GraphQLPermissionError\n\n\nclass TaskCreateMutation(MutationType[Task]):\n    name = Input()\n    done = Input(default_value=False)\n\n    @classmethod\n    def __permissions__(cls, instance: Task, info: GQLInfo, input_data: dict[str, Any]) -\u003e None:\n        if not info.context.user.is_staff:\n            msg = \"Only staff members can create tasks\"\n            raise GraphQLPermissionError(msg)\n\n    @classmethod\n    def __validate__(cls, instance: Task, info: GQLInfo, input_data: dict[str, Any]) -\u003e None:\n        if len(input_data[\"name\"]) \u003c 3:\n            msg = \"Task name must be at least 3 characters\"\n            raise GraphQLValidationError(msg)\n\n\nclass Query(RootType):\n    node = Entrypoint(Node)\n    task = Entrypoint(TaskType, cache_time=10)\n    tasks = Entrypoint(Connection(TaskType))\n\n\nclass Mutation(RootType):\n    create_task = Entrypoint(TaskCreateMutation)\n    bulk_create_tasks = Entrypoint(TaskCreateMutation, many=True)\n\n\nclass Subscription(RootType):\n    task_created = Entrypoint(ModelCreateSubscription(TaskType))\n\n    @Entrypoint\n    async def countdown(self, info: GQLInfo) -\u003e AsyncIterator[int]:\n        for i in range(10, -1, -1):\n            yield i\n            await asyncio.sleep(1)\n\n\nschema = create_schema(query=Query, mutation=Mutation, subscription=Subscription)\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmrthearman%2Fundine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmrthearman%2Fundine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmrthearman%2Fundine/lists"}