diff options
author | CoprDistGit <infra@openeuler.org> | 2023-06-20 07:05:08 +0000 |
---|---|---|
committer | CoprDistGit <infra@openeuler.org> | 2023-06-20 07:05:08 +0000 |
commit | ba1a540665a2e98410e15e7366034f8c2fb7e914 (patch) | |
tree | 05310f5e8e88e8430b5dd5dde08c8365bff1f221 /python-django-url-framework.spec | |
parent | 4cf550a28e981bd613063586930894f35758a708 (diff) |
automatic import of python-django-url-frameworkopeneuler20.03
Diffstat (limited to 'python-django-url-framework.spec')
-rw-r--r-- | python-django-url-framework.spec | 1599 |
1 files changed, 1599 insertions, 0 deletions
diff --git a/python-django-url-framework.spec b/python-django-url-framework.spec new file mode 100644 index 0000000..269227d --- /dev/null +++ b/python-django-url-framework.spec @@ -0,0 +1,1599 @@ +%global _empty_manifest_terminate_build 0 +Name: python-django-url-framework +Version: 0.6.0 +Release: 1 +Summary: Automagically discover urls in a django application, similar to the Ruby on Rails Controller/Action/View implementation. +License: MIT +URL: https://github.com/zeraien/django-url-framework/ +Source0: https://mirrors.aliyun.com/pypi/web/packages/06/fc/b10ba8ac609dcb79c58ef433d462d7c042d82df2b172fd081ed5808387db/django-url-framework-0.6.0.tar.gz +BuildArch: noarch + + +%description +The django-url-framework will help you get your django applications done faster. + + +[](https://django-url-framework.readthedocs.io/en/latest/?badge=latest) +[](https://gitter.im/zeraien/django-url-framework?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + +It automatically detects urls in a django application, similar to the way Ruby on Rails does it with the Controller-Action-View implementation. + +Controllers are created in each django application with a predefined file naming scheme (`foo_controller.py`) and extending `ActionController`. The `ActionController` contains methods often used in a web context, and does common request-related processing. + +Each application can have multiple controllers thus allowing for smaller classes in a larger application. + +Each function not starting with an underscore becomes it's own action. By simply returning a dictionary from the action, it will be rendered with the template named using the `controller/action.html` naming scheme. + +Each action and controller can override certain global settings such as using a custom template name or giving the action (or controller) a custom name. + +## Install + +From pypi: + +``` +pip install django-url-framework +``` + +Alternatively just check out the source here and run `python setup.py install` or `pip install .` + +## Add to your project + +### settings.py + +```python +INSTALLED_APPS = ( + ..., + 'django_url_framework', + ... +) +``` +### urls.py +```python +import django_url_framework +from django.conf import settings +from django.conf.urls import patterns, include + +django_url_framework.site.autodiscover(new_inflection_library=True) + +urlpatterns = patterns('', + (r'^', include(django_url_framework.site.urls) ), +) +``` + +## Example + +### Folder structure + +``` +project/ + app/ + cart_controller.py + id_controller.py + templates/ + cart/ + add.html + index.html + remove.html + id_manager/ + bar.html +``` + +### cart_controller.py + +```python +from django_url_framework.controller import ActionController + +class CartController(ActionController): + def edit(self, request, id = None): + return {} + def remove(self, request, id): + return {} + def index(self, request): + return {} +``` + +### id_controller.py + +```python +from django_url_framework.controller import ActionController + +class IDManagerController(ActionController): + def index(self, request, object_id = None): + return {} + def bar(self, request): + return {} + def bar__delete(self, request): + return {} +``` + +### Result + +The following URLs will be created: + +``` +/cart/ <- will go to *index action* +/cart/(\w+)/ +/cart/edit/ +/cart/edit/(\w+)/ +/cart/remove/(\w+)/ +/foo/ +/foo/(\w+)/ +/foo/bar/ +/foo/bar/delete/ +``` + +You can easily access your URLs using django's built-in `{% url ... %}` tag. Simply call `{% url cart_index %}` or `{% url cart_delete id %}` and it will work as you would expect. + +There is also a helper tag for faster linking within the same controller. +`{% go_action remove %}` will take you to `/cart/remove/`. To use it, `{% load url_framework %}` in your templates. + +The names of the controller files do not affect your URLs, however, the files must have `_controller.py` suffix. The URL name of the controller is derived from the class name, minus the Controller part. You can also manually specify controller names using the `controller_name` attribute on the controller class. + +### Controller names + +The controller name is derived from it's class name, by converting camelcase into underscores. +For instance `FooController` is simple `foo`, while `FooBarController` becomes `foo_bar`. + +The latest version uses the `inflection` library, however to avoid breaking old code, this is still optional until 2021. + +The biggest difference is that with `inflection`, `HTTPResponse` becomes `http_response`, while the old name would be `httpresponse`. I suggest enabling the `inflection` library for all new and existing projects. You can manually specify names for controllers whose name change would break your code, or disable the inflection library for those controllers using a flag. + +You can give the controller a custom name with the `controller_name` parameter: +```python +class Controller(ActionController): + controller_name = "foo" +``` + +Enable or disable the use of the new `inflection` library using a flag +```python +class Controller(ActionController): + use_inflection_library = True +``` + +### Other useful controller settings + +```python +class BarController(ActionController): + + # default filename extension for all templates + template_extension = "pug" + + # will require every template file to start with this string + template_prefix = "foo_" + + # will not look for templates in subdirectories, but in the root templates/ folder + no_subdirectories = False + + # do not prefix templates with `_` (underscore) when they are called using an AJAX request + no_ajax_prefix = False + + # Set a prefix for the controller's name, applies even if + # you set controller_name (template name is based on controller_name, sans prefix) + # NOTE: The urlconf name will not include the prefix, only the actual URL itself + # Thus: FooController.list will have the URL /prefixed_foo/list/, but the url name will be + # `foo_list`. + controller_prefix = "prefixed_" + + # completely override the name of the controller + controller_name = "shopping_cart" + + # When used with custom urlconf in actions, these arguments will not be passed to the action + # example: "/<id:int>/<skip:bool>/" Only `id` will be passed to the `action`, while `skip` will not be. + consume_urlconf_keyword_arguments = ['skip'] + + # set a prefix for all the URLs in this controller + # So, what normally would be `/controller/action/`, becomes `^prefix/controller/action/` + urlconf_prefix:list = ["^prefix"] + + # A custom json encoder, subclassing JSONEncoder + json_default_encoder:JSONEncoder = None + + # use the yaml default flow style + yaml_default_flow_style:bool = True + + # use the new inflection library to generate controller url + # if this is None, will use the global setting, otherwise override this on a per controller basis + use_inflection_library:Union[bool,None] = None + +``` + +### Template filenames + +By default templates are stored in the subdirectory with the controller's name, and the templates are given the same filename as the action name. +If a request is determinned to be AJAX in nature, the template filename is prefixed with an underscore. +Example: +```python +class FooController(ActionController): + def foo_action(self, request): + return {} +``` + +File structure: +```python +/foo/foo_action.html +/foo/_foo_action.html <--- for AJAX requests. +``` + +You can disable this prefixing on a per action or per controller level. + +For all actions in a controller: +```python +class FooController(ActionController): + no_ajax_prefix = True +``` + +For a single action: +```python +from django_url_framework.decorators.action_options +class FooController(ActionController): + @no_ajax_prefix + def foo_action(self, request): + return {} +``` + + +## Action names + +```python +class FooController(ActionController): + def action(self, request): + return {} +``` +Creates the following URL: +``` +/controller/action/ +``` + +Double underscores `__` in action names are converted to slashes in the urlconf, so: `action__name` becomes `/action/name/`. + +```python +class Controller(ActionController): + def action__foo(self, request): + return {} +``` +Creates the following URL: +``` +/controller/action/foo/ +``` + + +### Decorate to name + +You can also decorate functions to give them different names and prefixes and urls. See decorator package for more details, here is an example: +```python +@action_options.name("foo") +@action_options.prefix("prefix_") +def bar(self, request): + return {} +``` +will result in: +``` +/controller/prefix_foo/ +``` + +The action will now have the template `/controller/foo.html`. Prefixes do not affect template naming. + +## Action parameters + +Providing a third parameter to an action will create a URLconf for that parameter, like so: +```python +def action(self, request, object_id): + return {} +``` +Will allow you to call that action with: +``` +/controller/action/(\w+)/ <--- parameter consisting of A-Za-z0-9_ +``` +If you make the argument optional, an additional URLconf entry is created allowing you to call the action without the third argument. +```python +def action(self, request, object_id = None): + return {} +``` +Results in: + +``` +/controller/action/ +/controller/action/(\w+)/ <--- optional argument consisting of A-Za-z0-9_ +``` + +### Decorate for JSON, YAML or Automatic + +You can decorate any action to have a default renderer. +Instead of using `self._as_json` as before, you can just put a decorator like so: + +```python +from django_url_framework.decorators import json_action + @json_action(json_encoder=None) + def action(self, request, year, month): + ... + return {} +``` +Other decorators include `@yaml_action(default_flow_style:bool)` and `@auto()`. +YaML is self-explanatory, however `@auto` is a bit interesting, it will automatically determine the renderer based on the `HTTP_ACCEPT` header. + +*Warning* - if you expose raw data in your actions, that normally would be massaged inside a Server-Side template, DO NOT USE the `@auto` decorator as this allows an attacker to download raw data from your server. +However, if your responses are designed for an API, the `@auto` decorator will enable the API client to request data as it sees fit, for example, it can request a Server-Side rendered HTML, or the same data as JSON or YaML. + +Here is a list of supported renderers: +- text/html - `TemplateRenderer` - renders using the appropriate Django template +- text/plain - `TextRenderer` - prints text data as is, or prints object types using `pprint.pformat` +- application/json - `JSONRenderer` - renders data as JSON +- application/yaml - `YamlRenderer` - renders data as YaML + +`@auto()` accepts the following parameters: +- json_encoder +- yaml_default_flow_style +The work the same as if passed to `@json_action()` or `@yaml_action()` + +### Set HTTP Status Codes easily + +Any action can return a tuple of two items, the second item should be an `int` and will become the HTTP status code for your response. + +```python + @json_action() + def update(self, request, year, month): + ... + return False, 304 #not modified + + @json_action() + def create(self, request, year, month): + ... + return True, 201 #created +``` + +### Decorate for custom parameters + +You can also create your own custom parameters by using the `@url_parameters` decorator to the function. +```python +from django_url_framework.decorators.action_options import url_paramters +class Controller(ActionController): + @url_parameters(r'(?P<year>\d{4})/(?P<month>\d\d)') + def action(self, request, year, month): + ... + return {} +``` +The above will create the following url patterns: +``` +/controller/action/(?P<year>\d{4})/(?P<month>\d\d) +``` +*Note the lack of trailing slash - you must provide this yourself.* + +### Custom url for any action + +You can write your own urlconf for each action, by decorating it with `@urlconf`. +```python +from django_url_framework.decorators.action_options import urlconf +class Controller(ActionController): + @action_options.urlconf([ + r'^bar/(?P<year>\d{4})/$', + r'^bar/(?P<year>\d{4})/(?P<month>\d\d)/$', + r'^foo/(?P<year>\d{4})/(?P<month>\d\d)/(?P<day>\d\d)/$' + ], + do_not_autogenerate=True) + def action(self, request, year, month=None, day=None): + ... + return {} +``` +The above will create the following url patterns: +``` +/controller/bar/(?P<year>\d{4})/ +/controller/bar/(?P<year>\d{4})/(?P<month>\d\d)/$ +/controller/foo/(?P<year>\d{4})/(?P<month>\d\d)/(?P<day>\d\d)/$ +``` + +The `do_not_autogenerate` argument is **true** by default and will prevent any urls for this action +from being autogenerated. If `do_not_autogenerate` were to be set to false in the example below, +the following url would also be created: +``` +/controller/action/ +``` +This URL would not actually work since the `year` argument is required the `action` function. + +## Flash messages + +The ActionController also has a `_flash` instance variable that allows you to send messages to the user that can survive a redirect. Simply use + +```python +self._flash.append("Message") + +self._flash.error("Error message") +``` + +The flash messages can be either messages or error messages. The flash object is automatically exported into the context and you can use it as such: + +```HTML+Django +{% if flash.has_messages %} + {% for message in flash.get_and_clear %} + + {% if message.is_error %}<span class='icon-error'></span>{% endif %} + + <p class="{{message.type}}">{{message}}</p> + + {% endfor %} +{% endif } +``` + +## Before and After each action + +You can override `_before_filter` and/or `_after_filter` to perform certain actions and checks before or after an action. Read more in `ActionController` docs. + +These methods accept the "request" parameter which is an HTTP request object for this request. + +```python +class AccountController(ActionController): + + def _before_filter(self, request): + campaign_id = request.GET.get("campaign_id") + try: + self._campaign = Campaign.objects.get(pk=campaign_id) + except Campaign.DoesNotExist: + self._campaign = None +``` + +You can disable the before and after filters by decorating any action with the `@disable_filters` decorator. + +Example: +```python +from django_url_framework.decorators.action_options import disable_filters +@disable_filters +def action(self, request): + return {} +``` + +One of the great features of django url framework is that you can require login for all actions in a controller by simply decorating the before_filter with a decorator to require logging in, see next section! + +## Authentication + +To require login on an action use the `@login_required` decorator provided by django-url-framework. The decorator also works on `_before_filter`. + +```python +from django_url_framework.decorators import login_required +class AccountController(ActionController): + + @login_required + def action(self, request): + return {} +``` + +If the user isn’t logged in, redirect to `settings.LOGIN_URL`, passing the current absolute path in the query string. Example: `/accounts/login/?next=/polls/3/`. +`login_required()` also takes an optional `login_url` parameter. Example: + +```python +from django_url_framework.decorators import login_required +class AccountController(ActionController): + + @login_required(login_url="/login/") + def action(self, request): + return {} +``` + +By default, the path that the user should be redirected to upon successful authentication is stored in a query string parameter called "next". If you would prefer to use a different name for this parameter, `login_required()` takes an optional `redirect_field_name` parameter. + +Additionally you can use `@superuser_required`, `@permission_required(permission_instance)` and `@must_be_member_of_group(group_name="some_group")`. + +Another example makes it easy to limiting access to a subset of data based on the logged in user for the whole controller. + +```python +from django_url_framework.decorators import login_required +class ItemController(ActionController): + @login_required() + def _before_filter(self): + self.my_items = Item.objects.filter(user=request.user) + self.my_products = Product.objects.filter(item__in=self.my_items) + return { + "page_title": "Item Page" + } + def item(self, request, pk): + item = get_object_or_404(self.my_items, pk=pk) + return {"item":item} + def product(self, request, pk): + item = get_object_or_404(self.my_products, pk=pk) + return {"product":product} + + +``` + +## Only POST? (or GET or anything...) +You can limit what http methods a function can be called with. + +The example below limits the `update` action to only **POST** and **DELETE** http methods. + +```python +from django_url_framework.decorators import http_methods +class Controller(ActionController): + @http_methods.POST + @http_methods.DELETE + def update(self, request): + return {} +``` + +By default all actions can be called with all http methods. + +## Custom template extensions +When using jade or something similar you can specify a custom extension for all templates in the controller. + +```python +class FooController(ActionController): + #custom extension for all templates in this controller + template_extension = "jade" +``` + + + + +%package -n python3-django-url-framework +Summary: Automagically discover urls in a django application, similar to the Ruby on Rails Controller/Action/View implementation. +Provides: python-django-url-framework +BuildRequires: python3-devel +BuildRequires: python3-setuptools +BuildRequires: python3-pip +%description -n python3-django-url-framework +The django-url-framework will help you get your django applications done faster. + + +[](https://django-url-framework.readthedocs.io/en/latest/?badge=latest) +[](https://gitter.im/zeraien/django-url-framework?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + +It automatically detects urls in a django application, similar to the way Ruby on Rails does it with the Controller-Action-View implementation. + +Controllers are created in each django application with a predefined file naming scheme (`foo_controller.py`) and extending `ActionController`. The `ActionController` contains methods often used in a web context, and does common request-related processing. + +Each application can have multiple controllers thus allowing for smaller classes in a larger application. + +Each function not starting with an underscore becomes it's own action. By simply returning a dictionary from the action, it will be rendered with the template named using the `controller/action.html` naming scheme. + +Each action and controller can override certain global settings such as using a custom template name or giving the action (or controller) a custom name. + +## Install + +From pypi: + +``` +pip install django-url-framework +``` + +Alternatively just check out the source here and run `python setup.py install` or `pip install .` + +## Add to your project + +### settings.py + +```python +INSTALLED_APPS = ( + ..., + 'django_url_framework', + ... +) +``` +### urls.py +```python +import django_url_framework +from django.conf import settings +from django.conf.urls import patterns, include + +django_url_framework.site.autodiscover(new_inflection_library=True) + +urlpatterns = patterns('', + (r'^', include(django_url_framework.site.urls) ), +) +``` + +## Example + +### Folder structure + +``` +project/ + app/ + cart_controller.py + id_controller.py + templates/ + cart/ + add.html + index.html + remove.html + id_manager/ + bar.html +``` + +### cart_controller.py + +```python +from django_url_framework.controller import ActionController + +class CartController(ActionController): + def edit(self, request, id = None): + return {} + def remove(self, request, id): + return {} + def index(self, request): + return {} +``` + +### id_controller.py + +```python +from django_url_framework.controller import ActionController + +class IDManagerController(ActionController): + def index(self, request, object_id = None): + return {} + def bar(self, request): + return {} + def bar__delete(self, request): + return {} +``` + +### Result + +The following URLs will be created: + +``` +/cart/ <- will go to *index action* +/cart/(\w+)/ +/cart/edit/ +/cart/edit/(\w+)/ +/cart/remove/(\w+)/ +/foo/ +/foo/(\w+)/ +/foo/bar/ +/foo/bar/delete/ +``` + +You can easily access your URLs using django's built-in `{% url ... %}` tag. Simply call `{% url cart_index %}` or `{% url cart_delete id %}` and it will work as you would expect. + +There is also a helper tag for faster linking within the same controller. +`{% go_action remove %}` will take you to `/cart/remove/`. To use it, `{% load url_framework %}` in your templates. + +The names of the controller files do not affect your URLs, however, the files must have `_controller.py` suffix. The URL name of the controller is derived from the class name, minus the Controller part. You can also manually specify controller names using the `controller_name` attribute on the controller class. + +### Controller names + +The controller name is derived from it's class name, by converting camelcase into underscores. +For instance `FooController` is simple `foo`, while `FooBarController` becomes `foo_bar`. + +The latest version uses the `inflection` library, however to avoid breaking old code, this is still optional until 2021. + +The biggest difference is that with `inflection`, `HTTPResponse` becomes `http_response`, while the old name would be `httpresponse`. I suggest enabling the `inflection` library for all new and existing projects. You can manually specify names for controllers whose name change would break your code, or disable the inflection library for those controllers using a flag. + +You can give the controller a custom name with the `controller_name` parameter: +```python +class Controller(ActionController): + controller_name = "foo" +``` + +Enable or disable the use of the new `inflection` library using a flag +```python +class Controller(ActionController): + use_inflection_library = True +``` + +### Other useful controller settings + +```python +class BarController(ActionController): + + # default filename extension for all templates + template_extension = "pug" + + # will require every template file to start with this string + template_prefix = "foo_" + + # will not look for templates in subdirectories, but in the root templates/ folder + no_subdirectories = False + + # do not prefix templates with `_` (underscore) when they are called using an AJAX request + no_ajax_prefix = False + + # Set a prefix for the controller's name, applies even if + # you set controller_name (template name is based on controller_name, sans prefix) + # NOTE: The urlconf name will not include the prefix, only the actual URL itself + # Thus: FooController.list will have the URL /prefixed_foo/list/, but the url name will be + # `foo_list`. + controller_prefix = "prefixed_" + + # completely override the name of the controller + controller_name = "shopping_cart" + + # When used with custom urlconf in actions, these arguments will not be passed to the action + # example: "/<id:int>/<skip:bool>/" Only `id` will be passed to the `action`, while `skip` will not be. + consume_urlconf_keyword_arguments = ['skip'] + + # set a prefix for all the URLs in this controller + # So, what normally would be `/controller/action/`, becomes `^prefix/controller/action/` + urlconf_prefix:list = ["^prefix"] + + # A custom json encoder, subclassing JSONEncoder + json_default_encoder:JSONEncoder = None + + # use the yaml default flow style + yaml_default_flow_style:bool = True + + # use the new inflection library to generate controller url + # if this is None, will use the global setting, otherwise override this on a per controller basis + use_inflection_library:Union[bool,None] = None + +``` + +### Template filenames + +By default templates are stored in the subdirectory with the controller's name, and the templates are given the same filename as the action name. +If a request is determinned to be AJAX in nature, the template filename is prefixed with an underscore. +Example: +```python +class FooController(ActionController): + def foo_action(self, request): + return {} +``` + +File structure: +```python +/foo/foo_action.html +/foo/_foo_action.html <--- for AJAX requests. +``` + +You can disable this prefixing on a per action or per controller level. + +For all actions in a controller: +```python +class FooController(ActionController): + no_ajax_prefix = True +``` + +For a single action: +```python +from django_url_framework.decorators.action_options +class FooController(ActionController): + @no_ajax_prefix + def foo_action(self, request): + return {} +``` + + +## Action names + +```python +class FooController(ActionController): + def action(self, request): + return {} +``` +Creates the following URL: +``` +/controller/action/ +``` + +Double underscores `__` in action names are converted to slashes in the urlconf, so: `action__name` becomes `/action/name/`. + +```python +class Controller(ActionController): + def action__foo(self, request): + return {} +``` +Creates the following URL: +``` +/controller/action/foo/ +``` + + +### Decorate to name + +You can also decorate functions to give them different names and prefixes and urls. See decorator package for more details, here is an example: +```python +@action_options.name("foo") +@action_options.prefix("prefix_") +def bar(self, request): + return {} +``` +will result in: +``` +/controller/prefix_foo/ +``` + +The action will now have the template `/controller/foo.html`. Prefixes do not affect template naming. + +## Action parameters + +Providing a third parameter to an action will create a URLconf for that parameter, like so: +```python +def action(self, request, object_id): + return {} +``` +Will allow you to call that action with: +``` +/controller/action/(\w+)/ <--- parameter consisting of A-Za-z0-9_ +``` +If you make the argument optional, an additional URLconf entry is created allowing you to call the action without the third argument. +```python +def action(self, request, object_id = None): + return {} +``` +Results in: + +``` +/controller/action/ +/controller/action/(\w+)/ <--- optional argument consisting of A-Za-z0-9_ +``` + +### Decorate for JSON, YAML or Automatic + +You can decorate any action to have a default renderer. +Instead of using `self._as_json` as before, you can just put a decorator like so: + +```python +from django_url_framework.decorators import json_action + @json_action(json_encoder=None) + def action(self, request, year, month): + ... + return {} +``` +Other decorators include `@yaml_action(default_flow_style:bool)` and `@auto()`. +YaML is self-explanatory, however `@auto` is a bit interesting, it will automatically determine the renderer based on the `HTTP_ACCEPT` header. + +*Warning* - if you expose raw data in your actions, that normally would be massaged inside a Server-Side template, DO NOT USE the `@auto` decorator as this allows an attacker to download raw data from your server. +However, if your responses are designed for an API, the `@auto` decorator will enable the API client to request data as it sees fit, for example, it can request a Server-Side rendered HTML, or the same data as JSON or YaML. + +Here is a list of supported renderers: +- text/html - `TemplateRenderer` - renders using the appropriate Django template +- text/plain - `TextRenderer` - prints text data as is, or prints object types using `pprint.pformat` +- application/json - `JSONRenderer` - renders data as JSON +- application/yaml - `YamlRenderer` - renders data as YaML + +`@auto()` accepts the following parameters: +- json_encoder +- yaml_default_flow_style +The work the same as if passed to `@json_action()` or `@yaml_action()` + +### Set HTTP Status Codes easily + +Any action can return a tuple of two items, the second item should be an `int` and will become the HTTP status code for your response. + +```python + @json_action() + def update(self, request, year, month): + ... + return False, 304 #not modified + + @json_action() + def create(self, request, year, month): + ... + return True, 201 #created +``` + +### Decorate for custom parameters + +You can also create your own custom parameters by using the `@url_parameters` decorator to the function. +```python +from django_url_framework.decorators.action_options import url_paramters +class Controller(ActionController): + @url_parameters(r'(?P<year>\d{4})/(?P<month>\d\d)') + def action(self, request, year, month): + ... + return {} +``` +The above will create the following url patterns: +``` +/controller/action/(?P<year>\d{4})/(?P<month>\d\d) +``` +*Note the lack of trailing slash - you must provide this yourself.* + +### Custom url for any action + +You can write your own urlconf for each action, by decorating it with `@urlconf`. +```python +from django_url_framework.decorators.action_options import urlconf +class Controller(ActionController): + @action_options.urlconf([ + r'^bar/(?P<year>\d{4})/$', + r'^bar/(?P<year>\d{4})/(?P<month>\d\d)/$', + r'^foo/(?P<year>\d{4})/(?P<month>\d\d)/(?P<day>\d\d)/$' + ], + do_not_autogenerate=True) + def action(self, request, year, month=None, day=None): + ... + return {} +``` +The above will create the following url patterns: +``` +/controller/bar/(?P<year>\d{4})/ +/controller/bar/(?P<year>\d{4})/(?P<month>\d\d)/$ +/controller/foo/(?P<year>\d{4})/(?P<month>\d\d)/(?P<day>\d\d)/$ +``` + +The `do_not_autogenerate` argument is **true** by default and will prevent any urls for this action +from being autogenerated. If `do_not_autogenerate` were to be set to false in the example below, +the following url would also be created: +``` +/controller/action/ +``` +This URL would not actually work since the `year` argument is required the `action` function. + +## Flash messages + +The ActionController also has a `_flash` instance variable that allows you to send messages to the user that can survive a redirect. Simply use + +```python +self._flash.append("Message") + +self._flash.error("Error message") +``` + +The flash messages can be either messages or error messages. The flash object is automatically exported into the context and you can use it as such: + +```HTML+Django +{% if flash.has_messages %} + {% for message in flash.get_and_clear %} + + {% if message.is_error %}<span class='icon-error'></span>{% endif %} + + <p class="{{message.type}}">{{message}}</p> + + {% endfor %} +{% endif } +``` + +## Before and After each action + +You can override `_before_filter` and/or `_after_filter` to perform certain actions and checks before or after an action. Read more in `ActionController` docs. + +These methods accept the "request" parameter which is an HTTP request object for this request. + +```python +class AccountController(ActionController): + + def _before_filter(self, request): + campaign_id = request.GET.get("campaign_id") + try: + self._campaign = Campaign.objects.get(pk=campaign_id) + except Campaign.DoesNotExist: + self._campaign = None +``` + +You can disable the before and after filters by decorating any action with the `@disable_filters` decorator. + +Example: +```python +from django_url_framework.decorators.action_options import disable_filters +@disable_filters +def action(self, request): + return {} +``` + +One of the great features of django url framework is that you can require login for all actions in a controller by simply decorating the before_filter with a decorator to require logging in, see next section! + +## Authentication + +To require login on an action use the `@login_required` decorator provided by django-url-framework. The decorator also works on `_before_filter`. + +```python +from django_url_framework.decorators import login_required +class AccountController(ActionController): + + @login_required + def action(self, request): + return {} +``` + +If the user isn’t logged in, redirect to `settings.LOGIN_URL`, passing the current absolute path in the query string. Example: `/accounts/login/?next=/polls/3/`. +`login_required()` also takes an optional `login_url` parameter. Example: + +```python +from django_url_framework.decorators import login_required +class AccountController(ActionController): + + @login_required(login_url="/login/") + def action(self, request): + return {} +``` + +By default, the path that the user should be redirected to upon successful authentication is stored in a query string parameter called "next". If you would prefer to use a different name for this parameter, `login_required()` takes an optional `redirect_field_name` parameter. + +Additionally you can use `@superuser_required`, `@permission_required(permission_instance)` and `@must_be_member_of_group(group_name="some_group")`. + +Another example makes it easy to limiting access to a subset of data based on the logged in user for the whole controller. + +```python +from django_url_framework.decorators import login_required +class ItemController(ActionController): + @login_required() + def _before_filter(self): + self.my_items = Item.objects.filter(user=request.user) + self.my_products = Product.objects.filter(item__in=self.my_items) + return { + "page_title": "Item Page" + } + def item(self, request, pk): + item = get_object_or_404(self.my_items, pk=pk) + return {"item":item} + def product(self, request, pk): + item = get_object_or_404(self.my_products, pk=pk) + return {"product":product} + + +``` + +## Only POST? (or GET or anything...) +You can limit what http methods a function can be called with. + +The example below limits the `update` action to only **POST** and **DELETE** http methods. + +```python +from django_url_framework.decorators import http_methods +class Controller(ActionController): + @http_methods.POST + @http_methods.DELETE + def update(self, request): + return {} +``` + +By default all actions can be called with all http methods. + +## Custom template extensions +When using jade or something similar you can specify a custom extension for all templates in the controller. + +```python +class FooController(ActionController): + #custom extension for all templates in this controller + template_extension = "jade" +``` + + + + +%package help +Summary: Development documents and examples for django-url-framework +Provides: python3-django-url-framework-doc +%description help +The django-url-framework will help you get your django applications done faster. + + +[](https://django-url-framework.readthedocs.io/en/latest/?badge=latest) +[](https://gitter.im/zeraien/django-url-framework?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + +It automatically detects urls in a django application, similar to the way Ruby on Rails does it with the Controller-Action-View implementation. + +Controllers are created in each django application with a predefined file naming scheme (`foo_controller.py`) and extending `ActionController`. The `ActionController` contains methods often used in a web context, and does common request-related processing. + +Each application can have multiple controllers thus allowing for smaller classes in a larger application. + +Each function not starting with an underscore becomes it's own action. By simply returning a dictionary from the action, it will be rendered with the template named using the `controller/action.html` naming scheme. + +Each action and controller can override certain global settings such as using a custom template name or giving the action (or controller) a custom name. + +## Install + +From pypi: + +``` +pip install django-url-framework +``` + +Alternatively just check out the source here and run `python setup.py install` or `pip install .` + +## Add to your project + +### settings.py + +```python +INSTALLED_APPS = ( + ..., + 'django_url_framework', + ... +) +``` +### urls.py +```python +import django_url_framework +from django.conf import settings +from django.conf.urls import patterns, include + +django_url_framework.site.autodiscover(new_inflection_library=True) + +urlpatterns = patterns('', + (r'^', include(django_url_framework.site.urls) ), +) +``` + +## Example + +### Folder structure + +``` +project/ + app/ + cart_controller.py + id_controller.py + templates/ + cart/ + add.html + index.html + remove.html + id_manager/ + bar.html +``` + +### cart_controller.py + +```python +from django_url_framework.controller import ActionController + +class CartController(ActionController): + def edit(self, request, id = None): + return {} + def remove(self, request, id): + return {} + def index(self, request): + return {} +``` + +### id_controller.py + +```python +from django_url_framework.controller import ActionController + +class IDManagerController(ActionController): + def index(self, request, object_id = None): + return {} + def bar(self, request): + return {} + def bar__delete(self, request): + return {} +``` + +### Result + +The following URLs will be created: + +``` +/cart/ <- will go to *index action* +/cart/(\w+)/ +/cart/edit/ +/cart/edit/(\w+)/ +/cart/remove/(\w+)/ +/foo/ +/foo/(\w+)/ +/foo/bar/ +/foo/bar/delete/ +``` + +You can easily access your URLs using django's built-in `{% url ... %}` tag. Simply call `{% url cart_index %}` or `{% url cart_delete id %}` and it will work as you would expect. + +There is also a helper tag for faster linking within the same controller. +`{% go_action remove %}` will take you to `/cart/remove/`. To use it, `{% load url_framework %}` in your templates. + +The names of the controller files do not affect your URLs, however, the files must have `_controller.py` suffix. The URL name of the controller is derived from the class name, minus the Controller part. You can also manually specify controller names using the `controller_name` attribute on the controller class. + +### Controller names + +The controller name is derived from it's class name, by converting camelcase into underscores. +For instance `FooController` is simple `foo`, while `FooBarController` becomes `foo_bar`. + +The latest version uses the `inflection` library, however to avoid breaking old code, this is still optional until 2021. + +The biggest difference is that with `inflection`, `HTTPResponse` becomes `http_response`, while the old name would be `httpresponse`. I suggest enabling the `inflection` library for all new and existing projects. You can manually specify names for controllers whose name change would break your code, or disable the inflection library for those controllers using a flag. + +You can give the controller a custom name with the `controller_name` parameter: +```python +class Controller(ActionController): + controller_name = "foo" +``` + +Enable or disable the use of the new `inflection` library using a flag +```python +class Controller(ActionController): + use_inflection_library = True +``` + +### Other useful controller settings + +```python +class BarController(ActionController): + + # default filename extension for all templates + template_extension = "pug" + + # will require every template file to start with this string + template_prefix = "foo_" + + # will not look for templates in subdirectories, but in the root templates/ folder + no_subdirectories = False + + # do not prefix templates with `_` (underscore) when they are called using an AJAX request + no_ajax_prefix = False + + # Set a prefix for the controller's name, applies even if + # you set controller_name (template name is based on controller_name, sans prefix) + # NOTE: The urlconf name will not include the prefix, only the actual URL itself + # Thus: FooController.list will have the URL /prefixed_foo/list/, but the url name will be + # `foo_list`. + controller_prefix = "prefixed_" + + # completely override the name of the controller + controller_name = "shopping_cart" + + # When used with custom urlconf in actions, these arguments will not be passed to the action + # example: "/<id:int>/<skip:bool>/" Only `id` will be passed to the `action`, while `skip` will not be. + consume_urlconf_keyword_arguments = ['skip'] + + # set a prefix for all the URLs in this controller + # So, what normally would be `/controller/action/`, becomes `^prefix/controller/action/` + urlconf_prefix:list = ["^prefix"] + + # A custom json encoder, subclassing JSONEncoder + json_default_encoder:JSONEncoder = None + + # use the yaml default flow style + yaml_default_flow_style:bool = True + + # use the new inflection library to generate controller url + # if this is None, will use the global setting, otherwise override this on a per controller basis + use_inflection_library:Union[bool,None] = None + +``` + +### Template filenames + +By default templates are stored in the subdirectory with the controller's name, and the templates are given the same filename as the action name. +If a request is determinned to be AJAX in nature, the template filename is prefixed with an underscore. +Example: +```python +class FooController(ActionController): + def foo_action(self, request): + return {} +``` + +File structure: +```python +/foo/foo_action.html +/foo/_foo_action.html <--- for AJAX requests. +``` + +You can disable this prefixing on a per action or per controller level. + +For all actions in a controller: +```python +class FooController(ActionController): + no_ajax_prefix = True +``` + +For a single action: +```python +from django_url_framework.decorators.action_options +class FooController(ActionController): + @no_ajax_prefix + def foo_action(self, request): + return {} +``` + + +## Action names + +```python +class FooController(ActionController): + def action(self, request): + return {} +``` +Creates the following URL: +``` +/controller/action/ +``` + +Double underscores `__` in action names are converted to slashes in the urlconf, so: `action__name` becomes `/action/name/`. + +```python +class Controller(ActionController): + def action__foo(self, request): + return {} +``` +Creates the following URL: +``` +/controller/action/foo/ +``` + + +### Decorate to name + +You can also decorate functions to give them different names and prefixes and urls. See decorator package for more details, here is an example: +```python +@action_options.name("foo") +@action_options.prefix("prefix_") +def bar(self, request): + return {} +``` +will result in: +``` +/controller/prefix_foo/ +``` + +The action will now have the template `/controller/foo.html`. Prefixes do not affect template naming. + +## Action parameters + +Providing a third parameter to an action will create a URLconf for that parameter, like so: +```python +def action(self, request, object_id): + return {} +``` +Will allow you to call that action with: +``` +/controller/action/(\w+)/ <--- parameter consisting of A-Za-z0-9_ +``` +If you make the argument optional, an additional URLconf entry is created allowing you to call the action without the third argument. +```python +def action(self, request, object_id = None): + return {} +``` +Results in: + +``` +/controller/action/ +/controller/action/(\w+)/ <--- optional argument consisting of A-Za-z0-9_ +``` + +### Decorate for JSON, YAML or Automatic + +You can decorate any action to have a default renderer. +Instead of using `self._as_json` as before, you can just put a decorator like so: + +```python +from django_url_framework.decorators import json_action + @json_action(json_encoder=None) + def action(self, request, year, month): + ... + return {} +``` +Other decorators include `@yaml_action(default_flow_style:bool)` and `@auto()`. +YaML is self-explanatory, however `@auto` is a bit interesting, it will automatically determine the renderer based on the `HTTP_ACCEPT` header. + +*Warning* - if you expose raw data in your actions, that normally would be massaged inside a Server-Side template, DO NOT USE the `@auto` decorator as this allows an attacker to download raw data from your server. +However, if your responses are designed for an API, the `@auto` decorator will enable the API client to request data as it sees fit, for example, it can request a Server-Side rendered HTML, or the same data as JSON or YaML. + +Here is a list of supported renderers: +- text/html - `TemplateRenderer` - renders using the appropriate Django template +- text/plain - `TextRenderer` - prints text data as is, or prints object types using `pprint.pformat` +- application/json - `JSONRenderer` - renders data as JSON +- application/yaml - `YamlRenderer` - renders data as YaML + +`@auto()` accepts the following parameters: +- json_encoder +- yaml_default_flow_style +The work the same as if passed to `@json_action()` or `@yaml_action()` + +### Set HTTP Status Codes easily + +Any action can return a tuple of two items, the second item should be an `int` and will become the HTTP status code for your response. + +```python + @json_action() + def update(self, request, year, month): + ... + return False, 304 #not modified + + @json_action() + def create(self, request, year, month): + ... + return True, 201 #created +``` + +### Decorate for custom parameters + +You can also create your own custom parameters by using the `@url_parameters` decorator to the function. +```python +from django_url_framework.decorators.action_options import url_paramters +class Controller(ActionController): + @url_parameters(r'(?P<year>\d{4})/(?P<month>\d\d)') + def action(self, request, year, month): + ... + return {} +``` +The above will create the following url patterns: +``` +/controller/action/(?P<year>\d{4})/(?P<month>\d\d) +``` +*Note the lack of trailing slash - you must provide this yourself.* + +### Custom url for any action + +You can write your own urlconf for each action, by decorating it with `@urlconf`. +```python +from django_url_framework.decorators.action_options import urlconf +class Controller(ActionController): + @action_options.urlconf([ + r'^bar/(?P<year>\d{4})/$', + r'^bar/(?P<year>\d{4})/(?P<month>\d\d)/$', + r'^foo/(?P<year>\d{4})/(?P<month>\d\d)/(?P<day>\d\d)/$' + ], + do_not_autogenerate=True) + def action(self, request, year, month=None, day=None): + ... + return {} +``` +The above will create the following url patterns: +``` +/controller/bar/(?P<year>\d{4})/ +/controller/bar/(?P<year>\d{4})/(?P<month>\d\d)/$ +/controller/foo/(?P<year>\d{4})/(?P<month>\d\d)/(?P<day>\d\d)/$ +``` + +The `do_not_autogenerate` argument is **true** by default and will prevent any urls for this action +from being autogenerated. If `do_not_autogenerate` were to be set to false in the example below, +the following url would also be created: +``` +/controller/action/ +``` +This URL would not actually work since the `year` argument is required the `action` function. + +## Flash messages + +The ActionController also has a `_flash` instance variable that allows you to send messages to the user that can survive a redirect. Simply use + +```python +self._flash.append("Message") + +self._flash.error("Error message") +``` + +The flash messages can be either messages or error messages. The flash object is automatically exported into the context and you can use it as such: + +```HTML+Django +{% if flash.has_messages %} + {% for message in flash.get_and_clear %} + + {% if message.is_error %}<span class='icon-error'></span>{% endif %} + + <p class="{{message.type}}">{{message}}</p> + + {% endfor %} +{% endif } +``` + +## Before and After each action + +You can override `_before_filter` and/or `_after_filter` to perform certain actions and checks before or after an action. Read more in `ActionController` docs. + +These methods accept the "request" parameter which is an HTTP request object for this request. + +```python +class AccountController(ActionController): + + def _before_filter(self, request): + campaign_id = request.GET.get("campaign_id") + try: + self._campaign = Campaign.objects.get(pk=campaign_id) + except Campaign.DoesNotExist: + self._campaign = None +``` + +You can disable the before and after filters by decorating any action with the `@disable_filters` decorator. + +Example: +```python +from django_url_framework.decorators.action_options import disable_filters +@disable_filters +def action(self, request): + return {} +``` + +One of the great features of django url framework is that you can require login for all actions in a controller by simply decorating the before_filter with a decorator to require logging in, see next section! + +## Authentication + +To require login on an action use the `@login_required` decorator provided by django-url-framework. The decorator also works on `_before_filter`. + +```python +from django_url_framework.decorators import login_required +class AccountController(ActionController): + + @login_required + def action(self, request): + return {} +``` + +If the user isn’t logged in, redirect to `settings.LOGIN_URL`, passing the current absolute path in the query string. Example: `/accounts/login/?next=/polls/3/`. +`login_required()` also takes an optional `login_url` parameter. Example: + +```python +from django_url_framework.decorators import login_required +class AccountController(ActionController): + + @login_required(login_url="/login/") + def action(self, request): + return {} +``` + +By default, the path that the user should be redirected to upon successful authentication is stored in a query string parameter called "next". If you would prefer to use a different name for this parameter, `login_required()` takes an optional `redirect_field_name` parameter. + +Additionally you can use `@superuser_required`, `@permission_required(permission_instance)` and `@must_be_member_of_group(group_name="some_group")`. + +Another example makes it easy to limiting access to a subset of data based on the logged in user for the whole controller. + +```python +from django_url_framework.decorators import login_required +class ItemController(ActionController): + @login_required() + def _before_filter(self): + self.my_items = Item.objects.filter(user=request.user) + self.my_products = Product.objects.filter(item__in=self.my_items) + return { + "page_title": "Item Page" + } + def item(self, request, pk): + item = get_object_or_404(self.my_items, pk=pk) + return {"item":item} + def product(self, request, pk): + item = get_object_or_404(self.my_products, pk=pk) + return {"product":product} + + +``` + +## Only POST? (or GET or anything...) +You can limit what http methods a function can be called with. + +The example below limits the `update` action to only **POST** and **DELETE** http methods. + +```python +from django_url_framework.decorators import http_methods +class Controller(ActionController): + @http_methods.POST + @http_methods.DELETE + def update(self, request): + return {} +``` + +By default all actions can be called with all http methods. + +## Custom template extensions +When using jade or something similar you can specify a custom extension for all templates in the controller. + +```python +class FooController(ActionController): + #custom extension for all templates in this controller + template_extension = "jade" +``` + + + + +%prep +%autosetup -n django-url-framework-0.6.0 + +%build +%py3_build + +%install +%py3_install +install -d -m755 %{buildroot}/%{_pkgdocdir} +if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi +if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi +if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi +if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi +pushd %{buildroot} +if [ -d usr/lib ]; then + find usr/lib -type f -printf "\"/%h/%f\"\n" >> filelist.lst +fi +if [ -d usr/lib64 ]; then + find usr/lib64 -type f -printf "\"/%h/%f\"\n" >> filelist.lst +fi +if [ -d usr/bin ]; then + find usr/bin -type f -printf "\"/%h/%f\"\n" >> filelist.lst +fi +if [ -d usr/sbin ]; then + find usr/sbin -type f -printf "\"/%h/%f\"\n" >> filelist.lst +fi +touch doclist.lst +if [ -d usr/share/man ]; then + find usr/share/man -type f -printf "\"/%h/%f.gz\"\n" >> doclist.lst +fi +popd +mv %{buildroot}/filelist.lst . +mv %{buildroot}/doclist.lst . + +%files -n python3-django-url-framework -f filelist.lst +%dir %{python3_sitelib}/* + +%files help -f doclist.lst +%{_docdir}/* + +%changelog +* Tue Jun 20 2023 Python_Bot <Python_Bot@openeuler.org> - 0.6.0-1 +- Package Spec generated |