Commits

David Larlet committed 8a651a4

Adding some real code

Comments (0)

Files changed (14)

djangorators/__init__.py

+
+from permissions import owner_required
+from related import from_object, from_queryset
+from rendering import as_html

djangorators/models.py

Empty file added.

djangorators/permissions.py

+from django.http import HttpResponseNotFound
+
+def owner_required(func):
+    """
+    Warning: depends on from_object's djangorator for the related_* access.
+    """
+    def _dec(request, *args, **kwargs):
+        if 'related_object' in kwargs:
+            if kwargs['related_object'].owner == request.user:
+                return func(request, *args, **kwargs)
+        elif 'related_queryset' in kwargs:
+            kwargs['related_queryset'] = kwargs['related_queryset'].filter(owner=request.user)
+            return func(request, *args, **kwargs)
+        
+        return HttpResponseNotFound()
+    return _dec

djangorators/related.py

+from django.shortcuts import get_object_or_404
+
+def from_object(object_class):
+    def wrap(func):
+        def _dec(request, *args, **kwargs):
+            object_id = kwargs['%s_id' % object_class.__name__.lower()]
+            kwargs['related_object'] = get_object_or_404(object_class, id=object_id)
+            return func(request, *args, **kwargs)
+        return _dec
+    return wrap
+
+def from_queryset(queryset):
+    def wrap(func):
+        def _dec(request, *args, **kwargs):
+            kwargs['related_queryset'] = queryset
+            return func(request, *args, **kwargs)
+        return _dec
+    return wrap

djangorators/rendering.py

+from django.views.generic.simple import direct_to_template
+from django.http import HttpResponse, HttpResponseRedirect, HttpResponseNotFound
+
+def as_html(template_name):
+    def wrap(func):
+        def _dec(request, *args, **kwargs):
+            response = func(request, *args, **kwargs)
+            # TODO: add more, or even better find an elegant hack :)
+            http_responses = (HttpResponse, HttpResponseRedirect, HttpResponseNotFound)
+            if isinstance(response, http_responses):
+                return response
+            # Otherwise, the response is a context which is rendered
+            return direct_to_template(request, template_name, response)
+        return _dec
+    return wrap

examples/djangorators_testproject/__init__.py

Empty file added.

examples/djangorators_testproject/manage.py

+import sys, os
+sys.path.insert(0, os.path.split(os.path.split(os.getcwd())[0])[0])
+
+from django.core.management import execute_manager
+
+try:
+    import settings # Assumed to be in the same directory.
+except ImportError:
+    import sys
+    sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
+    sys.exit(1)
+
+if __name__ == "__main__":
+    execute_manager(settings)

examples/djangorators_testproject/models.py

+from django.db import models
+from django.contrib.auth.models import User
+
+class Animal(models.Model):
+    name = models.CharField(max_length=50)
+    owner = models.ForeignKey(User)
+    
+    def __unicode__(self):
+        return u'%s owned by %s' % (self.name, self.owner)

examples/djangorators_testproject/settings.py

+import os
+ROOT_PATH = os.path.dirname(__file__)
+
+TEMPLATE_DEBUG = DEBUG = True
+MANAGERS = ADMINS = ()
+DATABASE_ENGINE = 'sqlite3'
+DATABASE_NAME = os.path.join(ROOT_PATH, 'testdb.sqlite')
+
+TIME_ZONE = 'America/Chicago'
+LANGUAGE_CODE = 'en-us'
+SITE_ID = 1
+USE_I18N = True
+MEDIA_ROOT = ''
+MEDIA_URL = ''
+ADMIN_MEDIA_PREFIX = '/media/'
+SECRET_KEY = '2+@4vnr#v8e273^+a)g$8%dre^dwcn#d&n#8+l6jk7r#$p&3zk'
+TEMPLATE_LOADERS = (
+    'django.template.loaders.filesystem.load_template_source',
+    'django.template.loaders.app_directories.load_template_source',
+)
+TEMPLATE_CONTEXT_PROCESSORS = (
+    "django.core.context_processors.auth",
+    "django.core.context_processors.debug",
+    "django.core.context_processors.i18n",
+    "django.core.context_processors.request",
+)
+MIDDLEWARE_CLASSES = (
+    'django.middleware.common.CommonMiddleware',
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
+)
+ROOT_URLCONF = 'urls'
+TEMPLATE_DIRS = (os.path.join(ROOT_PATH, 'templates'),)
+INSTALLED_APPS = (
+    'djangorators',
+    'djangorators_testproject',
+    'django.contrib.auth',
+    'django.contrib.admin',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+)

examples/djangorators_testproject/templates/animals/item.html

+{{ animal }}

examples/djangorators_testproject/templates/animals/list.html

+{% for animal in animals %}
+  {{ animal }}
+{% endfor %}

examples/djangorators_testproject/tests.py

+r"""
+    >>> from django.test.client import Client
+    >>> from django.contrib.auth.models import User
+    >>> from django.core.urlresolvers import reverse
+    >>> from djangorators_testproject.models import Animal
+    
+    >>> alice = User.objects.create_user('alice', 'alice@example.org', 'wonderful')
+    >>> c = Client()
+    >>> c.login(username='alice', password='wonderful')
+    True
+    
+    >>> cat = Animal.objects.create(name=u"cat", owner=alice)
+    >>> response = c.get(reverse('classic_animal_item', args=(cat.id,)))
+    >>> response.context['animal']
+    <Animal: cat (updated) owned by alice>
+    >>> print response.content
+    cat (updated) owned by alice
+    <BLANKLINE>
+    
+    >>> response = c.get(reverse('decorated_animal_item', args=(cat.id,)))
+    >>> response.context['animal']
+    <Animal: cat (updated) (updated) owned by alice>
+    >>> print response.content
+    cat (updated) (updated) owned by alice
+    <BLANKLINE>
+
+    >>> lion = Animal.objects.create(name=u"lion", owner=alice)
+
+    >>> response = c.get(reverse('classic_animal_list'))
+    >>> response.context['animals']
+    [<Animal: cat (updated) (updated) owned by alice>]
+    >>> print response.content
+    <BLANKLINE>
+      cat (updated) (updated) owned by alice
+    <BLANKLINE>
+    <BLANKLINE>
+
+    >>> response = c.get(reverse('decorated_animal_list'))
+    >>> response.context['animals']
+    [<Animal: cat (updated) (updated) owned by alice>]
+    >>> print response.content
+    <BLANKLINE>
+      cat (updated) (updated) owned by alice
+    <BLANKLINE>
+    <BLANKLINE>
+
+"""

examples/djangorators_testproject/urls.py

+from django.conf.urls.defaults import *
+
+from djangorators_testproject.views import classic_animal_item, classic_animal_list, \
+    decorated_animal_item, decorated_animal_list
+
+urlpatterns = patterns('',
+    url(r'^classic/animals/(?P<animal_id>\d+)/$',       classic_animal_item,    name='classic_animal_item'),
+    url(r'^classic/animals/$',                          classic_animal_list,    name='classic_animal_list'),
+    url(r'^decorated/animals/(?P<animal_id>\d+)/$',     decorated_animal_item,  name='decorated_animal_item'),
+    url(r'^decorated/animals/$',                        decorated_animal_list,  name='decorated_animal_list'),
+)

examples/djangorators_testproject/views.py

+from django.http import HttpResponseNotFound
+from django.shortcuts import get_object_or_404
+from django.views.generic.simple import direct_to_template
+
+from djangorators import from_object, from_queryset, owner_required, as_html
+from djangorators_testproject.models import Animal
+
+def classic_animal_item(request, animal_id):
+    # Retrieve item instance
+    animal = get_object_or_404(Animal, id=animal_id)
+    
+    # Check permissions
+    if animal.owner != request.user:
+        return HttpResponseNotFound()
+    
+    # Do something useful (isn't it?)
+    animal.name = '%s (updated)' % animal.name
+    animal.save()
+    
+    # Render response
+    return direct_to_template(request, 'animals/item.html', locals())
+
+@from_object(Animal)
+@owner_required
+@as_html('animals/item.html')
+def decorated_animal_item(request, *args, **kwargs):
+    animal = kwargs['related_object']
+    
+    # Only do something useful
+    animal.name = '%s (updated)' % animal.name
+    animal.save()
+    
+    return locals()
+
+def classic_animal_list(request):
+    # Retrieve queryset
+    animals = Animal.objects.all()
+    
+    # Check permissions
+    animals = animals.filter(owner=request.user)
+    
+    # Do something useful
+    animals = animals.exclude(name=u'lion')
+    
+    # Render response
+    return direct_to_template(request, 'animals/list.html', locals())    
+
+@from_queryset(Animal.objects.all())
+@owner_required
+@as_html('animals/list.html')
+def decorated_animal_list(request, *args, **kwargs):
+    animals = kwargs['related_queryset']
+    
+    # Only do something useful
+    animals = animals.exclude(name=u'lion')
+    
+    return locals()