{"id":19757153,"url":"https://github.com/lyst/django-urlconf-export","last_synced_at":"2025-08-23T15:07:29.743Z","repository":{"id":53048971,"uuid":"246058760","full_name":"lyst/django-urlconf-export","owner":"lyst","description":"Make URLs for your Django website from anywhere","archived":false,"fork":false,"pushed_at":"2021-04-08T19:01:33.000Z","size":713,"stargazers_count":5,"open_issues_count":2,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-30T12:31:52.078Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lyst.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-03-09T14:32:30.000Z","updated_at":"2024-06-25T14:21:29.000Z","dependencies_parsed_at":"2022-09-05T08:40:45.133Z","dependency_job_id":null,"html_url":"https://github.com/lyst/django-urlconf-export","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/lyst/django-urlconf-export","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lyst%2Fdjango-urlconf-export","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lyst%2Fdjango-urlconf-export/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lyst%2Fdjango-urlconf-export/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lyst%2Fdjango-urlconf-export/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lyst","download_url":"https://codeload.github.com/lyst/django-urlconf-export/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lyst%2Fdjango-urlconf-export/sbom","scorecard":{"id":607569,"data":{"date":"2025-08-11","repo":{"name":"github.com/lyst/django-urlconf-export","commit":"3095948f2480b327f709927bbd7ae6ae03151cfd"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.5,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/publish_to_pypi.yml:1","Warn: no topLevel permission defined: .github/workflows/run_tox_tests_and_lint.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Code-Review","score":0,"reason":"Found 0/20 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/publish_to_pypi.yml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/lyst/django-urlconf-export/publish_to_pypi.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/publish_to_pypi.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/lyst/django-urlconf-export/publish_to_pypi.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/run_tox_tests_and_lint.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/lyst/django-urlconf-export/run_tox_tests_and_lint.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/run_tox_tests_and_lint.yml:20: update your workflow using https://app.stepsecurity.io/secureworkflow/lyst/django-urlconf-export/run_tox_tests_and_lint.yml/master?enable=pin","Warn: pipCommand not pinned by hash: .github/workflows/publish_to_pypi.yml:23","Warn: pipCommand not pinned by hash: .github/workflows/publish_to_pypi.yml:24","Warn: pipCommand not pinned by hash: .github/workflows/run_tox_tests_and_lint.yml:25","Warn: pipCommand not pinned by hash: .github/workflows/run_tox_tests_and_lint.yml:26","Info:   0 out of   4 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   4 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENCE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENCE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 10 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"27 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: PYSEC-2024-48 / GHSA-fj7x-q9j7-g6q6","Warn: Project is vulnerable to: PYSEC-2022-42986 / GHSA-43fp-rhv2-5gv8","Warn: Project is vulnerable to: PYSEC-2023-135 / GHSA-xqr8-7jwr-rhp7","Warn: Project is vulnerable to: PYSEC-2021-98 / GHSA-68w8-qjq3-2gfm","Warn: Project is vulnerable to: GHSA-7xr5-9hcq-chf9","Warn: Project is vulnerable to: GHSA-8x94-hmjh-97hq","Warn: Project is vulnerable to: PYSEC-2021-99 / GHSA-p99v-5w3c-jqq9","Warn: Project is vulnerable to: PYSEC-2021-8 / GHSA-qm57-vhq3-3fwf","Warn: Project is vulnerable to: GHSA-rrqc-c2jx-6jgv","Warn: Project is vulnerable to: PYSEC-2021-7 / GHSA-rxjp-mfm9-w4wr","Warn: Project is vulnerable to: PYSEC-2021-439 / GHSA-v6rh-hp5x-86rv","Warn: Project is vulnerable to: PYSEC-2021-6 / GHSA-xgxc-v2qg-chmh","Warn: Project is vulnerable to: PYSEC-2021-109 / GHSA-xpfp-f569-q3p2","Warn: Project is vulnerable to: PYSEC-2024-60 / GHSA-jjg7-2v4v-x38h","Warn: Project is vulnerable to: PYSEC-2022-42969","Warn: Project is vulnerable to: GHSA-9hjg-9r4m-mvj7","Warn: Project is vulnerable to: GHSA-9wx4-h78v-vm56","Warn: Project is vulnerable to: PYSEC-2023-74 / GHSA-j8r2-6x86-q33q","Warn: Project is vulnerable to: GHSA-2m57-hf25-phgg","Warn: Project is vulnerable to: PYSEC-2021-333 / GHSA-p5w8-wqhj-9hhf","Warn: Project is vulnerable to: PYSEC-2023-87 / GHSA-rrm6-wvj7-cwh2","Warn: Project is vulnerable to: GHSA-34jh-p97f-mpxf","Warn: Project is vulnerable to: PYSEC-2023-212 / GHSA-g4mx-q9vg-27p4","Warn: Project is vulnerable to: GHSA-pq67-6m6q-mj2v","Warn: Project is vulnerable to: PYSEC-2021-108 / GHSA-q2q7-5pp4-w6pg","Warn: Project is vulnerable to: PYSEC-2023-192 / GHSA-v845-jxx5-vc9f","Warn: Project is vulnerable to: GHSA-jfmj-5v4g-7637"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-21T01:56:38.889Z","repository_id":53048971,"created_at":"2025-08-21T01:56:38.889Z","updated_at":"2025-08-21T01:56:38.889Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271754368,"owners_count":24815181,"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","status":"online","status_checked_at":"2025-08-23T02:00:09.327Z","response_time":69,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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-12T03:18:15.599Z","updated_at":"2025-08-23T15:07:29.670Z","avatar_url":"https://github.com/lyst.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Django URLconf Export\n\n![Django URLconf Export logo](https://github.com/lyst/django-urlconf-export/raw/master/logos/box-logo.jpg)\n\nDo you need to make URLs for your Django website in another microservice?\n\nThis used to be painful; you had to hard-code URL logic in multiple places.\n\nThis was messy and fragile, especially when URLs are translated to multiple languages.\n\nBut now, Django URLconf Export has solved this problem.\n\nIt exports your website URLconf in a JSON format, then imports it to any other Python service.\n\nSo you can make URLs for your website from anywhere, with no hassle, no repetition and no debt.\n\nSome example uses:\n\n* Email microservice that sends links to users.\n* Sitmaps generation microservice.\n* Microservice that buys paid ads for some website pages.\n\n## Video: 7 minute overview\n\n[![Link to short overview on YouTube](https://github.com/lyst/django-urlconf-export/raw/master/logos/video-link-720p.jpg)](https://youtu.be/3-9_6My5EWg)\n\n## Table of contents\n\n- [Django URLconf Export](https://github.com/lyst/django-urlconf-export#django-urlconf-export)\n  * [Video: 7 minute overview](https://github.com/lyst/django-urlconf-export#video-7-minute-overview)\n- [User Guide](https://github.com/lyst/django-urlconf-export#user-guide)\n  * [Installation](https://github.com/lyst/django-urlconf-export#installation)\n  * [Export URLconf as JSON](https://github.com/lyst/django-urlconf-export#export-urlconf-as-json)\n  * [Save URLconf to a file](https://github.com/lyst/django-urlconf-export#save-urlconf-to-a-file)\n    + [Example use-case](https://github.com/lyst/django-urlconf-export#example-use-case)\n  * [Serve URLconf from an endpoint](https://github.com/lyst/django-urlconf-export#serve-urlconf-from-an-endpoint)\n    + [Example use-case](https://github.com/lyst/django-urlconf-export#example-use-case-1)\n- [Integration](https://github.com/lyst/django-urlconf-export#integration)\n  * [Exporting from a Django service](https://github.com/lyst/django-urlconf-export#exporting-from-a-django-service)\n  * [Importing in a non-Django service](https://github.com/lyst/django-urlconf-export#importing-in-a-non-django-service)\n    + [Edge cases](https://github.com/lyst/django-urlconf-export#edge-cases)\n  * [Importing in a Django service with own URLs](https://github.com/lyst/django-urlconf-export#importing-in-a-django-service-with-own-urls)\n  * [Importing in a Django service with no URLs](https://github.com/lyst/django-urlconf-export#importing-in-a-django-service-with-no-urls)\n- [Feature Details](https://github.com/lyst/django-urlconf-export#feature-details)\n  * [Export whitelist and blacklist](https://github.com/lyst/django-urlconf-export#export-whitelist-and-blacklist)\n  * [Included URLs](https://github.com/lyst/django-urlconf-export#included-urls)\n  * [I18n URLs](https://github.com/lyst/django-urlconf-export#i18n-urls)\n  * [Export non-default root URLconf](https://github.com/lyst/django-urlconf-export#export-non-default-root-urlconf)\n  * [Quality assurance for i18n URLs](https://github.com/lyst/django-urlconf-export#quality-assurance-for-i18n-urls)\n    + [Check for translation errors in URL patterns](https://github.com/lyst/django-urlconf-export#check-for-translation-errors-in-url-patterns)\n    + [Ensure URL patterns use kwargs, not args](https://github.com/lyst/django-urlconf-export#ensure-url-patterns-use-kwargs-not-args)\n- [Development Guide](https://github.com/lyst/django-urlconf-export#development-guide)\n  * [Running tests](https://github.com/lyst/django-urlconf-export#running-tests)\n  * [Developing](https://github.com/lyst/django-urlconf-export#developing)\n  * [Changing test dependencies](https://github.com/lyst/django-urlconf-export#changing-test-dependencies)\n  * [Formatting imports and code](https://github.com/lyst/django-urlconf-export#formatting-imports-and-code)\n  * [Publishing to PyPi](https://github.com/lyst/django-urlconf-export#publishing-to-pypi)\n- [Further Development](https://github.com/lyst/django-urlconf-export#further-development)\n\n# User Guide\n\n## Installation\n\nThe package is called `django-urlconf-export`\n\nSome ways to install:\n\n```shell\npipenv install django-urlconf-export\n\npip install django-urlconf-export\n\npoetry add django-urlconf-export\n```\n\n## Export URLconf as JSON\n\nIf you have this URLconf:\n\n```Python\nurlpatterns = [\n    url(r\"^login/$\", View.as_view(), name=\"login\"),\n]\n```\n\nYou can run this code:\n\n```Python\nfrom django_urlconf_export import export_urlconf\n\nexport_urlconf.as_json()\n```\n\nYou will get this JSON:\n\n```Python\n[\n    {\"regex\": \"^login/$\", \"name\": \"login\"},\n]\n```\n\nThen somewhere else, you can import the JSON like this:\n\n```Python\nfrom django_urlconf_export import import_urlconf\n\nimport_urlconf.from_json(json_urlpatterns)\n```\n\nThen you can call `reverse` to make urls, just like normal:\n\n```Python\nreverse(\"login\") == \"/login/\"\n```\n\n\n## Save URLconf to a file\n\nIf you add `django_urlconf_export` to your website's `INSTALLED_APPS` you can run:\n\n```shell\ndjango-admin export_urlconf_to_file \u003e \"urlconf.json\"\n```\n\nTo create a file called `urlconf.json`\n\nThen you can import the file somewhere else like this:\n\n```python\nimport_urlconf.from_file(\"urlconf.json\")\n```\n\n### Example use-case\n\nAt Lyst, we have a skeleton repo that we share with digital agencies who create special pages for us like [The Year in Fashion](https://www.lyst.com/year-in-fashion-2019/). The repo is a stripped-down simulation of our production environment. Agencies develop pages for our website within the repo, so integration is easy.\n\nWe include a URLconf file in the skeleton repo. Before we did this, agencies used to hard-code URLs into their work. But now:\n\n* They can make URLs in the standard Django way.\n* The URLs are always correct; no silent errors.\n* The URLs are localised for all the languages we support.\n\n## Serve URLconf from an endpoint\n\nThis view returns URLconf JSON:\n\n```Python\nfrom django_urlconf_export.views.export import URLConfExportView\n\nurlpatterns = [\n    url(r\"^urlconf/\", URLConfExportView.as_view()),\n]\n```\n\nThen you can import from a URI like this:\n\n```Python\nimport_urlconf.from_uri(\"/urlconf/\")\n```\n\n### Example use-case\n\nA Lyst we have 3 services that make Lyst website urls:\n\n* An email service.\n* A sitemaps generation service.\n* A paid advertising purchasing service.\n\nThese services fetch URLconf from the Lyst website when they boot up, and update it periodically.\n\nSo when the URLs change, we don't need to update any service code. This is particularly helpful when we add a new language for our localised URLs.\n\n# Integration\n\n## Exporting from a Django service\n\nIn most situations, the best approach is to [serve URLconf from an endpoint](https://github.com/lyst/django-urlconf-export#serve-urlconf-from-an-endpoint).\n\nIn some situations, it might work better if you [save URLconf to a file](https://github.com/lyst/django-urlconf-export#save-urlconf-to-a-file).\n\nIf you have a specialised use-case that isn't handled by either of these approaches, You could roll your own core logic to [export URLconf as JSON](https://github.com/lyst/django-urlconf-export#export-urlconf-as-json).\n\nIf you roll a bespoke integration you think might be useful to others, please feel free to submit a PR.\n\n## Importing in a non-Django service\n\nYou can import URLconf and make URLs in any Python code.\n\nFirst, add Django as a dependency e.g. `pip install django`\n\nThen call `import_urlconf.init_django()` before you import any URLconf e.g.\n\n```python\nfrom django_urlconf_export import import_urlconf\n\nimport_urlconf.init_django()\n\nimport_urlconf.from_uri(\"https://www.example.com/urlconf/\")\n```\n\nThen you can call `reverse()` and make URLs for your website, just like in the website code.\n\n### Edge cases\n\nBy default, Django will be initialized with `settings.ROOT_URLCONF == \"imported_urlconf\"`\n\nThe module will be created when you import some urlconf.\n\nIf you need to set `settings.ROOT_URLCONF` to different module name, you can:\n\n```python\nimport_urlconf.init_django(ROOT_URLCONF=\"another_urlconf_module\")\n```\n\nYou can set any other Django settings this way too. \n\nSee [the source code](https://github.com/lyst/django-urlconf-export/blob/master/src/django_urlconf_export/import_urlconf.py) for the default Django settings.\n\n\n## Importing in a Django service with own URLs\n\nBy default, the library imports URLconf into the root URLconf module of the service - `settings.ROOT_URLCONF`. \n\nBut if the service has its own URLs, `settings.ROOT_URLCONF` will have some URLconf in it already.\n\nTo avoid overwriting the service's URLs, you can import to a different module with this Django setting:\n\n```python\nURLCONF_IMPORT_ROOT_URLCONF = \"imported_urlconf\"\n```\n\nOr you can add a `urlconf=\"...\"` argument when you import:\n\n```python\nimport_urlconf.from_file(\"urlconf.json\", urlconf=\"imported_urlconf\")\n```\n\nIf the module does not exist, it will be created - so you can call it anything you like.\n\nIf the module exists, any existing `urlpatterns` will be overwritten.\n\nThen you can make a url like:\n\n```python\nreverse(\"login\", urlconf=\"imported_urlconf\")\n```\n\nOr for convenience, you could make a `website_urls.py` module like this:\n\n```python\nfrom django import urls as django_urls\nfrom django.apps import AppConfig\nfrom django_urlconf_export import import_urlconf\n\n\nclass WebsiteURLsAppConfig(AppConfig):\n    name = \"website_urls\"\n    verbose_name = \"Make URLs for our website in any Django service.\"\n\n    def ready(self):\n        \"\"\"\n        When Django initializes, get the latest urlconf from our website.\n        \"\"\"\n        update_urlconf()\n\n\ndef update_urlconf():\n    \"\"\"\n    Download the latest urlconf from our website\n    \"\"\"\n    import_urlconf.from_uri(\"https://www.example.com/urlconf/\", urlconf=\"imported_urlconf\")\n\n\ndef reverse(*args, **kwargs):\n    \"\"\"\n    Thin wrapper for Django's reverse method, to make a URL for our website.\n    \"\"\"\n    return django_urls.reverse(*args, urlconf=\"imported_urlconf\", **kwargs)\n```\n\nAdding `\"website_urls.WebsiteURLsAppConfig\"` to `INSTALLED_APPS` in Django setting will import the URLconf when Django starts up.\n\nThen you can make URLs for your website by calling `website_urls.reverse(...)`\n\nIf you want to update the URLconf later, you can call `website_urls.update_urlconf()`.\n\n## Importing in a Django service with no URLs\n\nIf your Django service doesn't have any URLs of it's own, you can store imported URLconf in the default URLconf module - `settings.ROOT_URLCONF`.\n\nThis makes things a bit simpler. You could make a `website_urls.py` module like this:\n\n```python\nfrom django.apps import AppConfig\nfrom django_urlconf_export import import_urlconf\n\n\nclass WebsiteURLsAppConfig(AppConfig):\n    name = \"website_urls\"\n    verbose_name = \"Make URLs for our website in any Django service.\"\n\n    def ready(self):\n        \"\"\"\n        When Django initializes, get the latest urlconf from our website.\n        \"\"\"\n        update_urlconf()\n\n\ndef update_urlconf():\n    \"\"\"\n    Download the latest urlconf from our website\n    \"\"\"\n    import_urlconf.from_uri(\"https://www.example.com/urlconf/\")\n```\n\nAdding `\"website_urls.WebsiteURLsAppConfig\"` to `INSTALLED_APPS` in Django setting will import the URLconf when Django starts up.\n\nThen you can call `reverse()` and make URLs for your website, just like in the website code:\n\n```python\nfrom django.urls import reverse\n\nreverse(...)\n```\n\nIf you want to update the URLconf later, you can call `website_urls.update_urlconf()`.\n\n# Feature Details\n\nIf you prefer to read code than docs, the tests have examples of all feature details:\n\n* [export_urlconf tests](https://github.com/lyst/django-urlconf-export/blob/master/tests/django_urlconf_export/test_export_urlconf.py)\n* [import_urlconf tests](https://github.com/lyst/django-urlconf-export/blob/master/tests/django_urlconf_export/test_import_urlconf.py)\n\n## Export whitelist and blacklist\n\nBy default, all URLs will be exported. But you can set a whitelist and/or blacklist with these Django settings:\n\n```python\nURLCONF_EXPORT_WHITELIST = {\"only-show-this-url\"}\nURLCONF_EXPORT_BLACKLIST = {\"hide-this-url\", \"hide-this-one-too\"}\n```\n\nThe whitelist is applied first, then the blacklist.\n\nList items can be regexes, for example `\"secret-.\"` matches all URL names that start with `secret-` like `secret-page-1`, `secret-page-2` etc.\n\nThe whitelist and blacklist sets are a mixture of:\n\n* URL names\n* URL namespaces\n\nFor included URLs with a `namespace` (see [Django docs](https://docs.djangoproject.com/en/3.0/topics/http/urls/#url-namespaces)) like the Django admin urls, the `namespace` and the `url_name` must be _both_ be allowed by the lists. \n\nSo you can ban all URLs in the `admin` namespace with `blacklist = {\"admin\"}`.\n\nIf you want to export `admin:some-url` but no other `admin` URLs, set `whitelist = {\"admin\", \"some-url\"}`. \n\nNote: if you set `whitelist = {\"admin\"}` _no admin URLs will be exported_.\n\nSee the [unit tests](https://github.com/lyst/django-urlconf-export/blob/master/tests/django_urlconf_export/test_export_urlconf.py) for more examples.\n\nYou can check the whitelist and/or blacklist are working as expected like this:\n\n```python\nprint(export_urlconf.get_all_allowed_url_names())\n```\n\nYou can also set whitelist or blacklist explicitly when exporting as JSON:\n\n```Python\nexport_urlconf.as_json(\n    whitelist={\"only-show-this-url\"},\n    blacklist={\"hide-this-url\", \"hide-this-one-too\"}\n)\n```\n\nOr when generating a file:\n\n```shell\ndjango-admin export_urlconf_to_file \\\n        --whitelist 'only-show-this-url' \\\n        --blacklist 'hide-this-url\", \"hide-this-one-too' \\\n        \u003e urlconf.json\n```\n\nOr when serving from an endpoint:\n\n```Python\nurlpatterns = [\n    url(r\"^urlconf/\", URLConfExportView.as_view(\n        whitelist={\"only-show-this-url\"},\n        blacklist={\"hide-this-url\", \"hide-this-one-too\"}\n    )),\n]\n```\n\n## Included URLs\n\nWe fully support included URLconf. The JSON looks like:\n\n```python\n{\n    \"regex\": \"^colors/\",\n    \"namespace\": None,\n    \"app_name\": None,\n    \"includes\": [\n        {\"regex\": \"^red/$\", \"name\": \"red\"},\n        {\"regex\": \"^blue/$\", \"name\": \"blue\"}\n    ],\n}\n```\n\n## I18n URLs\n\nWe fully support internationalized URLs. \n\nThe JSON looks like:\n\n```python\n{\n    \"regex\": {\n        \"en-us\": \"^color/$\",\n        \"en-gb\": \"^colour/$\",\n        \"fr-fr\": \"^couleur/$\"\n    },\n    \"name\": \"color\"\n}\n```\n\n---\n\nSome websites (e.g. Lyst) only localise URLs at the language-family level.\n\nFor example, `en` rather than `en-us` and `en-gb`.\n\nIf you set this Django setting:\n\n```python\nURLCONF_EXPORT_LANGUAGE_WITHOUT_COUNTRY = True\n```\n\nThen you get JSON like:\n\n```python\n{\n    \"regex\": {\n        \"en\": \"^color/$\",\n        \"fr\": \"^couleur/$\"\n    },\n    \"name\": \"color\"\n}\n```\n\nYou can also add an argument when exporting as JSON:\n\n```Python\nexport_urlconf.as_json(language_without_country=True)\n```\n\nOr when generating a file:\n\n```shell\ndjango-admin export_urlconf_to_file --language-without-country \u003e urlconf.json\n```\n\nOr when serving from an endpoint:\n\n```Python\nurlpatterns = [\n    url(r\"^urlconf/\", URLConfExportView.as_view(language_without_country=True)),\n]\n```\n\n---\n\nWe support the `LocalePrefixPattern` (see [Django docs](https://docs.djangoproject.com/en/3.0/topics/i18n/translation/#language-prefix-in-url-patterns).\n\nSo if you have URLconf like:\n\n```python\nfrom django.conf.urls.i18n import i18n_patterns\n\nurlpatterns = i18n_patterns(\n    url(r\"^$\", View.as_view(), name=\"index\"),\n)\n```\n\nYou get JSON like:\n\n```python\n{\n    \"isLocalePrefix\": True,\n    \"classPath\": \"django.urls.resolvers.LocalePrefixPattern\",\n    \"includes\": [\n        {\"regex\": \"^$\", \"name\": \"index\"}\n    ],\n}\n```\n\nNote that `classPath` is saved in the JSON. So if (like Lyst) your project uses a subclass of Django's `LocalePrefixPattern` it will work.\n\n## Export non-default root URLconf\n\nBy default, we export the root URLconf module that creates the endpoints of your Django website: `settings.ROOT_URLCONF`. This is almost always what you want.\n\nIf you need to export from a different root URLconf module, you can use this Django setting:\n\n```python\nURLCONF_EXPORT_ROOT_URLCONF = \"path.to.non_default_root_urlconf\"\n```\n\nOr when exporting as JSON:\n\n```Python\nexport_urlconf.as_json(\"path.to.non_default_root_urlconf\")\n```\n\nOr when generating a file:\n\n```shell\ndjango-admin export_urlconf_to_file \\\n        --urlconf 'path.to.non_default_root_urlconf' \\\n        \u003e urlconf.json\n```\n\nOr when serving from an endpoint:\n\n```Python\nurlpatterns = [\n    url(r\"^urlconf/\", URLConfExportView.as_view(\n        urlconf=\"path.to.non_default_root_urlconf\",\n    )),\n]\n```\n\n## Quality assurance for i18n URLs\n\nThis library is particularly useful if you have internationalized URLs.\n\nWe provide some methods to help ensure URLs are translated correctly.\n\n### Check for translation errors in URL patterns\n\nIf you want to check that URL pattern kwargs are the same for all translations of a URL, you can add a unit test to your project like:\n\n```python\nfrom django_urlconf_export import urlconf_qa\n\ndef test_for_url_translation_errors():\n    urlconf_qa.assert_url_kwargs_are_the_same_for_all_languages()\n```\n\n### Ensure URL patterns use kwargs, not args\n\nDjango allows you to make URL patterns that have positional arguments (`args`) and/or named keyword arguments (`kwargs`).\n\nThis flexibility can lead to confusion, particularly in large teams. So it can be helpful to ensure developers only use `kwargs` and not `args`.\n\nIt's also less error-prone to translate URLs that use `kwargs`, because translators are free to change the order of `kwargs` in the URL to match the word order in their language.\n\nFor example, at Lyst we have URLs like:\n\n|         | Example URL   | Localised URL Pattern                         |\n|---------|---------------|-----------------------------------------------|\n| English | `/gucci-bags` | `/(?P\u003cdesigner_name\u003e.+)-(?P\u003cproduct_type\u003e.+)` |\n| French  | `/sacs-gucci` | `/(?P\u003cproduct_type\u003e.+)-(?P\u003cdesigner_name\u003e.+)` |\n\nTo enforce that URL patterns always use `kwargs` and not `args`, add a test like this:\n\n```python\nfrom django_urlconf_export import urlconf_qa\n\ndef test_all_urls_use_kwargs():\n    urlconf_qa.assert_all_urls_use_kwargs_not_args()\n```\n\n# Development Guide\n\n## Running tests\n\n`pip install tox` (or `pip3 install tox`)\n \nThen run `tox`\n\n## Developing\n\n`pip install --user pipenv` (or `pip3 install --user pipenv`)\n\nThen run:\n \n* `pipenv install`\n* `pipenv shell`\n* `exit`\n* `pipenv --venv`\n\nThe location of the virtual environment will be displayed.\n\nHere is a [guide for using this venv in PyCharm](https://stackoverflow.com/a/50749980/3048733).\n\n## Changing test dependencies\n\nYou need to `pipenv install {new-dependency}` and also add the dependency in `tox.ini`.\n\n## Formatting imports and code\n\nFirst run `pipenv shell`\n\nThen run:\n\n* `isort` - format imports\n* `black src/ tests/` - format code\n\nThen `exit` to quit the shell.\n\n## Publishing to PyPi\n\nCreate a new release, and the package will be published automatically by a GitHub action. \n\n# Further Development\n\nIt would be cool if we could make URLs in JavaScript using the JSON generated by this library. Then we could make URLs on the front-end, and in Node services.\n\nLyst are not working on this at the moment. If this feature would be useful to you, a PR would be very welcome :)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flyst%2Fdjango-urlconf-export","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flyst%2Fdjango-urlconf-export","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flyst%2Fdjango-urlconf-export/lists"}