跳转到主要内容

从任何地方为您的网站创建URL。

项目描述

Django URLconf 导出

Django URLconf Export logo

您需要在另一个微服务中为Django网站创建URL吗?

这曾经是个痛苦的过程;您不得不在多个地方硬编码URL逻辑。

这很混乱且脆弱,尤其是当URL翻译为多种语言时。

但现在,Django URLconf 导出已解决了这个问题。

它以JSON格式导出您的网站URLconf,然后将其导入到任何其他Python服务中。

因此,您可以从任何地方轻松创建网站URL,没有任何麻烦、重复和债务。

一些示例用途

  • 发送链接到用户的电子邮件微服务。
  • 生成sitmaps的微服务。
  • 为某些网站页面购买付费广告的微服务。

视频:7分钟概览

Link to short overview on YouTube

目录

用户指南

安装

该软件包名称为 django-urlconf-export

一些安装方法

pipenv install django-urlconf-export

pip install django-urlconf-export

poetry add django-urlconf-export

将URLconf导出为JSON

如果您有此URLconf

urlpatterns = [
    url(r"^login/$", View.as_view(), name="login"),
]

您可以运行此代码

from django_urlconf_export import export_urlconf

export_urlconf.as_json()

您将得到此JSON

[
    {"regex": "^login/$", "name": "login"},
]

然后在某个地方,您可以像这样导入JSON

from django_urlconf_export import import_urlconf

import_urlconf.from_json(json_urlpatterns)

然后您可以通过调用 reverse 来创建URL,就像平常一样

reverse("login") == "/login/"

将URLconf保存到文件

如果您将 django_urlconf_export 添加到您网站的 INSTALLED_APPS 中,您可以运行

django-admin export_urlconf_to_file > "urlconf.json"

创建一个名为 urlconf.json 的文件

然后您可以在其他地方像这样导入文件

import_urlconf.from_file("urlconf.json")

示例用例

在Lyst,我们有一个共享的骨架仓库,我们与为我们的网站创建特殊页面的数字机构共享,例如 2019年时尚年度。该仓库是我们生产环境的简化模拟。机构在仓库内为我们网站开发页面,因此集成变得容易。

我们在骨架仓库中包含一个URLconf文件。在我们这样做之前,机构通常会将URL硬编码到他们的工作中。但现在

  • 他们可以以标准的Django方式创建URL。
  • URL始终正确;没有静默错误。
  • URL已经为所有我们支持的语言进行了本地化。

从端点提供URLconf

此视图返回URLconf JSON

from django_urlconf_export.views.export import URLConfExportView

urlpatterns = [
    url(r"^urlconf/", URLConfExportView.as_view()),
]

然后您可以像这样从URI导入

import_urlconf.from_uri("/urlconf/")

示例用例

在Lyst,我们有3个服务生成Lyst网站URL

  • 电子邮件服务。
  • 网站地图生成服务。
  • 付费广告购买服务。

这些服务在启动时从Lyst网站获取URLconf,并定期更新。

因此,当URL发生变化时,我们不需要更新任何服务代码。这在我们为本地化URL添加新语言时特别有用。

集成

从Django服务导出

在大多数情况下,最佳做法是从端点提供URLconf

在某些情况下,如果您将URLconf保存到文件,可能效果更好。

如果您有这些方法都无法处理的专业用例,您可以自行实现核心逻辑以将URLconf导出为JSON

如果您开发的自定义集成可能对他人有用,请随时提交PR。

在非Django服务中导入

您可以在任何Python代码中导入URLconf并创建URL。

首先,将Django作为依赖项添加,例如 pip install django

然后在导入任何URLconf之前调用 import_urlconf.init_django(),例如。

from django_urlconf_export import import_urlconf

import_urlconf.init_django()

import_urlconf.from_uri("https://www.example.com/urlconf/")

然后您可以通过调用 reverse 来为您的网站创建URL,就像在网站代码中一样。

边缘情况

默认情况下,Django将与 settings.ROOT_URLCONF == "imported_urlconf" 初始化

在导入一些urlconf时将创建该模块。

如果您需要将 settings.ROOT_URLCONF 设置为不同的模块名称,您可以通过以下方式设置

import_urlconf.init_django(ROOT_URLCONF="another_urlconf_module")

您也可以以这种方式设置其他Django设置。

有关默认Django设置的源代码,请参阅源代码

在具有自定义URL的Django服务中导入

默认情况下,库将URLconf导入到服务的根URLconf模块 - settings.ROOT_URLCONF

但如果服务有自己的URL,settings.ROOT_URLCONF 中可能已经包含了一些URLconf。

为了避免覆盖服务URL,您可以通过此Django设置导入不同的模块

URLCONF_IMPORT_ROOT_URLCONF = "imported_urlconf"

或者您可以在导入时添加一个 urlconf="..." 参数

import_urlconf.from_file("urlconf.json", urlconf="imported_urlconf")

如果模块不存在,则会自动创建,因此您可以随意命名。

如果模块已存在,现有的 urlpatterns 将会被覆盖。

然后您可以创建一个类似的 URL

reverse("login", urlconf="imported_urlconf")

或者为了方便,您可以创建一个如下的 website_urls.py 模块

from django import urls as django_urls
from django.apps import AppConfig
from django_urlconf_export import import_urlconf


class WebsiteURLsAppConfig(AppConfig):
    name = "website_urls"
    verbose_name = "Make URLs for our website in any Django service."

    def ready(self):
        """
        When Django initializes, get the latest urlconf from our website.
        """
        update_urlconf()


def update_urlconf():
    """
    Download the latest urlconf from our website
    """
    import_urlconf.from_uri("https://www.example.com/urlconf/", urlconf="imported_urlconf")


def reverse(*args, **kwargs):
    """
    Thin wrapper for Django's reverse method, to make a URL for our website.
    """
    return django_urls.reverse(*args, urlconf="imported_urlconf", **kwargs)

"website_urls.WebsiteURLsAppConfig" 添加到 Django 设置中的 INSTALLED_APPS,当 Django 启动时将导入 URLconf。

然后您可以调用 website_urls.reverse(...) 来为您的网站创建 URL。

如果您稍后想更新 URLconf,可以调用 website_urls.update_urlconf()

在没有URL的Django服务中导入

如果您的 Django 服务没有自己的 URL,可以将导入的 URLconf 存储在默认 URLconf 模块中 - settings.ROOT_URLCONF

这使事情变得简单一些。您可以创建一个如下的 website_urls.py 模块

from django.apps import AppConfig
from django_urlconf_export import import_urlconf


class WebsiteURLsAppConfig(AppConfig):
    name = "website_urls"
    verbose_name = "Make URLs for our website in any Django service."

    def ready(self):
        """
        When Django initializes, get the latest urlconf from our website.
        """
        update_urlconf()


def update_urlconf():
    """
    Download the latest urlconf from our website
    """
    import_urlconf.from_uri("https://www.example.com/urlconf/")

"website_urls.WebsiteURLsAppConfig" 添加到 Django 设置中的 INSTALLED_APPS,当 Django 启动时将导入 URLconf。

然后您可以调用 reverse() 并为您的网站创建 URL,就像在网站代码中一样

from django.urls import reverse

reverse(...)

如果您稍后想更新 URLconf,可以调用 website_urls.update_urlconf()

功能详情

如果您喜欢阅读代码而不是文档,测试中包含了所有功能细节的示例

导出白名单和黑名单

默认情况下,所有 URL 都会被导出。但您可以使用这些 Django 设置设置白名单和/或黑名单

URLCONF_EXPORT_WHITELIST = {"only-show-this-url"}
URLCONF_EXPORT_BLACKLIST = {"hide-this-url", "hide-this-one-too"}

首先应用白名单,然后应用黑名单。

列表项可以是正则表达式,例如 "secret-." 匹配所有以 secret- 开头的 URL 名称,如 secret-page-1secret-page-2 等。

白名单和黑名单集合是 URL 名称、URL 命名空间的混合

  • URL 名称
  • URL 命名空间

对于包含 namespace(请参阅 Django 文档)的 URL,例如 Django 管理员 URL,列表必须同时允许 namespaceurl_name

因此,您可以使用 blacklist = {"admin"} 禁止 admin 命名空间中的所有 URL。

如果您想导出 admin:some-url 但不导出其他 admin URL,请设置 whitelist = {"admin", "some-url"}

注意:如果您设置 whitelist = {"admin"},则 不会导出任何管理员 URL

有关更多示例,请参阅 单元测试

您可以通过这种方式检查白名单和/或黑名单是否按预期工作

print(export_urlconf.get_all_allowed_url_names())

您也可以在导出为 JSON 时显式设置白名单或黑名单

export_urlconf.as_json(
    whitelist={"only-show-this-url"},
    blacklist={"hide-this-url", "hide-this-one-too"}
)

或者当生成文件时

django-admin export_urlconf_to_file \
        --whitelist 'only-show-this-url' \
        --blacklist 'hide-this-url", "hide-this-one-too' \
        > urlconf.json

或者当从端点提供服务时

urlpatterns = [
    url(r"^urlconf/", URLConfExportView.as_view(
        whitelist={"only-show-this-url"},
        blacklist={"hide-this-url", "hide-this-one-too"}
    )),
]

包含的URL

我们完全支持包含的 URLconf。JSON 看起来像这样

{
    "regex": "^colors/",
    "namespace": None,
    "app_name": None,
    "includes": [
        {"regex": "^red/$", "name": "red"},
        {"regex": "^blue/$", "name": "blue"}
    ],
}

I18n URL

我们完全支持国际化 URL。

JSON 看起来像这样

{
    "regex": {
        "en-us": "^color/$",
        "en-gb": "^colour/$",
        "fr-fr": "^couleur/$"
    },
    "name": "color"
}

一些网站(例如 Lyst)只在语言家族级别本地化 URL。

例如,使用 en 而不是 en-usen-gb

如果您设置此 Django 设置

URLCONF_EXPORT_LANGUAGE_WITHOUT_COUNTRY = True

则得到如下 JSON

{
    "regex": {
        "en": "^color/$",
        "fr": "^couleur/$"
    },
    "name": "color"
}

您还可以在导出为 JSON 时添加一个参数

export_urlconf.as_json(language_without_country=True)

或者当生成文件时

django-admin export_urlconf_to_file --language-without-country > urlconf.json

或者当从端点提供服务时

urlpatterns = [
    url(r"^urlconf/", URLConfExportView.as_view(language_without_country=True)),
]

我们支持 LocalePrefixPattern(请参阅 Django 文档)。

因此,如果您有如下的 URLconf

from django.conf.urls.i18n import i18n_patterns

urlpatterns = i18n_patterns(
    url(r"^$", View.as_view(), name="index"),
)

则得到如下 JSON

{
    "isLocalePrefix": True,
    "classPath": "django.urls.resolvers.LocalePrefixPattern",
    "includes": [
        {"regex": "^$", "name": "index"}
    ],
}

请注意,classPath 被保存在 JSON 中。因此,如果(像 Lyst 一样)您的项目使用 Django 的 LocalePrefixPattern 的子类,它将正常工作。

导出非默认根URLconf

默认情况下,我们导出创建 Django 网站端点的根 URLconf 模块:settings.ROOT_URLCONF。这几乎总是您想要的。

如果您需要从不同的根 URLconf 模块导出,可以使用此 Django 设置

URLCONF_EXPORT_ROOT_URLCONF = "path.to.non_default_root_urlconf"

或者当导出为 JSON 时

export_urlconf.as_json("path.to.non_default_root_urlconf")

或者当生成文件时

django-admin export_urlconf_to_file \
        --urlconf 'path.to.non_default_root_urlconf' \
        > urlconf.json

或者当从端点提供服务时

urlpatterns = [
    url(r"^urlconf/", URLConfExportView.as_view(
        urlconf="path.to.non_default_root_urlconf",
    )),
]

I18n URL的质量保证

此库在您有国际化 URL 时特别有用。

我们提供了一些方法来帮助确保 URL 正确翻译。

检查URL模式中的翻译错误

如果您想检查 URL 模式 kwargs 对于 URL 的所有翻译都是相同的,您可以在项目中添加一个单元测试

from django_urlconf_export import urlconf_qa

def test_for_url_translation_errors():
    urlconf_qa.assert_url_kwargs_are_the_same_for_all_languages()

确保URL模式使用kwargs,而不是args

Django 允许您创建具有位置参数(args)和/或命名关键字参数(kwargs)的 URL 模式。

这种灵活性可能会导致混淆,尤其是在大型团队中。因此,确保开发人员只使用 kwargs 而不是 args 可能很有帮助。

将使用kwargs的URL进行翻译也更容易避免错误,因为翻译者可以自由地更改URL中kwargs的顺序以匹配其语言中的单词顺序。

例如,在Lyst,我们有如下URL:

示例URL 本地化URL模式
英语 /gucci-bags /(?P.+)-(?P.+)
法语 /sacs-gucci /(?P.+)-(?P.+)

为了强制URL模式始终使用kwargs而不是args,请添加如下测试:

from django_urlconf_export import urlconf_qa

def test_all_urls_use_kwargs():
    urlconf_qa.assert_all_urls_use_kwargs_not_args()

开发指南

运行测试

pip install tox(或pip3 install tox

然后运行tox

开发

pip install --user pipenv(或pip3 install --user pipenv

然后运行

  • pipenv install
  • pipenv shell
  • 退出
  • pipenv --venv

将显示虚拟环境的位置。

这是在PyCharm中使用此venv的指南

更改测试依赖

您需要运行pipenv install {new-dependency},并在tox.ini中添加依赖项。

格式化导入和代码

首先运行pipenv shell

然后运行

  • isort - 格式化导入
  • black src/ tests/ - 格式化代码

然后运行exit退出shell。

发布到PyPi

创建一个新版本,该包将自动通过GitHub操作发布。

进一步开发

如果能够使用此库生成的JSON在JavaScript中创建URL会很好。这样我们就可以在前端和在Node服务中创建URL。

Lyst目前没有在这方面工作。如果这个功能对您有用,非常欢迎您提交PR :)

项目详情


下载文件

下载适合您平台的文件。如果您不确定选择哪个,请了解更多关于安装包的信息。

源代码发行版

django-urlconf-export-1.1.1.tar.gz (676.3 kB 查看哈希值)

上传时间:

构建发行版

django_urlconf_export-1.1.1-py3-none-any.whl (16.3 kB 查看哈希值)

上传时间: Python 3

由以下支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误日志 StatusPage StatusPage 状态页面