{"id":20961594,"url":"https://github.com/adamalton/djangae-consistency","last_synced_at":"2026-04-13T11:02:36.741Z","repository":{"id":34434833,"uuid":"38368256","full_name":"adamalton/djangae-consistency","owner":"adamalton","description":"Mitigation against eventual consistency issues on the App Engine Datastore","archived":false,"fork":false,"pushed_at":"2016-02-20T01:16:17.000Z","size":19,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-01-11T15:17:09.809Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/adamalton.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-07-01T11:46:40.000Z","updated_at":"2016-02-20T01:16:17.000Z","dependencies_parsed_at":"2022-09-14T06:10:30.257Z","dependency_job_id":null,"html_url":"https://github.com/adamalton/djangae-consistency","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/adamalton/djangae-consistency","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adamalton%2Fdjangae-consistency","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adamalton%2Fdjangae-consistency/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adamalton%2Fdjangae-consistency/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adamalton%2Fdjangae-consistency/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/adamalton","download_url":"https://codeload.github.com/adamalton/djangae-consistency/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adamalton%2Fdjangae-consistency/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31749767,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-13T09:16:15.125Z","status":"ssl_error","status_checked_at":"2026-04-13T09:16:05.023Z","response_time":93,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":[],"created_at":"2024-11-19T02:14:29.570Z","updated_at":"2026-04-13T11:02:36.723Z","avatar_url":"https://github.com/adamalton.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Djangae Consistency\n\n**Note: this project has now been merged into [djangae](https://github.com/potatolondon/djangae) as `djangae.contrib.consistency`.  Pull requests should be submitted there.**\n\n\nA Django app which helps to mitigate against eventual consistency issues with the App Engine Datastore.\nWorks only with [Djangae](https://github.com/potatolondon/djangae).\n\n\n## In A Nutshell\n\nIt caches recently created and/or modified objects so that it knows about them even if they're not\nyet being returned by the Datastore.  It then provides a function `improve_queryset_consistency`\nwhich you can use on a queryset so that it:\n\n* Uses the cache to include recently-created/-modified objects which match the query but which are\n  not yet being returned by the Datastore. (This is not effective if the cache gets purged).\n* Does not return any recently deleted objects which are still being returned by the Datastore.\n  (This is not cache-dependent.)\n\n\n## Usage\n\nAdd `'consistency'` to `settings.INSTALLED_APPS` and then use as follows.  (You may also need to\nimport `consistency.models` to get the signals to register.)\n\n```python\n\nfrom consistency import improve_queryset_consistency, get_recent_objects\n\n# Example 1 - `improve_queryset_consistency`\n\nqueryset = MyModel.objects.filter(is_yellow=True)\nmore_consistent_queryset = improve_queryset_consistency(queryset)\n# Use as normal\n\n\n# Example 2 - `get_recent_objects`\n\nqueryset = MyModel.objects.filter(is_yellow=True)\nobjects_possibly_missed = get_recent_objects(queryset)\n# Use both together to build your full set of results\n\n```\n\nNote that in both cases the recently-created objects are not guaranteed to be returned.  The\nrecently-created objects are only stored in memcache, which could be purged at any time.\n\n\n## Advanced Configuration\n\nBy default the app will cache recently-created objects for all models.  But you can change this\nbehaviour so that it only caches particular models, only caches objects that match particular\ncriteria, and/or caches objects that were recently *modified* as well as recently *created*.\n\n```python\nCONSISTENCY_CONFIG = {\n\n    # These defaults apply to every model, unless otherwise overriden.\n    # The values shown here are the default defaults (i.e. what you get if\n    # you don't set CONSISTENCY_CONFIG at all).\n    \"defaults\": {\n        \"cache_on_creation\": True,\n        \"cache_on_modification\": False,\n        \"cache_time\": 60, # Seconds\n        \"caches\": [\"django\"], # Where to store the cache.\n        \"only_cache_matching\": [], # Optional filtering (see below)\n    },\n\n    # The settings can be overridden for each individual model\n    \"models\": {\n        \"app_name.ModelName\": {\n            \"cache_on_creation\": True,\n            \"cache_on_modification\": True,\n            \"caches\": [\"session\", \"django\"],\n            \"cache_time\": 20,\n            \"only_cache_matching\": [\n                # A list of checks, where each check is a dict of filter\n                # kwargs or a function. If an object matches *any* of\n                # these then it is cached. No filters means cache everything.\n                {\"name\": \"Ted\", \"archived\": False},\n                lambda obj: obj.method(),\n            ]\n        },\n        \"app_name.UnimportantModel\": {\n            \"cache_on_creation\": False,\n            \"cache_on_modification\": False,\n            # Any settings which you don't override inheit from \"defaults\".\n        },\n    },\n}\n```\n\n\n## Notes\n\n* Even if you set both `cache_on_creation` and `cache_on_modification` to `False`, you can still use\n  `improve_queryset_consistency` to prevent stale objects from being returned by your query.\n* The way that `improve_queryset_consistency` works means that it converts your query into a\n  `pk__in` query.  This has 2 side effects:\n    - It causes the initial query to be executed.  It does this with `values_list('pk')` (which\n      becomes a Datastore keys-only query) so is fast, but you should be aware that it hits the DB.\n    - It introduces a limit of 1000 results, so if your queryset is not already limited then a\n      limit will be imposed, and if your queryset already has a limit then it may be reduced. This\n      is to ensure a total result of \u003c= 1000 objects.  This is imperfect though, and may result in\n      slightly fewer than 1000 results because recent objects in the cache will reduce the limit\n      even if they don't match the query. (This could potentially be fixed.)\n* To avoid the side effects of `improve_queryset_consistency` you may wish to use\n  `get_recent_objects` instead, giving you slightly more control over what happens.\n* As you can see in the config section, there are 2 places which the new objects can be cached: in\n  Django's normal cache (`django.core.cache`) or in the current user's session.\n    - Using the \"session\" cache may be slightly faster for querying (as the session object has probably\n      been loaded anyway, so it avoids another cache lookup), but it's unlikely to be faster when\n      creating/modifying an object, because writing to the session requires a Database write, which is\n      probably slower than a cache write.  Unless you're altering the session object anyway, in which\n      case the session cache may be advantageous.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadamalton%2Fdjangae-consistency","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fadamalton%2Fdjangae-consistency","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadamalton%2Fdjangae-consistency/lists"}