2007-04-17 05:56:10 +08:00
|
|
|
from django import http
|
|
|
|
from django.db import models
|
2008-07-22 11:24:09 +08:00
|
|
|
from django.contrib.databrowse.datastructures import EasyModel
|
2007-04-17 05:56:10 +08:00
|
|
|
from django.shortcuts import render_to_response
|
2007-11-14 20:58:53 +08:00
|
|
|
from django.utils.safestring import mark_safe
|
2007-04-17 05:56:10 +08:00
|
|
|
|
|
|
|
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)
|
2007-11-14 20:58:53 +08:00
|
|
|
html_snippets = mark_safe(u'\n'.join([p.model_index_html(request, self.model, self.site) for p in self.plugins.values()]))
|
2007-04-17 05:56:10 +08:00
|
|
|
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
|
|
|
|
|
2012-01-29 04:54:48 +08:00
|
|
|
def register(self, *model_list, **options):
|
2007-04-17 05:56:10 +08:00
|
|
|
"""
|
|
|
|
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.
|
|
|
|
"""
|
2012-01-29 04:54:48 +08:00
|
|
|
databrowse_class = options.pop('databrowse_class', DefaultModelDatabrowse)
|
|
|
|
for model in model_list:
|
2007-04-17 05:56:10 +08:00
|
|
|
if model in self.registry:
|
2008-08-26 02:32:26 +08:00
|
|
|
raise AlreadyRegistered('The model %s is already registered' % model.__name__)
|
2007-04-17 05:56:10 +08:00
|
|
|
self.registry[model] = databrowse_class
|
|
|
|
|
2012-01-29 04:54:48 +08:00
|
|
|
def unregister(self, *model_list):
|
2007-04-17 05:56:10 +08:00
|
|
|
"""
|
|
|
|
Unregisters the given model(s).
|
|
|
|
|
|
|
|
If a model isn't already registered, this will raise NotRegistered.
|
|
|
|
"""
|
2012-01-29 04:54:48 +08:00
|
|
|
for model in model_list:
|
2007-04-17 05:56:10 +08:00
|
|
|
if model not in self.registry:
|
2008-08-26 02:32:26 +08:00
|
|
|
raise NotRegistered('The model %s is not registered' % model.__name__)
|
2007-04-17 05:56:10 +08:00
|
|
|
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()}
|