summaryrefslogtreecommitdiffstats
path: root/webapp/django/contrib/databrowse/sites.py
diff options
context:
space:
mode:
Diffstat (limited to 'webapp/django/contrib/databrowse/sites.py')
-rw-r--r--webapp/django/contrib/databrowse/sites.py149
1 files changed, 149 insertions, 0 deletions
diff --git a/webapp/django/contrib/databrowse/sites.py b/webapp/django/contrib/databrowse/sites.py
new file mode 100644
index 0000000000..9ef35dbc1c
--- /dev/null
+++ b/webapp/django/contrib/databrowse/sites.py
@@ -0,0 +1,149 @@
+from django import http
+from django.db import models
+from django.contrib.databrowse.datastructures import EasyModel
+from django.shortcuts import render_to_response
+from django.utils.safestring import mark_safe
+
+class AlreadyRegistered(Exception):
+ pass
+
+class NotRegistered(Exception):
+ pass
+
+class DatabrowsePlugin(object):
+ def urls(self, plugin_name, easy_instance_field):
+ """
+ Given an EasyInstanceField object, returns a list of URLs for this
+ plugin's views of this object. These URLs should be absolute.
+
+ Returns None if the EasyInstanceField object doesn't get a
+ list of plugin-specific URLs.
+ """
+ return None
+
+ def model_index_html(self, request, model, site):
+ """
+ Returns a snippet of HTML to include on the model index page.
+ """
+ return ''
+
+ def model_view(self, request, model_databrowse, url):
+ """
+ Handles main URL routing for a plugin's model-specific pages.
+ """
+ raise NotImplementedError
+
+class ModelDatabrowse(object):
+ plugins = {}
+
+ def __init__(self, model, site):
+ self.model = model
+ self.site = site
+
+ def root(self, request, url):
+ """
+ Handles main URL routing for the databrowse app.
+
+ `url` is the remainder of the URL -- e.g. 'objects/3'.
+ """
+ # Delegate to the appropriate method, based on the URL.
+ if url is None:
+ return self.main_view(request)
+ try:
+ plugin_name, rest_of_url = url.split('/', 1)
+ except ValueError: # need more than 1 value to unpack
+ plugin_name, rest_of_url = url, None
+ try:
+ plugin = self.plugins[plugin_name]
+ except KeyError:
+ raise http.Http404('A plugin with the requested name does not exist.')
+ return plugin.model_view(request, self, rest_of_url)
+
+ def main_view(self, request):
+ easy_model = EasyModel(self.site, self.model)
+ html_snippets = mark_safe(u'\n'.join([p.model_index_html(request, self.model, self.site) for p in self.plugins.values()]))
+ return render_to_response('databrowse/model_detail.html', {
+ 'model': easy_model,
+ 'root_url': self.site.root_url,
+ 'plugin_html': html_snippets,
+ })
+
+class DatabrowseSite(object):
+ def __init__(self):
+ self.registry = {} # model_class -> databrowse_class
+ self.root_url = None
+
+ def register(self, model_or_iterable, databrowse_class=None, **options):
+ """
+ Registers the given model(s) with the given databrowse site.
+
+ The model(s) should be Model classes, not instances.
+
+ If a databrowse class isn't given, it will use DefaultModelDatabrowse
+ (the default databrowse options).
+
+ If a model is already registered, this will raise AlreadyRegistered.
+ """
+ databrowse_class = databrowse_class or DefaultModelDatabrowse
+ if issubclass(model_or_iterable, models.Model):
+ model_or_iterable = [model_or_iterable]
+ for model in model_or_iterable:
+ if model in self.registry:
+ raise AlreadyRegistered('The model %s is already registered' % model.__class__.__name__)
+ self.registry[model] = databrowse_class
+
+ def unregister(self, model_or_iterable):
+ """
+ Unregisters the given model(s).
+
+ If a model isn't already registered, this will raise NotRegistered.
+ """
+ if issubclass(model_or_iterable, models.Model):
+ model_or_iterable = [model_or_iterable]
+ for model in model_or_iterable:
+ if model not in self.registry:
+ raise NotRegistered('The model %s is not registered' % model.__class__.__name__)
+ del self.registry[model]
+
+ def root(self, request, url):
+ """
+ Handles main URL routing for the databrowse app.
+
+ `url` is the remainder of the URL -- e.g. 'comments/comment/'.
+ """
+ self.root_url = request.path[:len(request.path) - len(url)]
+ url = url.rstrip('/') # Trim trailing slash, if it exists.
+
+ if url == '':
+ return self.index(request)
+ elif '/' in url:
+ return self.model_page(request, *url.split('/', 2))
+
+ raise http.Http404('The requested databrowse page does not exist.')
+
+ def index(self, request):
+ m_list = [EasyModel(self, m) for m in self.registry.keys()]
+ return render_to_response('databrowse/homepage.html', {'model_list': m_list, 'root_url': self.root_url})
+
+ def model_page(self, request, app_label, model_name, rest_of_url=None):
+ """
+ Handles the model-specific functionality of the databrowse site, delegating
+ to the appropriate ModelDatabrowse class.
+ """
+ model = models.get_model(app_label, model_name)
+ if model is None:
+ raise http.Http404("App %r, model %r, not found." % (app_label, model_name))
+ try:
+ databrowse_class = self.registry[model]
+ except KeyError:
+ raise http.Http404("This model exists but has not been registered with databrowse.")
+ return databrowse_class(model, self).root(request, rest_of_url)
+
+site = DatabrowseSite()
+
+from django.contrib.databrowse.plugins.calendars import CalendarPlugin
+from django.contrib.databrowse.plugins.objects import ObjectDetailPlugin
+from django.contrib.databrowse.plugins.fieldchoices import FieldChoicePlugin
+
+class DefaultModelDatabrowse(ModelDatabrowse):
+ plugins = {'objects': ObjectDetailPlugin(), 'calendars': CalendarPlugin(), 'fields': FieldChoicePlugin()}