{ "info": { "author": "Istv\u00e1n P\u00e1sztor", "author_email": "pasztorpisti@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Framework :: Django", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 2", "Programming Language :: Python :: 3", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": "===============================\ndjango-universal-view-decorator\n===============================\n\nSmart view class (CBV) decoration\n\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\n\n\n.. image:: https://img.shields.io/travis/pasztorpisti/django-universal-view-decorator.svg?style=flat\n :target: https://travis-ci.org/pasztorpisti/django-universal-view-decorator\n :alt: build\n\n.. image:: https://img.shields.io/codacy/c1087ff8de9a43a0bd87caefc7c96a81/master.svg?style=flat\n :target: https://www.codacy.com/app/pasztorpisti/django-universal-view-decorator\n :alt: code quality\n\n.. image:: https://landscape.io/github/pasztorpisti/django-universal-view-decorator/master/landscape.svg?style=flat\n :target: https://landscape.io/github/pasztorpisti/django-universal-view-decorator/master\n :alt: code health\n\n.. image:: https://img.shields.io/coveralls/pasztorpisti/django-universal-view-decorator/master.svg?style=flat\n :target: https://coveralls.io/r/pasztorpisti/django-universal-view-decorator?branch=master\n :alt: coverage\n\n.. image:: https://img.shields.io/pypi/v/django-universal-view-decorator.svg?style=flat\n :target: https://pypi.python.org/pypi/django-universal-view-decorator\n :alt: pypi\n\n.. image:: https://img.shields.io/github/tag/pasztorpisti/django-universal-view-decorator.svg?style=flat\n :target: https://github.com/pasztorpisti/django-universal-view-decorator\n :alt: github\n\n.. image:: https://img.shields.io/github/license/pasztorpisti/django-universal-view-decorator.svg?style=flat\n :target: https://github.com/pasztorpisti/django-universal-view-decorator/blob/master/LICENSE.txt\n :alt: license: MIT\n\n.. contents::\n\n\nAbout Class Based View (CBV) decoration\n=======================================\n\nIn django you can implement views in two different ways\n\n 1. FBV (Function Based View)\n 2. CBV (Class Based View)\n\nA project can make use of both techniques in parallel. While decorators work really well with FBVs, using them\nwith CBVs is a bit uglier. The django documentation recommends two techniques to decorate class based views:\n\nhttps://docs.djangoproject.com/en/1.9/topics/class-based-views/intro/#decorating-class-based-views\n\n1. Decorating in URLConf: applying the decorator to the view function returned by the ``View.as_view()`` class method.\n\n .. code-block:: python\n\n urlpatterns = [\n url(r'^my_view/', permission_required('my_app.my_permission')(MyView.as_view())),\n ]\n\n I think this decoration technique is solid. It treats your view class as a view function and places the\n decorator between the url config and the view function exactly as in case of decorating a FBV. The decorator\n is guaranteed to execute before any methods in the decorated CBV.\n\n My only problem is that I have to do this in the URLConf module and on a per-url basis instead of being\n able to apply the decorator onto the view class in the module in which it has been implemented.\n\n2. Applying your decorator to one of the methods of your view class (e.g.: ``dispatch()``) with the help of\n ``@django.utils.decorators.method_decorator``.\n\n .. code-block:: python\n\n class MyView(View):\n @method_decorator(permission_required('my_app.my_permission'))\n def dispatch(self, *args, **kwargs):\n return super(MyView, self).dispatch(*args, **kwargs)\n\n # django 1.9+: this way you don't have to override dispatch() just to be able to decorate it\n @method_decorator(permission_required('my_app.my_permission'), name='dispatch')\n class MyView(View):\n ...\n\n Problems with this solution:\n\n - If someone subclasses the view and overrides the decorated method then the method override in the subclass is\n executed before the decorator. The decorator can actually be bypassed completely by not calling the super\n version of the overridden method. This may be a desired behavior sometimes but in case of some critical\n (e.g.: permission) decorators it is a problem. In case of decorating in URLConf this isn't a problem: in\n that case the decorator is always executed before any view class methods.\n - Minor issue: I have to write ``@method_decorator(permission_required('my_app.my_permission'))`` instead of\n simply ``@permission_required('my_app.my_permission')``.\n\n\nAs you see the two decoration techniques have different behavior. I find the behavior of technique #1 (URLConf\ndecoration) more useful and robust while cosmetically I prefer applying decorators to my view class implementations\nas in case of technique #2 (``@method_decorator``).\n\nThis library provides a ``@universal_view_decorator`` helper (similar to django's ``@method_decorator``) that combines\nthe behavior of decoration technique #1 with the cosmetics of technique #2:\n\n- You can apply the decorator to the view class directly - you don't have to mess with URLConf unless you want to\n apply decorators on a per-url basis.\n- Behaves like decoration method #1: under the hood it applies the decorator to the return value of\n ``View.as_view()`` so it can't be bypassed with subclassing.\n\nBesides the previously listed features ``@universal_view_decorator`` provides a bit more convenient interface than\ndjango's ``@method_decorator``: after wrapping your view decorator with this helper you can apply it to FBVs, CBVs\nand CBV methods with the exact same syntax. There is also a ``@universal_view_decorator_with_args`` variant of this\nhelper that comes in handy with view decorators that have parameters.\n\n\nInstallation\n============\n\n.. code-block:: sh\n\n pip install django-universal-view-decorator\n\nAlternatively you can download the distribution from the following places:\n\n- https://pypi.python.org/pypi/django-universal-view-decorator#downloads\n- https://github.com/pasztorpisti/django-universal-view-decorator/releases\n\n\nUsage\n=====\n\n\n``@universal_view_decorator``\n-----------------------------\n\nIf you wrap your view decorator with ``@universal_view_decorator`` then you can apply it to:\n\n- FBVs (just like before wrapping it with ``@universal_view_decorator``)\n- CBVs (with the same behavior as in case of decorating ``View.as_view()`` in URLConf)\n- CBV methods (with the same behavior when applying your decorator to the view class method using django's\n ``@method_decorator``)\n\n\n.. code-block:: python\n\n from django_universal_view_decorator import universal_view_decorator\n\n\n @universal_view_decorator(login_required)\n def function_based_view(request):\n ...\n\n\n # You can wrap multiple decorators at the same time\n @universal_view_decorator(login_required, permission_required('my_app.my_permission'))\n def function_based_view(request):\n ...\n\n\n # This double decoration is equivalent in behavior to the previous example\n # where we used one wrapper to wrap both legacy decorators.\n @universal_view_decorator(login_required)\n @universal_view_decorator(permission_required('my_app.my_permission'))\n def function_based_view(request):\n ...\n\n\n # Applying the decorator to view classes. Behavior is the same as applying\n # the permission decorator to ``ClassBasedView.as_view()`` in the URLConf.\n @universal_view_decorator(permission_required('my_app.my_permission'))\n class ClassBasedView(View):\n ...\n\n\n # Applying the decorator to view class methods.\n # Behavior is equivalent to that of django's @method_decorator.\n class ClassBasedView(View):\n @universal_view_decorator(login_required)\n def head(self, request):\n ...\n\n\n # Wrapping the decorator only once for reuse in our project:\n reusable_universal_login_required = universal_view_decorator(logic_required)\n\n\n @reusable_universal_login_required\n class ClassBasedView(View):\n ...\n\n\n``@universal_view_decorator_with_args``\n---------------------------------------\n\nThe ``@universal_view_decorator_with_args`` decorator is pretty much the same as ``@universal_view_decorator`` but\nit allows you to parametrize the wrapped decorator *after* wrapping it. This is very useful if you want to wrap\na decorator only once for reuse but the decorator has parameters that you don't want to specify when you do the\nwrapping:\n\n\n.. code-block:: python\n\n from django_universal_view_decorator import universal_view_decorator,\n universal_view_decorator_with_args\n\n\n # with @universal_view_decorator you have to bind args before wrapping :-(\n my_permission_required = universal_view_decorator(permission_required('my_app.my_permission'))\n\n # we can specify args for permission_required when we apply the decorator :-)\n universal_permission_required = universal_view_decorator_with_args(permission_required)\n\n\n @universal_permission_required('my_app.my_permission')\n def function_based_view(request):\n ...\n\n\n @universal_permission_required('my_app.my_permission')\n class ClassBasedView(View):\n ...\n\n\n class ClassBasedView(View):\n @universal_permission_required('my_app.my_permission')\n def dispatch(self, request, *args, **kwargs):\n ...\n\n\nInheritance\n===========\n\nSubclasses of a decorated view class inherit the decorators. In the following example ``DerivedView`` inherits a\n``@login_required`` decorator from its base class:\n\n\n.. code-block:: python\n\n from django_universal_view_decorator import universal_view_decorator\n\n\n @universal_view_decorator(login_required)\n class BaseView(View):\n ...\n\n\n @universal_view_decorator(permission_required('my_app.my_permission'))\n class DerivedView(View):\n ...\n\n\nThe inherited base class decorators are applied first. The above example has the same effect on ``DerivedView``\nas decorating it in a URLConf like this:\n\n\n.. code-block:: python\n\n urlpatterns = [\n url(r'^derived_view/', permission_required('my_app.my_permission')(login_required(DerivedView.as_view()))),\n ]", "description_content_type": null, "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/pasztorpisti/django-universal-view-decorator", "keywords": "django universal view class decorator", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "django-universal-view-decorator", "package_url": "https://pypi.org/project/django-universal-view-decorator/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/django-universal-view-decorator/", "project_urls": { "Homepage": "https://github.com/pasztorpisti/django-universal-view-decorator" }, "release_url": "https://pypi.org/project/django-universal-view-decorator/0.1.0/", "requires_dist": null, "requires_python": "", "summary": "Smart view class (CBV) decoration", "version": "0.1.0" }, "last_serial": 2092893, "releases": { "0.0.1": [ { "comment_text": "", "digests": { "md5": "8e65cf31ac0446be1c98eef45bc3aa1f", "sha256": "5d92248335af42ded0da6b2b02e4ec7500b2920cf8234f956c206a9f744203c9" }, "downloads": -1, "filename": "django_universal_view_decorator-0.0.1-py3-none-any.whl", "has_sig": false, "md5_digest": "8e65cf31ac0446be1c98eef45bc3aa1f", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 35922, "upload_time": "2016-04-06T16:20:03", "url": "https://files.pythonhosted.org/packages/6e/a6/1c26a6649ede4fb406761fef7c3d684016bcd30cf4f3d76e5c7df1f7428c/django_universal_view_decorator-0.0.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "a4795d850ae98d9407bc2c24c2b2f602", "sha256": "4adc2309722ee372015783c2ea353072edcf51b1d05c082f86b012bfbe4d4731" }, "downloads": -1, "filename": "django-universal-view-decorator-0.0.1.tar.gz", "has_sig": false, "md5_digest": "a4795d850ae98d9407bc2c24c2b2f602", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 29487, "upload_time": "2016-04-06T16:20:24", "url": "https://files.pythonhosted.org/packages/31/b9/6a2272032e425997b5c083ea541e3f52a394e20738983cec3abd5b1dda05/django-universal-view-decorator-0.0.1.tar.gz" } ], "0.0.2": [ { "comment_text": "", "digests": { "md5": "e565d62bbea2533919be8760783e10a5", "sha256": "8545b2bd830d92380e35b0be27be9a4dbf27994be83bb656b95ae67a40881fe8" }, "downloads": -1, "filename": "django_universal_view_decorator-0.0.2-py3-none-any.whl", "has_sig": false, "md5_digest": "e565d62bbea2533919be8760783e10a5", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 37558, "upload_time": "2016-04-07T15:16:10", "url": "https://files.pythonhosted.org/packages/39/fe/63e0bcb38916f5ead98d4f04ee148853ea59b7050fe069d69569062baec3/django_universal_view_decorator-0.0.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "36e87f2b57035faac4687dc2733d2958", "sha256": "088e3e91a4f84135681bf1fcf8c7e8e016e92d333a8854afd2460e9ff2a31ffa" }, "downloads": -1, "filename": "django-universal-view-decorator-0.0.2.tar.gz", "has_sig": false, "md5_digest": "36e87f2b57035faac4687dc2733d2958", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 31796, "upload_time": "2016-04-07T15:16:34", "url": "https://files.pythonhosted.org/packages/b5/2f/556734294f5e4709330814ea1c03866f394d5a41dfa7d5142066e76b4fd4/django-universal-view-decorator-0.0.2.tar.gz" } ], "0.0.3": [ { "comment_text": "", "digests": { "md5": "64c9273f45b29ca3bf18a7e05196eacb", "sha256": "e860e604c3ac2e3e280602bf7df95b1cb914c19ddd8a57cbbdda6c9cd4229f22" }, "downloads": -1, "filename": "django_universal_view_decorator-0.0.3-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "64c9273f45b29ca3bf18a7e05196eacb", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 23092, "upload_time": "2016-04-14T00:23:33", "url": "https://files.pythonhosted.org/packages/a3/9c/8f2c5bf9318ecfcdcf817d6ef894b4b4a7e6a3c4ed3af8b7e11df624da24/django_universal_view_decorator-0.0.3-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "4f3dfe94aa4502a9d7fe6299f63285df", "sha256": "305c19d4ba511ab10f1d8e14585b0692b79734aac2fca62364d1ba3a3ef31cb6" }, "downloads": -1, "filename": "django-universal-view-decorator-0.0.3.tar.gz", "has_sig": false, "md5_digest": "4f3dfe94aa4502a9d7fe6299f63285df", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 32473, "upload_time": "2016-04-12T00:01:38", "url": "https://files.pythonhosted.org/packages/bf/df/4a9f49784de382981a0b8b19d7be7182556bc5fedd59cd83ee70c992f546/django-universal-view-decorator-0.0.3.tar.gz" } ], "0.1.0": [ { "comment_text": "", "digests": { "md5": "92be28d209839cdc13b734068bd93c38", "sha256": "f85e4234a0c8353c8440ae7dbb70149ddf2a9b887a3df911da374ddb20dd7c09" }, "downloads": -1, "filename": "django_universal_view_decorator-0.1.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "92be28d209839cdc13b734068bd93c38", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 18792, "upload_time": "2016-04-30T23:15:50", "url": "https://files.pythonhosted.org/packages/e9/e9/1c81ce3c9c00fc6c1ee05d1213bc3534cb0e94affedbf4ece703b0874384/django_universal_view_decorator-0.1.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "2ebed785f1bb28236a7acb290122ccf1", "sha256": "2134e01e98669af78d7a8cd7b3570eee97aff4d8b3bf3105f94f0babc9088329" }, "downloads": -1, "filename": "django-universal-view-decorator-0.1.0.tar.gz", "has_sig": false, "md5_digest": "2ebed785f1bb28236a7acb290122ccf1", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 27904, "upload_time": "2016-04-30T23:15:57", "url": "https://files.pythonhosted.org/packages/0c/4a/7f026b7174e78980b17c2ca9ab26257bac37a4dae14ca403b0f643b52541/django-universal-view-decorator-0.1.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "92be28d209839cdc13b734068bd93c38", "sha256": "f85e4234a0c8353c8440ae7dbb70149ddf2a9b887a3df911da374ddb20dd7c09" }, "downloads": -1, "filename": "django_universal_view_decorator-0.1.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "92be28d209839cdc13b734068bd93c38", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 18792, "upload_time": "2016-04-30T23:15:50", "url": "https://files.pythonhosted.org/packages/e9/e9/1c81ce3c9c00fc6c1ee05d1213bc3534cb0e94affedbf4ece703b0874384/django_universal_view_decorator-0.1.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "2ebed785f1bb28236a7acb290122ccf1", "sha256": "2134e01e98669af78d7a8cd7b3570eee97aff4d8b3bf3105f94f0babc9088329" }, "downloads": -1, "filename": "django-universal-view-decorator-0.1.0.tar.gz", "has_sig": false, "md5_digest": "2ebed785f1bb28236a7acb290122ccf1", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 27904, "upload_time": "2016-04-30T23:15:57", "url": "https://files.pythonhosted.org/packages/0c/4a/7f026b7174e78980b17c2ca9ab26257bac37a4dae14ca403b0f643b52541/django-universal-view-decorator-0.1.0.tar.gz" } ] }