/usr/share/pyshared/lazr/restful/docs/django.txt is in python-lazr.restful 0.9.29-0ubuntu2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 | Django integration
******************
lazr.restful includes some code to make it easier to publish Django
model objects as web service resources.
Setup
=====
lazr.restful doesn't depend on Django, but these tests need access to
Django-like modules and classes. We're going to create some fake
modules and classes for purposes of the tests. If Django is actually
installed on this system, these modules will mask the real modules, but
it'll only last until the end of the test.
>>> import sys
>>> import types
>>> def create_fake_module(name):
... previous = None
... previous_names = []
... for module_name in name.split('.'):
... previous_names.append(module_name)
... full_name = '.'.join(previous_names)
... module = sys.modules.get(full_name)
... if module is None:
... module = types.ModuleType(full_name)
... if previous is not None:
... setattr(previous, module_name, module)
... previous = module
... sys.modules[full_name] = module
Before loading django.zcml, we need to create fake versions of all the
modules and classes we'll be using, because if the real Django happens
to be installed, loading the real Django classes will trigger all
sorts of Django code that we can't handle.
>>> create_fake_module('settings')
>>> import settings
>>> class ObjectDoesNotExist(Exception):
... pass
>>> create_fake_module('django.core.exceptions')
>>> import django.core.exceptions
>>> django.core.exceptions.ObjectDoesNotExist = ObjectDoesNotExist
>>> class Manager(object):
... """A fake version of Django's Manager class."""
... def __init__(self, l):
... self.list = l
... def iterator(self):
... return self.list.__iter__()
... def all(self):
... return self.list
... def count(self):
... return len(self.list)
>>> create_fake_module('django.db.models.manager')
>>> import django.db.models.manager
>>> django.db.models.manager.Manager = Manager
Now we can load a ZCML configuration typical of a lazr.restful
application that publishes Django model objects through a web service.
>>> from zope.configuration import xmlconfig
>>> ignore = xmlconfig.string("""
... <configure xmlns="http://namespaces.zope.org/zope">
... <include package="lazr.restful" file="basic-site.zcml" />
... <include package="lazr.restful.frameworks" file="django.zcml" />
... </configure>
... """)
Configuration
=============
Like any lazr.restful app, a Django app can subclass
BaseWebServiceConfiguration and customize the subclass to set
configuration options. However, you might find it easier to subclass
DjangoWebServiceConfiguration instead and put the configuration in
your settings.py file.
An attribute 'foo_bar' defined in IWebServiceConfiguration can be set
in your settings.py file as LAZR_RESTFUL_FOO_BAR. Here, we'll override
the default value of 'show_tracebacks'.
>>> settings.LAZR_RESTFUL_SHOW_TRACEBACKS = False
>>> from lazr.restful.frameworks.django import (
... DjangoWebServiceConfiguration)
>>> class MyConfiguration(DjangoWebServiceConfiguration):
... pass
>>> MyConfiguration().show_tracebacks
True
Once grok is called on the configuration class...
>>> from grokcore.component.testing import grok_component
>>> ignored = grok_component('MyConfiguration', MyConfiguration)
...MyConfiguration is the registered utility for
IWebServiceConfiguration, and its value for use_https and
show_tracebacks have been taken from the 'settings' module.
>>> from zope.component import getUtility
>>> from lazr.restful.interfaces import IWebServiceConfiguration
>>> utility = getUtility(IWebServiceConfiguration)
>>> utility.show_tracebacks
False
Attributes that don't have values in settings.py are given their
default value.
>>> utility.active_versions
[]
>>> utility.use_https
True
IDjangoLocation
===============
The simplest way to generate URLs for your resources is to have your
service root resource implement IAbsoluteURL (to generate the root of
all web service URLs), and have all your model classes implement
ILocation (which defines the URL in terms of a parent object's
URL).
ILocation requires that you define a property called __name__. This is
part of the URL unique to an object, as opposed to the first part of
the URL, which comes from its parent. Unfortunately, the Django object
metaclass won't allow you to assign a property to __name__.
IDjangoLocation is a class provided by lazr.restful. It acts just like
ILocation, but the last part of the URL comes from __url_path__
instead of __name__.
Here's some setup; a root resource that has its own AbsoluteURL
implementation.
>>> from lazr.restful.testing.webservice import (
... DummyRootResource, DummyRootResourceURL)
>>> from zope.component import getSiteManager
>>> sm = getSiteManager()
>>> sm.registerAdapter(DummyRootResourceURL)
Now here's a subordinate resource that just implements IDjangoLocatino.
>>> from zope.interface import implements
>>> from lazr.restful.frameworks.django import IDjangoLocation
>>> class SubordinateResource:
... implements(IDjangoLocation)
...
... @property
... def __parent__(self):
... return DummyRootResource()
...
... @property
... def __url_path__(self):
... return "myname"
The django.zcml file in lazr/restful/frameworks contains an adapter
between IDjangoLocation and ILocation. Thanks to that adapter, it's
possible to adapt a Django model object to ILocation and check on its
__name__.
>>> from zope.location.interfaces import ILocation
>>> resource = SubordinateResource()
>>> as_location = ILocation(resource)
>>> print as_location.__name__
myname
It's also possible to adapt a Django model object to IAbsoluteURL and
get its full URL.
>>> from zope.component import getMultiAdapter
>>> from zope.traversing.browser.interfaces import IAbsoluteURL
>>> from lazr.restful.simple import Request
>>> request = Request("", {})
>>> print str(getMultiAdapter((resource, request), IAbsoluteURL))
http://dummy/myname
ObjectDoesNotExist
==================
The django.zcml helper file contains an adapter registration so that
Django's ObjectDoesNotExist exceptions are treated as 404
errors.
To test this, we simply instantiate an ObjectDoesNotExist and then get
a view for it.
>>> exception = ObjectDoesNotExist()
>>> view = getMultiAdapter((exception, request), name="index.html")
>>> view()
''
The view for the ObjectDoesNotExist exception sets the HTTP response
code to 404.
>>> request.response.getStatus()
404
Managers
========
The django.zcml file includes an adapter between Django's Manager
class (which controls access to the database) and Zope's
IFiniteCollection interface (used by lazr.batchnavigator to batch data
sets).
>>> from zope.interface.common.sequence import IFiniteSequence
>>> data = ["foo", "bar", "baz"]
>>> from django.db.models.manager import Manager
>>> manager = Manager(data)
>>> sequence = IFiniteSequence(manager)
The adapter class is ManagerSequencer.
>>> sequence
<lazr.restful.frameworks.django.ManagerSequencer...>
A ManagerSequencer object makes a Manager object act like a Python
list, which is what IFiniteSequence needs.
>>> len(sequence)
3
>>> print sequence[1]
bar
>>> sequence[1:3]
['bar', 'baz']
>>> [x for x in sequence]
['foo', 'bar', 'baz']
|