Implemented auto-escaping of variable output in templates. Fully controllable by...
[django.git] / django / contrib / databrowse / sites.py
blob5d8c1c8b494dd8986b166b6f03074c50047dc0dd
1 from django import http
2 from django.db import models
3 from django.contrib.databrowse.datastructures import EasyModel, EasyChoice
4 from django.shortcuts import render_to_response
5 from django.utils.safestring import mark_safe
7 class AlreadyRegistered(Exception):
8 pass
10 class NotRegistered(Exception):
11 pass
13 class DatabrowsePlugin(object):
14 def urls(self, plugin_name, easy_instance_field):
15 """
16 Given an EasyInstanceField object, returns a list of URLs for this
17 plugin's views of this object. These URLs should be absolute.
19 Returns None if the EasyInstanceField object doesn't get a
20 list of plugin-specific URLs.
21 """
22 return None
24 def model_index_html(self, request, model, site):
25 """
26 Returns a snippet of HTML to include on the model index page.
27 """
28 return ''
30 def model_view(self, request, model_databrowse, url):
31 """
32 Handles main URL routing for a plugin's model-specific pages.
33 """
34 raise NotImplementedError
36 class ModelDatabrowse(object):
37 plugins = {}
39 def __init__(self, model, site):
40 self.model = model
41 self.site = site
43 def root(self, request, url):
44 """
45 Handles main URL routing for the databrowse app.
47 `url` is the remainder of the URL -- e.g. 'objects/3'.
48 """
49 # Delegate to the appropriate method, based on the URL.
50 if url is None:
51 return self.main_view(request)
52 try:
53 plugin_name, rest_of_url = url.split('/', 1)
54 except ValueError: # need more than 1 value to unpack
55 plugin_name, rest_of_url = url, None
56 try:
57 plugin = self.plugins[plugin_name]
58 except KeyError:
59 raise http.Http404('A plugin with the requested name does not exist.')
60 return plugin.model_view(request, self, rest_of_url)
62 def main_view(self, request):
63 easy_model = EasyModel(self.site, self.model)
64 html_snippets = mark_safe(u'\n'.join([p.model_index_html(request, self.model, self.site) for p in self.plugins.values()]))
65 return render_to_response('databrowse/model_detail.html', {
66 'model': easy_model,
67 'root_url': self.site.root_url,
68 'plugin_html': html_snippets,
71 class DatabrowseSite(object):
72 def __init__(self):
73 self.registry = {} # model_class -> databrowse_class
74 self.root_url = None
76 def register(self, model_or_iterable, databrowse_class=None, **options):
77 """
78 Registers the given model(s) with the given databrowse site.
80 The model(s) should be Model classes, not instances.
82 If a databrowse class isn't given, it will use DefaultModelDatabrowse
83 (the default databrowse options).
85 If a model is already registered, this will raise AlreadyRegistered.
86 """
87 databrowse_class = databrowse_class or DefaultModelDatabrowse
88 if issubclass(model_or_iterable, models.Model):
89 model_or_iterable = [model_or_iterable]
90 for model in model_or_iterable:
91 if model in self.registry:
92 raise AlreadyRegistered('The model %s is already registered' % model.__class__.__name__)
93 self.registry[model] = databrowse_class
95 def unregister(self, model_or_iterable):
96 """
97 Unregisters the given model(s).
99 If a model isn't already registered, this will raise NotRegistered.
101 if issubclass(model_or_iterable, models.Model):
102 model_or_iterable = [model_or_iterable]
103 for model in model_or_iterable:
104 if model not in self.registry:
105 raise NotRegistered('The model %s is not registered' % model.__class__.__name__)
106 del self.registry[model]
108 def root(self, request, url):
110 Handles main URL routing for the databrowse app.
112 `url` is the remainder of the URL -- e.g. 'comments/comment/'.
114 self.root_url = request.path[:len(request.path) - len(url)]
115 url = url.rstrip('/') # Trim trailing slash, if it exists.
117 if url == '':
118 return self.index(request)
119 elif '/' in url:
120 return self.model_page(request, *url.split('/', 2))
122 raise http.Http404('The requested databrowse page does not exist.')
124 def index(self, request):
125 m_list = [EasyModel(self, m) for m in self.registry.keys()]
126 return render_to_response('databrowse/homepage.html', {'model_list': m_list, 'root_url': self.root_url})
128 def model_page(self, request, app_label, model_name, rest_of_url=None):
130 Handles the model-specific functionality of the databrowse site, delegating
131 to the appropriate ModelDatabrowse class.
133 model = models.get_model(app_label, model_name)
134 if model is None:
135 raise http.Http404("App %r, model %r, not found." % (app_label, model_name))
136 try:
137 databrowse_class = self.registry[model]
138 except KeyError:
139 raise http.Http404("This model exists but has not been registered with databrowse.")
140 return databrowse_class(model, self).root(request, rest_of_url)
142 site = DatabrowseSite()
144 from django.contrib.databrowse.plugins.calendars import CalendarPlugin
145 from django.contrib.databrowse.plugins.objects import ObjectDetailPlugin
146 from django.contrib.databrowse.plugins.fieldchoices import FieldChoicePlugin
148 class DefaultModelDatabrowse(ModelDatabrowse):
149 plugins = {'objects': ObjectDetailPlugin(), 'calendars': CalendarPlugin(), 'fields': FieldChoicePlugin()}