{ "info": { "author": "Ulas Tuerkmen", "author_email": "afroisalreadyinu@gmail.com", "bugtrack_url": null, "classifiers": [ "Framework :: Django" ], "description": "=============\ndjango-drapes\n=============\n\ndjango-drapes is a small library that aims to ease authorization and\nuser input verification. Most of the functionality is packed into\ndecorators intended for applying to views, hence the name\ndjango-drapes. The decorators:\n\n- verify_: Validate and convert values passed to a controller\n- require_: Check for permissions\n- verify_post_: Validate and process POST requests\n- render_with_: Render a dictionary with a template or json\n\nThere are also two template tags which can be used in combination with\nthese decorators:\n\n- if_allowed_: Display content depending on user permissions\n- modelview_: Output a model view\n\nDecorators\n==========\n\n.. _verify:\n\nverify\n------\n\n``verify`` is a decorator that turns values passed to the controller\ninto a more usable form (such as models), and throws suitable\nexceptions when this does not work. The conversions are specified as\nkeyword arguments with a validator matching the name of the controller\nargument. The validators have to implement the `formencode validator\ninterface `_.\n\nHere is a simple example::\n\n from django_drapes import verify\n import formencode\n\n @verify(int_arg=formencode.validators.Int())\n def controller(request, int_arg):\n \treturn 'Argument is %d' % int_arg\n\nThe controller receives ``int_arg`` as an integer, obviating the need\nto convert in the controller.\n\nThe values for the conversions are searched in the arguments for the\ncontroller function, and additionally the GET parameters if the\nrequest is a GET. This causes a mismatch between the url definition\nand the function signature, since one can't specify get parameters in\na url entry, and a controller normally has to look up a GET parameter\nin request.GET. Because of this mismatch, in case you want to verify a\nGET parameter, you should include this parameter as a keyword argument\nin the controller signature.\n\nThe most frequently done conversion is selecting a model with a unique\nfield. django-drapes has a built in validator for this kind of\nconversion, called ``ModelValidator``. It can be used as follows::\n\n from django.db import models\n from django_drapes import verify, ModelValidator\n\n class Project(models.Model):\n slug = models.SlugField(unique=True)\n\n @verify(item=ModelValidator(get_by='slug'))\n def controller(request, item):\n \treturn \"Item's slug is %s\" % item.slug\n\nAn advanced feature implemented by ``ModelValidator`` is looking up a\nmodel by multiple keys. In order to do this, you should initialize\n``ModelValidator`` with a list of strings as ``get_by``. These strings\nshould be in the form ``model_field=view_arg``, matching arguments to\na view to fields on a model. For example, let's assume that we have a\nproject where users can create items identified by slugs. Items\nbelonging to different users can have the same slug, and the page for\nsuch an item is identified by the name of the user and the slug of the\nitem. In that case, drapes decorators can be used as follows::\n\n @verify(owner=ModelValidator(User, get_by='username'))\n @verify(item=ModelValidator(Project, get_by=['slug=item','owner=owner']))\n @render_with('view_item.html')\n def view_item(request, owner, item):\n\treturn dict(item=item)\n\nThis case also demonstrates `Mixing the decorators`_.\n\n.. _require:\n\nrequire\n-------\n\n``require`` checks permissions on an incoming request to a controller.\nJust like validate, it accepts keyword arguments with key referring\neither to user (accessed through ``request.user``) or the positional\nor keyword arguments of a view function. Value must be a string\ncorresponding to the permission. What the permission refers to is\ndetermined in the following order:\n\n- An attribute of the object\n- A method of the object that does not require any arguments\n- A method of the model permission (a subclass of ModelPermission;\n see below) that accepts a user as argument.\n\nHere is a very simple example::\n\n from django.db import models\n from django_drapes import verify, ModelValidator\n import formencode\n\n class Thing(models.Model):\n slug = models.SlugField(unique=True)\n\tpublished = models.BooleanField(default=False)\n\n @verify(item=ModelValidator(Thing, get_by=slug))\n @require(user='is_authenticated',\n thing='published')\n def controller(request, thing):\n \treturn \"This thing's slug is %s\" % item.slug\n\nPermissions can be added to models by subclassing the ModelPermission\nclass, and setting a model as the class attribute::\n\n from django.db import models\n from django.shortcuts import render\n from django_drapes import (verify,\n ModelValidator,\n\t\t\t ModelPermission)\n\n class Thing(models.Model):\n slug = models.SlugField()\n\n class ThingPermissions(ModelPermission):\n model = Thing\n\tdef can_view(self, user):\n return user.username == 'horst'\n\n @verify(thing=ModelValidator(get_by=slug))\n @require(thing='can_view')\n def controller(request, thing):\n \treturn render(request, 'thing.htm', dict(thing=thing))\n\nThe only person who can view this item is the one named horst. The\ndefault selector used by ``ModelValidator`` is model id; this can be\noverriden using the ``get_by`` argument, as seen above.\n\n.. _verify_post:\n\nverify_post\n-----------\n\n``verify_post`` is a decorator for easing the workflow with form\ninput. The aim is to split the handling of user input through forms\ninto the presentation of empty or erronuous forms, and the processing\nof a valid form.\n\nThere are two ways to use verify_post. The first is the simple case,\nwhere the same entry point to an app should display a form for GET,\nand also process it when it gets POSTed. In this case,\n``verify_post.single`` should be used. This factory method accepts two\npositional arguments: the form used to verify the POST, and the\nhandler to call if the form validates::\n\n from django import forms\n from django_drapes import verify_post\n from django.http import HttpResponseRedirect\n from django.shortcuts import render_to_response\n #we are assuming the models exist somewhere\n from .models import Thing\n from django_drapes import (verify,\n verify_post,\n ModelValidator)\n\n class ThingForm(forms.Form):\n name = forms.CharField(required=True, min_length=4)\n\n def create_thing(request, item, form):\n thing = Thing(name=form.data['name'])\n thing.save()\n\treturn HttpResponseRedirect(thing.get_absolute_url())\n\n @verify(item=ModelValidator())\n @verify_post.single(ThingForm, create_thing)\n @require(item='can_view')\n def controller(request, item, invalid_form=None):\n \treturn render_to_response('form_template.html',\n\t dict(form=ThingForm()))\n\nSome notes on this example. When you are handling single forms, the\ncontroller must have a keyword argument ``invalid_form``. If the form\ndoes not validate, it is passed on to the controller through this\nargument. The handler of the correct form, in this case\n``create_thing``, must have the same signature as the controller,\nexcept for ``invalid_form``, which is replaced with ``form`` in the\nsignature of the correct handler.\n\nIf you want to use the same entry point to show and validate forms of\ndifferent kinds, you should use ``verify_post.multi``. This method\naccepts a list of form options specified with keyword arguments which\nare the names of the forms on the page. The form options have to be\ntuples specifying the form for validation and the valid form\nhandler. Here is an example::\n\n from django import forms\n from django_drapes import verify_post\n from .models import Thing, Organism\n\n class ThingForm(forms.Form):\n name = forms.CharField(required=True, min_length=4)\n\tdrape_form_name = forms.CharField(required=True,\n widget=forms.HiddenInput(),\n\t\t\t\t\t initial='thing_form')\n\n class OrganismForm(forms.Form):\n genus = forms.CharField(required=True, min_length=10)\n\tdrape_form_name = forms.CharField(required=True,\n widget=forms.HiddenInput(),\n\t\t\t\t\t initial='organism_form')\n\n def create_thing(request, form):\n Thing(name=form.data['name'])\n\n def create_organism(request, form):\n Organism(genus=form.data['genus'])\n\n @verify_post.multi(thing_form=(EntityForm, create_entity),\n organism_form=(OrganismsForm, create_organism))\n @require(item='can_view')\n def controller(request, item, invalid_form=None):\n \treturn render_to_response('form_template.html',\n\t dict(form=ThingForm()))\n\nAs it can be seen in this example, the hidden field\n``drape_form_name`` of a form has to match the keyword argument to\n``verify_post`` which specifies how that form should be handled.\n\nOne complication for which I couldn't come up with a decent solution\nis form validation with a user. In some cases, it is necessary to to\ninitialize a form class with a user; an example is when a value has to\nbe unique per user. In these cases, you have to set the keyword\nargument ``pass_user`` to ``True`` for ``verify_post.single``, and a\nthree-element tuple whose last element is ``True`` to\n``verify_post.multi``. Let me know in case you have a better solution.\n\n.. _render_with:\n\nrender_with\n-----------\n\nrender_with turns dictionary return values into rendered templates. It\nrequires a string as argument, signifying either a template path or\njson. render_with then calls django.shortcuts.render with the\ndictionary-like return value of the controller, and the template\nname::\n\n @render_with('test.htm')\n def controller(request):\n return dict(message='Hello world')\n\nThe default template can be overriden by setting a 'template' key in\nthe return dictionary to the desired template name. render_with also\nrespects return values which are subclasses of HttpResponse\n(e.g. HttpResponseRedirect). If you want to return something else from\nyour controller, do not use this decorator.\n\n.. _mixing:\n\nMixing the decorators\n---------------------\n\nAny number of these decorators can be applied to the same\ncontroller. The following is posible::\n\n @verify(model_inst=ModelValidator(MockModel,\n get_by='slug'))\n @require(model_inst='can_view',\n user='is_authenticated')\n @verify_post.single(ThingForm, create_thing)\n @render_with('some_template.html')\n def controller(request, model_inst):\n return model_inst.message\n\nThe principle here is that if a decorator depends on the conversions\nof another, it should come after it.\n\nTemplate tags\n=============\n\ndjango-drapes comes with two template tags which make it possible to\nrefer to permission classes, and to render pieces of html from a\nmodel. These tags are if_allowed and modelview.\n\n.. _if_allowed:\n\nif_allowed\n----------\n\n``if_allowed`` is a tag which conditionally renders content based on\nthe outcome of a permission applied to a user. Let's have an example\nfor a change. Model and permissions::\n\n from django.db import models\n from django_drapes import ModelPermission\n\n class Thing(models.Model):\n slug = models.SlugField(unique=True)\n\n class ThingPermissions(ModelPermission):\n model = Thing\n\n\tdef can_view(self, user):\n\t return user.username == 'horst'\n\nAnd then in the template which gets rendered with a user and a thing,\nyou can do the following::\n\n {% load wherever_you_put_the_tags %}\n {% if_allowed user can_view thing %}\n {{thing.get_absolute_url}}\n {% else %}\n For horst's eyes only\n {% end_if_allowed %}\n\nIf your username is not horst, you will see 'For horst's eyes only'.\n\n.. _modelview:\n\nmodelview\n---------\n\nThe other template tag is a helper called ``modelview``. In order to\ninsert markup representing an aspect of a model, you can subclass\n``ModelView``, and set its class attribute model to a django\nmodel. Attributes of this model can later be referred to in a template\nusing the ``modelview`` template tag::\n\n from django.db import models\n from django.template.loader import get_template\n from django.template import Context\n from django_drapes import ModelView\n\n class Thing(models.Model):\n slug = models.SlugField(unique=True)\n\n class ThingView(ModelView):\n model = MockModel\n\n def some_view(self, arg1, arg2=None):\n template = get_template('thing_some_view.html')\n #do stuff with arg1 and arg2 ...\n return template.render(Context(dict(thing=self)))\n\nIt is advised to use template.render here, since this way you don't\nget a response with the full HTTP headers. A nice feature of this\ntemplate tag is that it will pass on any arguments you are calling it\nwith to the view function.\n\nIf you want to get the output of a model view outside of a template,\nyou can use the view function named just ``v`` to get the ModelView\nfor a model instance::\n\n from django_drapes import verify, ModelValidator, v\n from .models import Thing\n\n @verify(thing=ModelValidator(Thing,\n get_by='slug'))\n def just_some_view(request, thing):\n return v(thing).some_view()\n\nRegistering the template tags\n-----------------------------\n\nSince django-drapes is not organized as an app, both of these tags\nhave to be manually registered to be used in templates. You can do\nthis by creating a templatetags folder in one of your project apps,\nand then including the following in a file there::\n\n from django import template\n from django_drapes import model_permission, modelview\n register = template.Library()\n register.tag('if_allowed', model_permission)\n register.tag('modelview', modelview)\n\nYou are free to change the names of the tags, of course.", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "UNKNOWN", "keywords": null, "license": "UNKNOWN", "maintainer": null, "maintainer_email": null, "name": "django-drapes", "package_url": "https://pypi.org/project/django-drapes/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/django-drapes/", "project_urls": { "Download": "UNKNOWN", "Homepage": "UNKNOWN" }, "release_url": "https://pypi.org/project/django-drapes/0.1.2/", "requires_dist": null, "requires_python": null, "summary": "Some decorators and classes to make working with django projects easier.", "version": "0.1.2" }, "last_serial": 789504, "releases": { "0.1": [ { "comment_text": "", "digests": { "md5": "f1de86f5d063fdd2fcccbeaacdaa4cbb", "sha256": "79faa553cfe402ad71e2f12b1cf3bba63606fa01822130a69d9c440184927761" }, "downloads": -1, "filename": "django-drapes-0.1.tar.gz", "has_sig": false, "md5_digest": "f1de86f5d063fdd2fcccbeaacdaa4cbb", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9444, "upload_time": "2012-03-14T18:45:09", "url": "https://files.pythonhosted.org/packages/48/5e/da9587aa9859696985d32c776afa2c5fa7aa0c19cf3fbf740fc24a4750d6/django-drapes-0.1.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "4439efc24d6e4643880abef09a31a0b0", "sha256": "99dc80a2934a0d861e036842416bd7322dd5a6a1ed61db5fe980d00a6ba5beb5" }, "downloads": -1, "filename": "django-drapes-0.1.1.tar.gz", "has_sig": false, "md5_digest": "4439efc24d6e4643880abef09a31a0b0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10866, "upload_time": "2012-03-14T19:08:54", "url": "https://files.pythonhosted.org/packages/be/24/9c2da78f3ef6f1282fa5ad1097a01d013716e47896505b9f52a950781094/django-drapes-0.1.1.tar.gz" } ], "0.1.2": [ { "comment_text": "", "digests": { "md5": "be8e70c4b57a6a06dcd2eaae4a48b3a5", "sha256": "f1265092ffb6e21d5b5bf4a3c2fb40311b1762e95f8855e519aac81ca3e2267b" }, "downloads": -1, "filename": "django-drapes-0.1.2.tar.gz", "has_sig": false, "md5_digest": "be8e70c4b57a6a06dcd2eaae4a48b3a5", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9619, "upload_time": "2012-04-02T15:43:56", "url": "https://files.pythonhosted.org/packages/19/18/93190252c93a7ba81d6c310b38e4853447d715260c3b3b2101365c66d56d/django-drapes-0.1.2.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "be8e70c4b57a6a06dcd2eaae4a48b3a5", "sha256": "f1265092ffb6e21d5b5bf4a3c2fb40311b1762e95f8855e519aac81ca3e2267b" }, "downloads": -1, "filename": "django-drapes-0.1.2.tar.gz", "has_sig": false, "md5_digest": "be8e70c4b57a6a06dcd2eaae4a48b3a5", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9619, "upload_time": "2012-04-02T15:43:56", "url": "https://files.pythonhosted.org/packages/19/18/93190252c93a7ba81d6c310b38e4853447d715260c3b3b2101365c66d56d/django-drapes-0.1.2.tar.gz" } ] }