├── .github └── workflows │ └── publish.yml ├── .gitignore ├── LICENSE ├── README.md ├── django_urls └── __init__.py └── setup.py /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | publish: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v3 14 | 15 | - name: Set up Python 16 | uses: actions/setup-python@v4 17 | with: 18 | python-version: '3.12' 19 | 20 | - name: Install build tools 21 | run: | 22 | python -m pip install --upgrade pip setuptools wheel build 23 | 24 | - name: Build package 25 | run: | 26 | python -m build 27 | 28 | - name: Publish to PyPI 29 | uses: pypa/gh-action-pypi-publish@release/v1 30 | with: 31 | username: __token__ 32 | password: ${{ secrets.PYPI_TOKEN }} 33 | packages-dir: dist 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | 53 | # Translations 54 | *.mo 55 | *.pot 56 | 57 | # Django stuff: 58 | *.log 59 | local_settings.py 60 | db.sqlite3 61 | db.sqlite3-journal 62 | 63 | # Flask stuff: 64 | instance/ 65 | .webassets-cache 66 | 67 | # Scrapy stuff: 68 | .scrapy 69 | 70 | # Sphinx documentation 71 | docs/_build/ 72 | 73 | # PyBuilder 74 | target/ 75 | 76 | # Jupyter Notebook 77 | .ipynb_checkpoints 78 | 79 | # IPython 80 | profile_default/ 81 | ipython_config.py 82 | 83 | # pyenv 84 | .python-version 85 | 86 | # pipenv 87 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 88 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 89 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 90 | # install all needed dependencies. 91 | #Pipfile.lock 92 | 93 | # celery beat schedule file 94 | celerybeat-schedule 95 | 96 | # SageMath parsed files 97 | *.sage.py 98 | 99 | # Environments 100 | .env 101 | .venv 102 | env/ 103 | venv/ 104 | ENV/ 105 | env.bak/ 106 | venv.bak/ 107 | 108 | # Spyder project settings 109 | .spyderproject 110 | .spyproject 111 | 112 | # Rope project settings 113 | .ropeproject 114 | 115 | # mkdocs documentation 116 | /site 117 | 118 | # mypy 119 | .mypy_cache/ 120 | .dmypy.json 121 | dmypy.json 122 | 123 | # Pycharm 124 | .idea/ 125 | 126 | # Pyre type checker 127 | .pyre/ 128 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![PyPI - License](https://img.shields.io/pypi/l/django-urls.svg)](https://pypi.org/project/django-urls/) 2 | [![PyPI - Downloads](https://img.shields.io/pypi/dm/django-urls.svg)](https://pypi.org/project/django-urls/) 3 | 4 | ## What is *django_urls*? 5 | 6 | It is flask style urls for django. 7 | 8 | ## How to use it? 9 | 10 | ```python 11 | # app/urls.py or where-ever you want really. 12 | from django_urls import UrlManager 13 | app_urls = UrlManager(views_root='dotted.path.to.app.views.module') 14 | 15 | app_urls.extend(extra_urls_list) 16 | ``` 17 | 18 | ```python 19 | # app/views/foo.py 20 | 21 | from app.urls import app_urls 22 | 23 | @app_urls.path('path/', name='MyView', importance=5) # the bigger the importance higher in the list it goes 24 | class MyView(View): 25 | ... 26 | 27 | @app_urls.re_path('path2/', name='my_view', importance=1) 28 | def my_view(request): 29 | ... 30 | ``` 31 | 32 | ```python 33 | # project/urls.py 34 | from django.urls import include, path 35 | from app.urls import app_urls 36 | 37 | url_patterns = [ 38 | path('some_path/', include(app_urls.url_patterns)) 39 | ] 40 | ``` 41 | 42 | 43 | That's it, not too much setup, right? 44 | -------------------------------------------------------------------------------- /django_urls/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | from glob import glob 3 | from importlib import import_module 4 | 5 | from django.urls import re_path as _re_path, path as _path 6 | 7 | 8 | def _glob_init(name): 9 | name = name.replace(".", os.sep) 10 | path = os.sep + "**" 11 | modules = [] 12 | for module in glob(name + path, recursive=True): 13 | importable = os.path.splitext(module)[0].replace(os.sep, ".").rstrip(".") 14 | if "__" in importable: 15 | continue 16 | module = import_module(importable) 17 | modules.append(module) 18 | return modules 19 | 20 | 21 | class UrlManager: 22 | def __init__(self, views_root=None): 23 | self.views_root = views_root 24 | self._url_patterns = [] 25 | 26 | def _path(self, route, kwargs=None, name=None, is_re=None, importance=0): 27 | importance = int(importance) 28 | func = _re_path if is_re else _path 29 | 30 | def decorator(view): 31 | _view = view # keep the original view 32 | if isinstance(view, type): 33 | view = view.as_view() 34 | self._url_patterns.append( 35 | (func(route, view, kwargs=kwargs, name=name or view.__name__), importance) 36 | ) 37 | return _view 38 | 39 | return decorator 40 | 41 | def path(self, route, kwargs=None, name=None, importance=0): 42 | return self._path(route, kwargs=kwargs, name=name, is_re=False, importance=importance) 43 | 44 | def re_path(self, route, kwargs=None, name=None, importance=0): 45 | return self._path(route, kwargs=kwargs, name=name, is_re=True, importance=importance) 46 | 47 | def extend(self, urlpatterns): 48 | self._url_patterns.extend(urlpatterns) 49 | return self._url_patterns 50 | 51 | @property 52 | def url_patterns(self): 53 | if self.views_root: 54 | if isinstance(self.views_root, str): 55 | _glob_init(self.views_root) 56 | else: 57 | for root in self.views_root: 58 | _glob_init(root) 59 | return list(i[0] for i in sorted(self._url_patterns, key=lambda x: x[1])) 60 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | with open('README.md') as f: 4 | long_description = f.read() 5 | 6 | setup( 7 | name='django_urls', 8 | version='1.1.4', 9 | packages=['django_urls'], 10 | url='https://github.com/isik-kaplan/django_urls', 11 | description="URL decorator for django views", 12 | long_description=long_description, 13 | long_description_content_type="text/markdown", 14 | license='MIT LICENSE', 15 | author='isik-kaplan', 16 | author_email='', 17 | python_requires=">=3.5", 18 | install_requires=['django>=2.0'], 19 | classifiers=[ 20 | 'License :: OSI Approved :: MIT License', 21 | 'Programming Language :: Python :: 3', 22 | 'Framework :: Django', 23 | 'Development Status :: 5 - Production/Stable', 24 | ], 25 | ) 26 | --------------------------------------------------------------------------------