Hello site
[auf_framonde.git] / eggs / Django-1.4.5-py2.7.egg / django / contrib / admindocs / views.py
1 import inspect
2 import os
3 import re
4
5 from django import template
6 from django.template import RequestContext
7 from django.conf import settings
8 from django.contrib.admin.views.decorators import staff_member_required
9 from django.db import models
10 from django.shortcuts import render_to_response
11 from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
12 from django.http import Http404
13 from django.core import urlresolvers
14 from django.contrib.admindocs import utils
15 from django.contrib.sites.models import Site
16 from django.utils.importlib import import_module
17 from django.utils.translation import ugettext as _
18 from django.utils.safestring import mark_safe
19
20 # Exclude methods starting with these strings from documentation
21 MODEL_METHODS_EXCLUDE = ('_', 'add_', 'delete', 'save', 'set_')
22
23 class GenericSite(object):
24 domain = 'example.com'
25 name = 'my site'
26
27 @staff_member_required
28 def doc_index(request):
29 if not utils.docutils_is_available:
30 return missing_docutils_page(request)
31 return render_to_response('admin_doc/index.html', {
32 'root_path': urlresolvers.reverse('admin:index'),
33 }, context_instance=RequestContext(request))
34
35 @staff_member_required
36 def bookmarklets(request):
37 admin_root = urlresolvers.reverse('admin:index')
38 return render_to_response('admin_doc/bookmarklets.html', {
39 'root_path': admin_root,
40 'admin_url': mark_safe("%s://%s%s" % (request.is_secure() and 'https' or 'http', request.get_host(), admin_root)),
41 }, context_instance=RequestContext(request))
42
43 @staff_member_required
44 def template_tag_index(request):
45 if not utils.docutils_is_available:
46 return missing_docutils_page(request)
47
48 load_all_installed_template_libraries()
49
50 tags = []
51 app_libs = template.libraries.items()
52 builtin_libs = [(None, lib) for lib in template.builtins]
53 for module_name, library in builtin_libs + app_libs:
54 for tag_name, tag_func in library.tags.items():
55 title, body, metadata = utils.parse_docstring(tag_func.__doc__)
56 if title:
57 title = utils.parse_rst(title, 'tag', _('tag:') + tag_name)
58 if body:
59 body = utils.parse_rst(body, 'tag', _('tag:') + tag_name)
60 for key in metadata:
61 metadata[key] = utils.parse_rst(metadata[key], 'tag', _('tag:') + tag_name)
62 if library in template.builtins:
63 tag_library = None
64 else:
65 tag_library = module_name.split('.')[-1]
66 tags.append({
67 'name': tag_name,
68 'title': title,
69 'body': body,
70 'meta': metadata,
71 'library': tag_library,
72 })
73 return render_to_response('admin_doc/template_tag_index.html', {
74 'root_path': urlresolvers.reverse('admin:index'),
75 'tags': tags
76 }, context_instance=RequestContext(request))
77
78 @staff_member_required
79 def template_filter_index(request):
80 if not utils.docutils_is_available:
81 return missing_docutils_page(request)
82
83 load_all_installed_template_libraries()
84
85 filters = []
86 app_libs = template.libraries.items()
87 builtin_libs = [(None, lib) for lib in template.builtins]
88 for module_name, library in builtin_libs + app_libs:
89 for filter_name, filter_func in library.filters.items():
90 title, body, metadata = utils.parse_docstring(filter_func.__doc__)
91 if title:
92 title = utils.parse_rst(title, 'filter', _('filter:') + filter_name)
93 if body:
94 body = utils.parse_rst(body, 'filter', _('filter:') + filter_name)
95 for key in metadata:
96 metadata[key] = utils.parse_rst(metadata[key], 'filter', _('filter:') + filter_name)
97 if library in template.builtins:
98 tag_library = None
99 else:
100 tag_library = module_name.split('.')[-1]
101 filters.append({
102 'name': filter_name,
103 'title': title,
104 'body': body,
105 'meta': metadata,
106 'library': tag_library,
107 })
108 return render_to_response('admin_doc/template_filter_index.html', {
109 'root_path': urlresolvers.reverse('admin:index'),
110 'filters': filters
111 }, context_instance=RequestContext(request))
112
113 @staff_member_required
114 def view_index(request):
115 if not utils.docutils_is_available:
116 return missing_docutils_page(request)
117
118 if settings.ADMIN_FOR:
119 settings_modules = [import_module(m) for m in settings.ADMIN_FOR]
120 else:
121 settings_modules = [settings]
122
123 views = []
124 for settings_mod in settings_modules:
125 urlconf = import_module(settings_mod.ROOT_URLCONF)
126 view_functions = extract_views_from_urlpatterns(urlconf.urlpatterns)
127 if Site._meta.installed:
128 site_obj = Site.objects.get(pk=settings_mod.SITE_ID)
129 else:
130 site_obj = GenericSite()
131 for (func, regex) in view_functions:
132 views.append({
133 'full_name': '%s.%s' % (func.__module__, getattr(func, '__name__', func.__class__.__name__)),
134 'site_id': settings_mod.SITE_ID,
135 'site': site_obj,
136 'url': simplify_regex(regex),
137 })
138 return render_to_response('admin_doc/view_index.html', {
139 'root_path': urlresolvers.reverse('admin:index'),
140 'views': views
141 }, context_instance=RequestContext(request))
142
143 @staff_member_required
144 def view_detail(request, view):
145 if not utils.docutils_is_available:
146 return missing_docutils_page(request)
147
148 mod, func = urlresolvers.get_mod_func(view)
149 try:
150 view_func = getattr(import_module(mod), func)
151 except (ImportError, AttributeError):
152 raise Http404
153 title, body, metadata = utils.parse_docstring(view_func.__doc__)
154 if title:
155 title = utils.parse_rst(title, 'view', _('view:') + view)
156 if body:
157 body = utils.parse_rst(body, 'view', _('view:') + view)
158 for key in metadata:
159 metadata[key] = utils.parse_rst(metadata[key], 'model', _('view:') + view)
160 return render_to_response('admin_doc/view_detail.html', {
161 'root_path': urlresolvers.reverse('admin:index'),
162 'name': view,
163 'summary': title,
164 'body': body,
165 'meta': metadata,
166 }, context_instance=RequestContext(request))
167
168 @staff_member_required
169 def model_index(request):
170 if not utils.docutils_is_available:
171 return missing_docutils_page(request)
172 m_list = [m._meta for m in models.get_models()]
173 return render_to_response('admin_doc/model_index.html', {
174 'root_path': urlresolvers.reverse('admin:index'),
175 'models': m_list
176 }, context_instance=RequestContext(request))
177
178 @staff_member_required
179 def model_detail(request, app_label, model_name):
180 if not utils.docutils_is_available:
181 return missing_docutils_page(request)
182
183 # Get the model class.
184 try:
185 app_mod = models.get_app(app_label)
186 except ImproperlyConfigured:
187 raise Http404(_("App %r not found") % app_label)
188 model = None
189 for m in models.get_models(app_mod):
190 if m._meta.object_name.lower() == model_name:
191 model = m
192 break
193 if model is None:
194 raise Http404(_("Model %(model_name)r not found in app %(app_label)r") % {'model_name': model_name, 'app_label': app_label})
195
196 opts = model._meta
197
198 # Gather fields/field descriptions.
199 fields = []
200 for field in opts.fields:
201 # ForeignKey is a special case since the field will actually be a
202 # descriptor that returns the other object
203 if isinstance(field, models.ForeignKey):
204 data_type = field.rel.to.__name__
205 app_label = field.rel.to._meta.app_label
206 verbose = utils.parse_rst((_("the related `%(app_label)s.%(data_type)s` object") % {'app_label': app_label, 'data_type': data_type}), 'model', _('model:') + data_type)
207 else:
208 data_type = get_readable_field_data_type(field)
209 verbose = field.verbose_name
210 fields.append({
211 'name': field.name,
212 'data_type': data_type,
213 'verbose': verbose,
214 'help_text': field.help_text,
215 })
216
217 # Gather many-to-many fields.
218 for field in opts.many_to_many:
219 data_type = field.rel.to.__name__
220 app_label = field.rel.to._meta.app_label
221 verbose = _("related `%(app_label)s.%(object_name)s` objects") % {'app_label': app_label, 'object_name': data_type}
222 fields.append({
223 'name': "%s.all" % field.name,
224 "data_type": 'List',
225 'verbose': utils.parse_rst(_("all %s") % verbose , 'model', _('model:') + opts.module_name),
226 })
227 fields.append({
228 'name' : "%s.count" % field.name,
229 'data_type' : 'Integer',
230 'verbose' : utils.parse_rst(_("number of %s") % verbose , 'model', _('model:') + opts.module_name),
231 })
232
233 # Gather model methods.
234 for func_name, func in model.__dict__.items():
235 if (inspect.isfunction(func) and len(inspect.getargspec(func)[0]) == 1):
236 try:
237 for exclude in MODEL_METHODS_EXCLUDE:
238 if func_name.startswith(exclude):
239 raise StopIteration
240 except StopIteration:
241 continue
242 verbose = func.__doc__
243 if verbose:
244 verbose = utils.parse_rst(utils.trim_docstring(verbose), 'model', _('model:') + opts.module_name)
245 fields.append({
246 'name': func_name,
247 'data_type': get_return_data_type(func_name),
248 'verbose': verbose,
249 })
250
251 # Gather related objects
252 for rel in opts.get_all_related_objects() + opts.get_all_related_many_to_many_objects():
253 verbose = _("related `%(app_label)s.%(object_name)s` objects") % {'app_label': rel.opts.app_label, 'object_name': rel.opts.object_name}
254 accessor = rel.get_accessor_name()
255 fields.append({
256 'name' : "%s.all" % accessor,
257 'data_type' : 'List',
258 'verbose' : utils.parse_rst(_("all %s") % verbose , 'model', _('model:') + opts.module_name),
259 })
260 fields.append({
261 'name' : "%s.count" % accessor,
262 'data_type' : 'Integer',
263 'verbose' : utils.parse_rst(_("number of %s") % verbose , 'model', _('model:') + opts.module_name),
264 })
265 return render_to_response('admin_doc/model_detail.html', {
266 'root_path': urlresolvers.reverse('admin:index'),
267 'name': '%s.%s' % (opts.app_label, opts.object_name),
268 'summary': _("Fields on %s objects") % opts.object_name,
269 'description': model.__doc__,
270 'fields': fields,
271 }, context_instance=RequestContext(request))
272
273 @staff_member_required
274 def template_detail(request, template):
275 templates = []
276 for site_settings_module in settings.ADMIN_FOR:
277 settings_mod = import_module(site_settings_module)
278 if Site._meta.installed:
279 site_obj = Site.objects.get(pk=settings_mod.SITE_ID)
280 else:
281 site_obj = GenericSite()
282 for dir in settings_mod.TEMPLATE_DIRS:
283 template_file = os.path.join(dir, template)
284 templates.append({
285 'file': template_file,
286 'exists': os.path.exists(template_file),
287 'contents': lambda: os.path.exists(template_file) and open(template_file).read() or '',
288 'site_id': settings_mod.SITE_ID,
289 'site': site_obj,
290 'order': list(settings_mod.TEMPLATE_DIRS).index(dir),
291 })
292 return render_to_response('admin_doc/template_detail.html', {
293 'root_path': urlresolvers.reverse('admin:index'),
294 'name': template,
295 'templates': templates,
296 }, context_instance=RequestContext(request))
297
298 ####################
299 # Helper functions #
300 ####################
301
302 def missing_docutils_page(request):
303 """Display an error message for people without docutils"""
304 return render_to_response('admin_doc/missing_docutils.html')
305
306 def load_all_installed_template_libraries():
307 # Load/register all template tag libraries from installed apps.
308 for module_name in template.get_templatetags_modules():
309 mod = import_module(module_name)
310 try:
311 libraries = [
312 os.path.splitext(p)[0]
313 for p in os.listdir(os.path.dirname(mod.__file__))
314 if p.endswith('.py') and p[0].isalpha()
315 ]
316 except OSError:
317 libraries = []
318 for library_name in libraries:
319 try:
320 lib = template.get_library(library_name)
321 except template.InvalidTemplateLibrary, e:
322 pass
323
324 def get_return_data_type(func_name):
325 """Return a somewhat-helpful data type given a function name"""
326 if func_name.startswith('get_'):
327 if func_name.endswith('_list'):
328 return 'List'
329 elif func_name.endswith('_count'):
330 return 'Integer'
331 return ''
332
333 def get_readable_field_data_type(field):
334 """Returns the description for a given field type, if it exists,
335 Fields' descriptions can contain format strings, which will be interpolated
336 against the values of field.__dict__ before being output."""
337
338 return field.description % field.__dict__
339
340 def extract_views_from_urlpatterns(urlpatterns, base=''):
341 """
342 Return a list of views from a list of urlpatterns.
343
344 Each object in the returned list is a two-tuple: (view_func, regex)
345 """
346 views = []
347 for p in urlpatterns:
348 if hasattr(p, 'url_patterns'):
349 try:
350 patterns = p.url_patterns
351 except ImportError:
352 continue
353 views.extend(extract_views_from_urlpatterns(patterns, base + p.regex.pattern))
354 elif hasattr(p, 'callback'):
355 try:
356 views.append((p.callback, base + p.regex.pattern))
357 except ViewDoesNotExist:
358 continue
359 else:
360 raise TypeError(_("%s does not appear to be a urlpattern object") % p)
361 return views
362
363 named_group_matcher = re.compile(r'\(\?P(<\w+>).+?\)')
364 non_named_group_matcher = re.compile(r'\(.*?\)')
365
366 def simplify_regex(pattern):
367 """
368 Clean up urlpattern regexes into something somewhat readable by Mere Humans:
369 turns something like "^(?P<sport_slug>\w+)/athletes/(?P<athlete_slug>\w+)/$"
370 into "<sport_slug>/athletes/<athlete_slug>/"
371 """
372 # handle named groups first
373 pattern = named_group_matcher.sub(lambda m: m.group(1), pattern)
374
375 # handle non-named groups
376 pattern = non_named_group_matcher.sub("<var>", pattern)
377
378 # clean up any outstanding regex-y characters.
379 pattern = pattern.replace('^', '').replace('$', '').replace('?', '').replace('//', '/').replace('\\', '')
380 if not pattern.startswith('/'):
381 pattern = '/' + pattern
382 return pattern