Kaydet (Commit) 05227116 authored tarafından Aymeric Augustin's avatar Aymeric Augustin

Removed django.contrib.databrowse.

RIP -- you served us well.
üst 02f3daad
...@@ -19,7 +19,6 @@ recursive-include django/contrib/auth/fixtures * ...@@ -19,7 +19,6 @@ recursive-include django/contrib/auth/fixtures *
recursive-include django/contrib/auth/templates * recursive-include django/contrib/auth/templates *
recursive-include django/contrib/auth/tests/templates * recursive-include django/contrib/auth/tests/templates *
recursive-include django/contrib/comments/templates * recursive-include django/contrib/comments/templates *
recursive-include django/contrib/databrowse/templates *
recursive-include django/contrib/formtools/templates * recursive-include django/contrib/formtools/templates *
recursive-include django/contrib/formtools/tests/templates * recursive-include django/contrib/formtools/tests/templates *
recursive-include django/contrib/flatpages/fixtures * recursive-include django/contrib/flatpages/fixtures *
......
import warnings
from django.contrib.databrowse.sites import DatabrowsePlugin, ModelDatabrowse, DatabrowseSite, site
warnings.warn("The Databrowse contrib app is deprecated", DeprecationWarning)
"""
These classes are light wrappers around Django's database API that provide
convenience functionality and permalink functions for the databrowse app.
"""
from __future__ import unicode_literals
from django.db import models
from django.utils import formats
from django.utils.text import capfirst
from django.utils.encoding import smart_text, force_str, iri_to_uri
from django.db.models.query import QuerySet
from django.utils.encoding import python_2_unicode_compatible
EMPTY_VALUE = '(None)'
DISPLAY_SIZE = 100
class EasyModel(object):
def __init__(self, site, model):
self.site = site
self.model = model
self.model_list = list(site.registry.keys())
self.verbose_name = model._meta.verbose_name
self.verbose_name_plural = model._meta.verbose_name_plural
def __repr__(self):
return force_str('<EasyModel for %s>' % self.model._meta.object_name)
def model_databrowse(self):
"Returns the ModelDatabrowse class for this model."
return self.site.registry[self.model]
def url(self):
return '%s%s/%s/' % (self.site.root_url, self.model._meta.app_label, self.model._meta.module_name)
def objects(self, **kwargs):
return self.get_query_set().filter(**kwargs)
def get_query_set(self):
easy_qs = self.model._default_manager.get_query_set()._clone(klass=EasyQuerySet)
easy_qs._easymodel = self
return easy_qs
def object_by_pk(self, pk):
return EasyInstance(self, self.model._default_manager.get(pk=pk))
def sample_objects(self):
for obj in self.model._default_manager.all()[:3]:
yield EasyInstance(self, obj)
def field(self, name):
try:
f = self.model._meta.get_field(name)
except models.FieldDoesNotExist:
return None
return EasyField(self, f)
def fields(self):
return [EasyField(self, f) for f in (self.model._meta.fields + self.model._meta.many_to_many)]
class EasyField(object):
def __init__(self, easy_model, field):
self.model, self.field = easy_model, field
def __repr__(self):
return force_str('<EasyField for %s.%s>' % (self.model.model._meta.object_name, self.field.name))
def choices(self):
for value, label in self.field.choices:
yield EasyChoice(self.model, self, value, label)
def url(self):
if self.field.choices:
return '%s%s/%s/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name, self.field.name)
elif self.field.rel:
return '%s%s/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name)
class EasyChoice(object):
def __init__(self, easy_model, field, value, label):
self.model, self.field = easy_model, field
self.value, self.label = value, label
def __repr__(self):
return force_str('<EasyChoice for %s.%s>' % (self.model.model._meta.object_name, self.field.name))
def url(self):
return '%s%s/%s/%s/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name, self.field.field.name, iri_to_uri(self.value))
@python_2_unicode_compatible
class EasyInstance(object):
def __init__(self, easy_model, instance):
self.model, self.instance = easy_model, instance
def __repr__(self):
return force_str('<EasyInstance for %s (%s)>' % (self.model.model._meta.object_name, self.instance._get_pk_val()))
def __str__(self):
val = smart_text(self.instance)
if len(val) > DISPLAY_SIZE:
return val[:DISPLAY_SIZE] + '...'
return val
def pk(self):
return self.instance._get_pk_val()
def url(self):
return '%s%s/%s/objects/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name, iri_to_uri(self.pk()))
def fields(self):
"""
Generator that yields EasyInstanceFields for each field in this
EasyInstance's model.
"""
for f in self.model.model._meta.fields + self.model.model._meta.many_to_many:
yield EasyInstanceField(self.model, self, f)
def related_objects(self):
"""
Generator that yields dictionaries of all models that have this
EasyInstance's model as a ForeignKey or ManyToManyField, along with
lists of related objects.
"""
for rel_object in self.model.model._meta.get_all_related_objects() + self.model.model._meta.get_all_related_many_to_many_objects():
if rel_object.model not in self.model.model_list:
continue # Skip models that aren't in the model_list
em = EasyModel(self.model.site, rel_object.model)
yield {
'model': em,
'related_field': rel_object.field.verbose_name,
'object_list': [EasyInstance(em, i) for i in getattr(self.instance, rel_object.get_accessor_name()).all()],
}
class EasyInstanceField(object):
def __init__(self, easy_model, instance, field):
self.model, self.field, self.instance = easy_model, field, instance
self.raw_value = getattr(instance.instance, field.name)
def __repr__(self):
return force_str('<EasyInstanceField for %s.%s>' % (self.model.model._meta.object_name, self.field.name))
def values(self):
"""
Returns a list of values for this field for this instance. It's a list
so we can accomodate many-to-many fields.
"""
# This import is deliberately inside the function because it causes
# some settings to be imported, and we don't want to do that at the
# module level.
if self.field.rel:
if isinstance(self.field.rel, models.ManyToOneRel):
objs = getattr(self.instance.instance, self.field.name)
elif isinstance(self.field.rel, models.ManyToManyRel): # ManyToManyRel
return list(getattr(self.instance.instance, self.field.name).all())
elif self.field.choices:
objs = dict(self.field.choices).get(self.raw_value, EMPTY_VALUE)
elif isinstance(self.field, models.DateField) or isinstance(self.field, models.TimeField):
if self.raw_value:
if isinstance(self.field, models.DateTimeField):
objs = capfirst(formats.date_format(self.raw_value, 'DATETIME_FORMAT'))
elif isinstance(self.field, models.TimeField):
objs = capfirst(formats.time_format(self.raw_value, 'TIME_FORMAT'))
else:
objs = capfirst(formats.date_format(self.raw_value, 'DATE_FORMAT'))
else:
objs = EMPTY_VALUE
elif isinstance(self.field, models.BooleanField) or isinstance(self.field, models.NullBooleanField):
objs = {True: 'Yes', False: 'No', None: 'Unknown'}[self.raw_value]
else:
objs = self.raw_value
return [objs]
def urls(self):
"Returns a list of (value, URL) tuples."
# First, check the urls() method for each plugin.
plugin_urls = []
for plugin_name, plugin in self.model.model_databrowse().plugins.items():
urls = plugin.urls(plugin_name, self)
if urls is not None:
return zip(self.values(), urls)
if self.field.rel:
m = EasyModel(self.model.site, self.field.rel.to)
if self.field.rel.to in self.model.model_list:
lst = []
for value in self.values():
if value is None:
continue
url = '%s%s/%s/objects/%s/' % (self.model.site.root_url, m.model._meta.app_label, m.model._meta.module_name, iri_to_uri(value._get_pk_val()))
lst.append((smart_text(value), url))
else:
lst = [(value, None) for value in self.values()]
elif self.field.choices:
lst = []
for value in self.values():
url = '%s%s/%s/fields/%s/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name, self.field.name, iri_to_uri(self.raw_value))
lst.append((value, url))
elif isinstance(self.field, models.URLField):
val = list(self.values())[0]
lst = [(val, iri_to_uri(val))]
else:
lst = [(list(self.values())[0], None)]
return lst
class EasyQuerySet(QuerySet):
"""
When creating (or cloning to) an `EasyQuerySet`, make sure to set the
`_easymodel` variable to the related `EasyModel`.
"""
def iterator(self, *args, **kwargs):
for obj in super(EasyQuerySet, self).iterator(*args, **kwargs):
yield EasyInstance(self._easymodel, obj)
def _clone(self, *args, **kwargs):
c = super(EasyQuerySet, self)._clone(*args, **kwargs)
c._easymodel = self._easymodel
return c
# Empty models.py to allow for specifying databrowse as a test label.
from __future__ import unicode_literals
from django import http
from django.db import models
from django.contrib.databrowse.datastructures import EasyModel
from django.contrib.databrowse.sites import DatabrowsePlugin
from django.shortcuts import render_to_response
from django.utils.html import format_html, format_html_join
from django.utils.text import capfirst
from django.utils.encoding import force_text
from django.views.generic import dates
from django.utils import datetime_safe
class DateViewMixin(object):
allow_empty = False
allow_future = True
root_url = None
model = None
field = None
def get_context_data(self, **kwargs):
context = super(DateViewMixin, self).get_context_data(**kwargs)
context.update({
'root_url': self.root_url,
'model': self.model,
'field': self.field
})
return context
class DayView(DateViewMixin, dates.DayArchiveView):
template_name = 'databrowse/calendar_day.html'
class MonthView(DateViewMixin, dates.MonthArchiveView):
template_name = 'databrowse/calendar_month.html'
class YearView(DateViewMixin, dates.YearArchiveView):
template_name = 'databrowse/calendar_year.html'
class IndexView(DateViewMixin, dates.ArchiveIndexView):
template_name = 'databrowse/calendar_main.html'
class CalendarPlugin(DatabrowsePlugin):
def __init__(self, field_names=None):
self.field_names = field_names
def field_dict(self, model):
"""
Helper function that returns a dictionary of all DateFields or
DateTimeFields in the given model. If self.field_names is set, it takes
take that into account when building the dictionary.
"""
if self.field_names is None:
return dict([(f.name, f) for f in model._meta.fields if isinstance(f, models.DateField)])
else:
return dict([(f.name, f) for f in model._meta.fields if isinstance(f, models.DateField) and f.name in self.field_names])
def model_index_html(self, request, model, site):
fields = self.field_dict(model)
if not fields:
return ''
return format_html('<p class="filter"><strong>View calendar by:</strong> {0}</p>',
format_html_join(', ', '<a href="calendars/{0}/">{1}</a>',
((f.name, force_text(capfirst(f.verbose_name))) for f in fields.values())))
def urls(self, plugin_name, easy_instance_field):
if isinstance(easy_instance_field.field, models.DateField):
d = easy_instance_field.raw_value
return ['%s%s/%s/%s/%s/%s/' % (
easy_instance_field.model.url(),
plugin_name, easy_instance_field.field.name,
str(d.year),
datetime_safe.new_date(d).strftime('%b').lower(),
d.day)]
def model_view(self, request, model_databrowse, url):
self.model, self.site = model_databrowse.model, model_databrowse.site
self.fields = self.field_dict(self.model)
# If the model has no DateFields, there's no point in going further.
if not self.fields:
raise http.Http404('The requested model has no calendars.')
if url is None:
return self.homepage_view(request)
url_bits = url.split('/')
if url_bits[0] in self.fields:
return self.calendar_view(request, self.fields[url_bits[0]], *url_bits[1:])
raise http.Http404('The requested page does not exist.')
def homepage_view(self, request):
easy_model = EasyModel(self.site, self.model)
field_list = list(self.fields.values())
field_list.sort(key=lambda k:k.verbose_name)
return render_to_response('databrowse/calendar_homepage.html', {
'root_url': self.site.root_url,
'model': easy_model,
'field_list': field_list
})
def calendar_view(self, request, field, year=None, month=None, day=None):
easy_model = EasyModel(self.site, self.model)
root_url = self.site.root_url
if day is not None:
return DayView.as_view(
year=year, month=month, day=day,
date_field=field.name,
queryset=easy_model.get_query_set(),
root_url=root_url,
model=easy_model,
field=field
)(request)
elif month is not None:
return MonthView.as_view(
year=year, month=month,
date_field=field.name,
queryset=easy_model.get_query_set(),
root_url=root_url,
model=easy_model,
field=field
)(request)
elif year is not None:
return YearView.as_view(
year=year,
date_field=field.name,
queryset=easy_model.get_query_set(),
root_url=root_url,
model=easy_model,
field=field
)(request)
else:
return IndexView.as_view(
date_field=field.name,
queryset=easy_model.get_query_set(),
root_url=root_url,
model=easy_model,
field=field
)(request)
assert False, ('%s, %s, %s, %s' % (field, year, month, day))
from __future__ import unicode_literals
from django import http
from django.db import models
from django.contrib.databrowse.datastructures import EasyModel
from django.contrib.databrowse.sites import DatabrowsePlugin
from django.shortcuts import render_to_response
from django.utils.html import format_html, format_html_join
from django.utils.http import urlquote
from django.utils.text import capfirst
from django.utils.encoding import force_text
class FieldChoicePlugin(DatabrowsePlugin):
def __init__(self, field_filter=None):
# If field_filter is given, it should be a callable that takes a
# Django database Field instance and returns True if that field should
# be included. If field_filter is None, that all fields will be used.
self.field_filter = field_filter
def field_dict(self, model):
"""
Helper function that returns a dictionary of all fields in the given
model. If self.field_filter is set, it only includes the fields that
match the filter.
"""
if self.field_filter:
return dict([(f.name, f) for f in model._meta.fields if self.field_filter(f)])
else:
return dict([(f.name, f) for f in model._meta.fields if not f.rel and not f.primary_key and not f.unique and not isinstance(f, (models.AutoField, models.TextField))])
def model_index_html(self, request, model, site):
fields = self.field_dict(model)
if not fields:
return ''
return format_html('<p class="filter"><strong>View by:</strong> {0}</p>',
format_html_join(', ', '<a href="fields/{0}/">{1}</a>',
((f.name, force_text(capfirst(f.verbose_name))) for f in fields.values())))
def urls(self, plugin_name, easy_instance_field):
if easy_instance_field.field in self.field_dict(easy_instance_field.model.model).values():
return ['%s%s/%s/%s/' % (
easy_instance_field.model.url(),
plugin_name, easy_instance_field.field.name,
urlquote(easy_instance_field.raw_value, safe=''))]
def model_view(self, request, model_databrowse, url):
self.model, self.site = model_databrowse.model, model_databrowse.site
self.fields = self.field_dict(self.model)
# If the model has no fields with choices, there's no point in going
# further.
if not self.fields:
raise http.Http404('The requested model has no fields.')
if url is None:
return self.homepage_view(request)
url_bits = url.split('/', 1)
if url_bits[0] in self.fields:
return self.field_view(request, self.fields[url_bits[0]], *url_bits[1:])
raise http.Http404('The requested page does not exist.')
def homepage_view(self, request):
easy_model = EasyModel(self.site, self.model)
field_list = list(self.fields.values())
field_list.sort(key=lambda k: k.verbose_name)
return render_to_response('databrowse/fieldchoice_homepage.html', {'root_url': self.site.root_url, 'model': easy_model, 'field_list': field_list})
def field_view(self, request, field, value=None):
easy_model = EasyModel(self.site, self.model)
easy_field = easy_model.field(field.name)
if value is not None:
obj_list = easy_model.objects(**{field.name: value})
return render_to_response('databrowse/fieldchoice_detail.html', {'root_url': self.site.root_url, 'model': easy_model, 'field': easy_field, 'value': value, 'object_list': obj_list})
obj_list = [v[field.name] for v in self.model._default_manager.distinct().order_by(field.name).values(field.name)]
return render_to_response('databrowse/fieldchoice_list.html', {'root_url': self.site.root_url, 'model': easy_model, 'field': easy_field, 'object_list': obj_list})
try:
from urllib.parse import urljoin
except ImportError: # Python 2
from urlparse import urljoin
from django import http
from django.contrib.databrowse.datastructures import EasyModel
from django.contrib.databrowse.sites import DatabrowsePlugin
from django.shortcuts import render_to_response
class ObjectDetailPlugin(DatabrowsePlugin):
def model_view(self, request, model_databrowse, url):
# If the object ID wasn't provided, redirect to the model page, which is one level up.
if url is None:
return http.HttpResponseRedirect(urljoin(request.path, '../'))
easy_model = EasyModel(model_databrowse.site, model_databrowse.model)
obj = easy_model.object_by_pk(url)
return render_to_response('databrowse/object_detail.html', {'object': obj, 'root_url': model_databrowse.site.root_url})
from __future__ import unicode_literals
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('\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_list, **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 = options.pop('databrowse_class', DefaultModelDatabrowse)
for model in model_list:
if model in self.registry:
raise AlreadyRegistered('The model %s is already registered' % model.__name__)
self.registry[model] = databrowse_class
def unregister(self, *model_list):
"""
Unregisters the given model(s).
If a model isn't already registered, this will raise NotRegistered.
"""
for model in model_list:
if model not in self.registry:
raise NotRegistered('The model %s is not registered' % model.__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()}
<!DOCTYPE html>
<html lang="{{ LANGUAGE_CODE|default:"en-us" }}" {% if LANGUAGE_BIDI %}dir="rtl"{% endif %}>
<head>
<title>{% block title %}{% endblock %}</title>
{% block style %}
<style type="text/css">
* { margin:0; padding:0; }
body { background:#eee; color:#333; font:76%/1.6 "Lucida Grande","Bitstream Vera Sans",Verdana,sans-serif; }
a { color: #5b80b2; text-decoration:none; }
a:hover { text-decoration:underline; }
a img { border:none; }
h1 { font-size:1.8em; color:#666; margin:0.4em 0 0.2em 0; }
h2 { font-size:1.5em; color:#666; margin:1em 0 0.2em 0; }
p { margin:0.5em 0 1em 0; }
.odd { background-color:#EDF3FE; }
.quiet { color:#666; }
/* FILTERS */
.filter { color:#999; font-size:0.9em; float:left; margin-bottom:10px; margin-right:20px; }
.filter strong { color:#666; }
/* OBJECT LISTS */
.objectlist { clear:both; margin:0 -20px; color:#666; }
.objectlist li a { display:block; padding:1em 20px; }
.objectlist li a:hover { background:#5b80b2; color:#3B5572; color:#fff; text-decoration:none; }
.related h2 { font-size: 1em; margin-bottom: 0.6em; }
.related .objectlist li a { padding: 0.6em 20px; }
.related .objectlist li.odd { background:#eee; }
/* OBJECT DETAIL */
.objectinfo { border-collapse:collapse; color:#666; margin:0 -20px; }
.objectinfo td, .objectinfo th { padding:1em 20px; vertical-align:top; }
.objectinfo td { width:100%; }
.objectinfo th { text-align:left; white-space:nowrap; }
/* MODEL GROUPS */
.modelgroup { color:#999; font-size:0.9em; margin:0 -20px; }
.modelgroup h2 { font-size:1.2em; margin:0; }
.modelgroup h2 a { display: block; padding: 0.83em 20px; }
.modelgroup h2 a:hover { text-decoration: none; color: #fff; }
.modelgroup p { float:left; margin:-2.65em 0 0 14em; position:relative; }
.modelgroup p a { white-space:nowrap; }
.modelgroup a.more { color:#999; }
.modelgroup:hover { background:#5b80b2; color:#becfe5; }
.modelgroup:hover p a { color:#becfe5; }
.modelgroup:hover a { color:#fff; }
.modelgroup:hover a.more { color:#fff; }
/* BREADCRUMBS */
#breadcrumbs { padding:10px 0; color:#999; font-size:0.9em; }
/* HEADER */
#header a { display:block; background:#eee; color:#676868; padding:10px 20px; font-weight:bold; font-size:1em; text-decoration:none; border-bottom:1px solid #ddd; }
#header a:hover { text-decoration:underline; }
/* CONTENT */
#content { background:#fff; border-bottom:1px solid #ddd; padding:0 20px; }
</style>
{% endblock %}
{% block extrahead %}{% endblock %}
</head>
<body id="{% block bodyid %}page{% endblock %}">
<div id="header"><a href="{{ root_url }}">{% block databrowse_title %}Databrowse{% endblock %}</a></div>
<div id="content">
{% block content %}{% endblock %}
</div>
</body>
</html>
{% extends "databrowse/base_site.html" %}
{% block title %}{{ model.verbose_name_plural|capfirst }} with {{ field.verbose_name }} {{ day|date:"F j, Y" }}{% endblock %}
{% block content %}
<div id="breadcrumbs"><a href="{{ root_url }}">Home</a> / <a href="{{ model.url }}">{{ model.verbose_name_plural|capfirst }}</a> / <a href="../../../../">Calendars</a> / <a href="../../../">By {{ field.verbose_name }}</a> / <a href="../../">{{ day|date:"Y" }}</a> / <a href="../">{{ day|date:"F" }}</a> / {{ day|date:"d" }}</div>
<h1>{{ object_list.count }} {% if object_list.count|pluralize %}{{ model.verbose_name_plural }}{% else %}{{ model.verbose_name }}{% endif %} with {{ field.verbose_name }} on {{ day|date:"F j, Y" }}</h1>
<ul class="objectlist">
{% for object in object_list %}
<li class="{% cycle 'odd' 'even' %}"><a href="{{ object.url }}">{{ object }}</a></li>
{% endfor %}
</ul>
{% endblock %}
{% extends "databrowse/base_site.html" %}
{% block title %}Calendars{% endblock %}
{% block content %}
<div id="breadcrumbs"><a href="{{ root_url }}">Home</a> / <a href="{{ model.url }}">{{ model.verbose_name_plural|capfirst }}</a> / Calendars</div>
<h1>Calendars</h1>
<ul class="objectlist">
{% for field in field_list %}
<li class="{% cycle 'odd' 'even' %}"><a href="{{ field.name }}/">{{ model.verbose_name_plural|capfirst }} by {{ field.verbose_name }}</a></li>
{% endfor %}
</ul>
{% endblock %}
{% extends "databrowse/base_site.html" %}
{% block title %}{{ field.verbose_name|capfirst }} calendar{% endblock %}
{% block content %}
<div id="breadcrumbs"><a href="{{ root_url }}">Home</a> / <a href="{{ model.url }}">{{ model.verbose_name_plural|capfirst }}</a> / <a href="../">Calendars</a> / By {{ field.verbose_name }}</div>
<h1>{{ model.verbose_name_plural|capfirst }} by {{ field.verbose_name }}</h1>
<ul class="objectlist">
{% for year in date_list %}
<li class="{% cycle 'odd' 'even' %}"><a href="{{ year|date:"Y" }}/">{{ year|date:"Y" }}</a></li>
{% endfor %}
</ul>
{% endblock %}
{% extends "databrowse/base_site.html" %}
{% block title %}{{ model.verbose_name_plural|capfirst }} with {{ field.verbose_name }} in {{ month|date:"F Y" }}{% endblock %}
{% block content %}
<div id="breadcrumbs"><a href="{{ root_url }}">Home</a> / <a href="{{ model.url }}">{{ model.verbose_name_plural|capfirst }}</a> / <a href="../../../">Calendars</a> / <a href="../../">By {{ field.verbose_name }}</a> / <a href="../">{{ month|date:"Y" }}</a> / {{ month|date:"F" }}</div>
<h1>{{ object_list.count }} {% if object_list.count|pluralize %}{{ model.verbose_name_plural }}{% else %}{{ model.verbose_name }}{% endif %} with {{ field.verbose_name }} on {{ month|date:"F Y" }}</h1>
<ul class="objectlist">
{% for object in object_list %}
<li class="{% cycle 'odd' 'even' %}"><a href="{{ object.url }}">{{ object }}</a></li>
{% endfor %}
</ul>
{% endblock %}
{% extends "databrowse/base_site.html" %}
{% block title %}{{ model.verbose_name_plural|capfirst }} with {{ field.verbose_name }} in {{ year }}{% endblock %}
{% block content %}
<div id="breadcrumbs"><a href="{{ root_url }}">Home</a> / <a href="{{ model.url }}">{{ model.verbose_name_plural|capfirst }}</a> / <a href="../../">Calendars</a> / <a href="../">By {{ field.verbose_name }}</a> / {{ year }}</div>
<h1>{{ model.verbose_name_plural|capfirst }} with {{ field.verbose_name }} in {{ year }}</h1>
<ul class="objectlist">
{% for month in date_list %}
<li class="{% cycle 'odd' 'even' %}"><a href="{{ month|date:"M"|lower }}/">{{ month|date:"F" }}</a></li>
{% endfor %}
</ul>
{% endblock %}
{% extends "databrowse/base_site.html" %}
{% block title %}{{ model.verbose_name_plural|capfirst }} by {{ field.field.verbose_name }}: {{ value }}{% endblock %}
{% block content %}
<div id="breadcrumbs"><a href="{{ root_url }}">Home</a> / <a href="{{ model.url }}">{{ model.verbose_name_plural|capfirst }}</a> / <a href="{{ field.url }}">By {{ field.field.verbose_name }}</a> / {{ value }}</div>
<h1>{{ model.verbose_name_plural|capfirst }} by {{ field.field.verbose_name }}: {{ value }}</h1>
<ul class="objectlist">
{% for object in object_list %}
<li class="{% cycle 'odd' 'even' %}"><a href="{{ object.url }}">{{ object }}</a></li>
{% endfor %}
</ul>
{% endblock %}
{% extends "databrowse/base_site.html" %}
{% block title %}{{ model.verbose_name_plural|capfirst }} by {{ field.field.verbose_name }}{% endblock %}
{% block content %}
<div id="breadcrumbs"><a href="{{ root_url }}">Home</a> / <a href="{{ model.url }}">{{ model.verbose_name_plural|capfirst }}</a> / By {{ field.field.verbose_name }}</div>
<h1>{{ model.verbose_name_plural|capfirst }} by {{ field.field.verbose_name }}</h1>
<ul class="objectlist">
{% for choice in field.choices %}
<li class="{% cycle 'odd' 'even' %}"><a href="{{ choice.url }}">{{ choice.label }}</a></li>
{% endfor %}
</ul>
{% endblock %}
{% extends "databrowse/base_site.html" %}
{% block title %}{{ model.verbose_name_plural|capfirst }} with {{ field.field.verbose_name }} {{ value }}{% endblock %}
{% block content %}
<div id="breadcrumbs"><a href="{{ root_url }}">Home</a> / <a href="{{ model.url }}">{{ model.verbose_name_plural|capfirst }}</a> / <a href="../../">Fields</a> / <a href="../">By {{ field.field.verbose_name }}</a> / {{ value }}</div>
<h1>{{ object_list.count }} {% if object_list.count|pluralize %}{{ model.verbose_name_plural }}{% else %}{{ model.verbose_name }}{% endif %} with {{ field.field.verbose_name }} {{ value }}</h1>
<ul class="objectlist">
{% for object in object_list %}
<li class="{% cycle 'odd' 'even' %}"><a href="{{ object.url }}">{{ object }}</a></li>
{% endfor %}
</ul>
{% endblock %}
{% extends "databrowse/base_site.html" %}
{% block title %}Browsable fields in {{ model.verbose_name_plural }}{% endblock %}
{% block content %}
<div id="breadcrumbs"><a href="{{ root_url }}">Home</a> / <a href="{{ model.url }}">{{ model.verbose_name_plural|capfirst }}</a> / Fields</div>
<h1>Browsable fields in {{ model.verbose_name_plural }}</h1>
<ul class="objectlist">
{% for field in field_list %}
<li class="{% cycle 'odd' 'even' %}"><a href="{{ field.name }}/">{{ model.verbose_name_plural|capfirst }} by {{ field.verbose_name }}</a></li>
{% endfor %}
</ul>
{% endblock %}
{% extends "databrowse/base_site.html" %}
{% block title %}{{ model.verbose_name_plural|capfirst }} by {{ field.field.verbose_name }}{% endblock %}
{% block content %}
<div id="breadcrumbs"><a href="{{ root_url }}">Home</a> / <a href="{{ model.url }}">{{ model.verbose_name_plural|capfirst }}</a> / <a href="../">Fields</a> / By {{ field.field.verbose_name }}</div>
<h1>{{ model.verbose_name_plural|capfirst }} by {{ field.field.verbose_name }}</h1>
<ul class="objectlist">
{% for object in object_list %}
<li class="{% cycle 'odd' 'even' %}"><a href="{{ object|iriencode }}/">{{ object }}</a></li>
{% endfor %}
</ul>
{% endblock %}
{% extends "databrowse/base_site.html" %}
{% block title %}Databrowse{% endblock %}
{% block bodyid %}homepage{% endblock %}
{% block content %}
{% for model in model_list %}
<div class="modelgroup {% cycle 'even' 'odd' %}">
<h2><a href="{{ model.url }}">{{ model.verbose_name_plural|capfirst }}</a></h2>
<p>
{% for object in model.sample_objects %}
<a href="{{ object.url }}">{{ object }}</a>,
{% endfor %}
<a class="more" href="{{ model.url }}">More &rarr;</a>
</p>
</div>
{% endfor %}
{% endblock %}
{% extends "databrowse/base_site.html" %}
{% block title %}{{ model.verbose_name_plural|capfirst }}{% endblock %}
{% block content %}
<div id="breadcrumbs"><a href="{{ root_url }}">Home</a> / {{ model.verbose_name_plural|capfirst }}</div>
<h1>{{ model.objects.count }} {% if model.objects.count|pluralize %}{{ model.verbose_name_plural }}{% else %}{{ model.verbose_name }}{% endif %}</h1>
{{ plugin_html }}
<ul class="objectlist">
{% for object in model.objects %}
<li class="{% cycle 'odd' 'even' %}"><a href="{{ object.url }}">{{ object }}</a></li>
{% endfor %}
</ul>
{% endblock %}
{% extends "databrowse/base_site.html" %}
{% block title %}{{ object.model.verbose_name|capfirst }}: {{ object }}{% endblock %}
{% block content %}
<div id="breadcrumbs"><a href="{{ root_url }}">Home</a> / <a href="{{ object.model.url }}">{{ object.model.verbose_name_plural|capfirst }}</a> / {{ object }}</div>
<h1>{{ object.model.verbose_name|capfirst }}: {{ object }}</h1>
<table class="objectinfo">
{% for field in object.fields %}
<tr class="{% cycle 'odd' 'even' %}">
<th>{{ field.field.verbose_name|capfirst }}</th>
<td>
{% if field.urls %}
{% for value, url in field.urls %}
{% if url %}<a href="{{ url }}">{% endif %}{{ value }}{% if url %}</a>{% endif %}{% if not forloop.last %}, {% endif %}
{% endfor %}
{% else %}None{% endif %}
</td>
</tr>
{% endfor %}
</table>
{% for related_object in object.related_objects %}
<div class="related">
<h2>Appears in "{{ related_object.related_field }}" in the following {{ related_object.model.verbose_name_plural }}:</h2>
{% if related_object.object_list %}
<ul class="objectlist">
{% for object in related_object.object_list %}
<li class="{% cycle 'odd' 'even' %}"><a href="{{ object.url }}">{{ object }}</a></li>
{% endfor %}
</ul>
{% else %}
<p class="quiet">(None)</p>
{% endif %}
</div>
{% endfor %}
{% endblock %}
from django.contrib import databrowse
from django.db import models
from django.test import TestCase
from django.utils.encoding import python_2_unicode_compatible
@python_2_unicode_compatible
class SomeModel(models.Model):
some_field = models.CharField(max_length=50)
def __str__(self):
return self.some_field
@python_2_unicode_compatible
class SomeOtherModel(models.Model):
some_other_field = models.CharField(max_length=50)
def __str__(self):
return self.some_other_field
@python_2_unicode_compatible
class YetAnotherModel(models.Model):
yet_another_field = models.CharField(max_length=50)
def __str__(self):
return self.yet_another_field
class DatabrowseTests(TestCase):
def test_databrowse_register_unregister(self):
databrowse.site.register(SomeModel)
self.assertTrue(SomeModel in databrowse.site.registry)
databrowse.site.register(SomeOtherModel, YetAnotherModel)
self.assertTrue(SomeOtherModel in databrowse.site.registry)
self.assertTrue(YetAnotherModel in databrowse.site.registry)
self.assertRaisesMessage(
databrowse.sites.AlreadyRegistered,
'The model SomeModel is already registered',
databrowse.site.register, SomeModel, SomeOtherModel
)
databrowse.site.unregister(SomeOtherModel)
self.assertFalse(SomeOtherModel in databrowse.site.registry)
databrowse.site.unregister(SomeModel, YetAnotherModel)
self.assertFalse(SomeModel in databrowse.site.registry)
self.assertFalse(YetAnotherModel in databrowse.site.registry)
self.assertRaisesMessage(
databrowse.sites.NotRegistered,
'The model SomeModel is not registered',
databrowse.site.unregister, SomeModel, SomeOtherModel
)
self.assertRaisesMessage(
databrowse.sites.AlreadyRegistered,
'The model SomeModel is already registered',
databrowse.site.register, SomeModel, SomeModel
)
from django.conf.urls import patterns
from django.contrib.databrowse import views
# Note: The views in this URLconf all require a 'models' argument,
# which is a list of model classes (*not* instances).
urlpatterns = patterns('',
#(r'^$', views.homepage),
#(r'^([^/]+)/([^/]+)/$', views.model_detail),
(r'^([^/]+)/([^/]+)/fields/(\w+)/$', views.choice_list),
(r'^([^/]+)/([^/]+)/fields/(\w+)/(.*)/$', views.choice_detail),
#(r'^([^/]+)/([^/]+)/calendars/(\w+)/$', views.calendar_main),
#(r'^([^/]+)/([^/]+)/calendars/(\w+)/(\d{4})/$', views.calendar_year),
#(r'^([^/]+)/([^/]+)/calendars/(\w+)/(\d{4})/(\w{3})/$', views.calendar_month),
#(r'^([^/]+)/([^/]+)/calendars/(\w+)/(\d{4})/(\w{3})/(\d{1,2})/$', views.calendar_day),
#(r'^([^/]+)/([^/]+)/objects/(.*)/$', views.object_detail),
)
from django.http import Http404
from django.shortcuts import render_to_response
###########
# CHOICES #
###########
def choice_list(request, app_label, module_name, field_name, models):
m, f = lookup_field(app_label, module_name, field_name, models)
return render_to_response('databrowse/choice_list.html', {'model': m, 'field': f})
def choice_detail(request, app_label, module_name, field_name, field_val, models):
m, f = lookup_field(app_label, module_name, field_name, models)
try:
label = dict(f.field.choices)[field_val]
except KeyError:
raise Http404('Invalid choice value given')
obj_list = m.objects(**{f.field.name: field_val})
return render_to_response('databrowse/choice_detail.html', {'model': m, 'field': f, 'value': label, 'object_list': obj_list})
...@@ -267,7 +267,6 @@ Learn about some other core functionalities of the Django framework: ...@@ -267,7 +267,6 @@ Learn about some other core functionalities of the Django framework:
* :doc:`Conditional content processing <topics/conditional-view-processing>` * :doc:`Conditional content processing <topics/conditional-view-processing>`
* :doc:`Content types and generic relations <ref/contrib/contenttypes>` * :doc:`Content types and generic relations <ref/contrib/contenttypes>`
* :doc:`Databrowse <ref/contrib/databrowse>`
* :doc:`Flatpages <ref/contrib/flatpages>` * :doc:`Flatpages <ref/contrib/flatpages>`
* :doc:`Redirects <ref/contrib/redirects>` * :doc:`Redirects <ref/contrib/redirects>`
* :doc:`Signals <topics/signals>` * :doc:`Signals <topics/signals>`
......
==========
Databrowse
==========
.. module:: django.contrib.databrowse
:synopsis: Databrowse is a Django application that lets you browse your data.
.. deprecated:: 1.4
This module has been deprecated.
Databrowse is a Django application that lets you browse your data.
As the Django admin dynamically creates an admin interface by introspecting
your models, Databrowse dynamically creates a rich, browsable Web site by
introspecting your models.
How to use Databrowse
=====================
1. Point Django at the default Databrowse templates. There are two ways to
do this:
* Add ``'django.contrib.databrowse'`` to your :setting:`INSTALLED_APPS`
setting. This will work if your :setting:`TEMPLATE_LOADERS` setting
includes the ``app_directories`` template loader (which is the case by
default). See the :ref:`template loader docs <template-loaders>` for
more.
* Otherwise, determine the full filesystem path to the
:file:`django/contrib/databrowse/templates` directory, and add that
directory to your :setting:`TEMPLATE_DIRS` setting.
2. Register a number of models with the Databrowse site::
from django.contrib import databrowse
from myapp.models import SomeModel, SomeOtherModel, YetAnotherModel
databrowse.site.register(SomeModel)
databrowse.site.register(SomeOtherModel, YetAnotherModel)
Note that you should register the model *classes*, not instances.
.. versionchanged:: 1.4
Since Django 1.4, it is possible to register several models in the same
call to :func:`~databrowse.site.register`.
It doesn't matter where you put this, as long as it gets executed at some
point. A good place for it is in your :doc:`URLconf file
</topics/http/urls>` (``urls.py``).
3. Change your URLconf to import the :mod:`~django.contrib.databrowse` module::
from django.contrib import databrowse
...and add the following line to your URLconf::
(r'^databrowse/(.*)', databrowse.site.root),
The prefix doesn't matter -- you can use ``databrowse/`` or ``db/`` or
whatever you'd like.
4. Run the Django server and visit ``/databrowse/`` in your browser.
Requiring user login
====================
You can restrict access to logged-in users with only a few extra lines of
code. Simply add the following import to your URLconf::
from django.contrib.auth.decorators import login_required
Then modify the :doc:`URLconf </topics/http/urls>` so that the
:func:`databrowse.site.root` view is decorated with
:func:`django.contrib.auth.decorators.login_required`::
(r'^databrowse/(.*)', login_required(databrowse.site.root)),
If you haven't already added support for user logins to your :doc:`URLconf
</topics/http/urls>`, as described in the :doc:`user authentication docs
</ref/contrib/auth>`, then you will need to do so now with the following
mapping::
(r'^accounts/login/$', 'django.contrib.auth.views.login'),
The final step is to create the login form required by
:func:`django.contrib.auth.views.login`. The
:doc:`user authentication docs </ref/contrib/auth>` provide full details and a
sample template that can be used for this purpose.
...@@ -27,7 +27,6 @@ those packages have. ...@@ -27,7 +27,6 @@ those packages have.
comments/index comments/index
contenttypes contenttypes
csrf csrf
databrowse
flatpages flatpages
formtools/index formtools/index
gis/index gis/index
......
...@@ -10,10 +10,6 @@ from django import contrib ...@@ -10,10 +10,6 @@ from django import contrib
from django.utils._os import upath from django.utils._os import upath
from django.utils import six from django.utils import six
# databrowse is deprecated, but we still want to run its tests
warnings.filterwarnings('ignore', "The Databrowse contrib app is deprecated",
DeprecationWarning, 'django.contrib.databrowse')
CONTRIB_DIR_NAME = 'django.contrib' CONTRIB_DIR_NAME = 'django.contrib'
MODEL_TESTS_DIR_NAME = 'modeltests' MODEL_TESTS_DIR_NAME = 'modeltests'
REGRESSION_TESTS_DIR_NAME = 'regressiontests' REGRESSION_TESTS_DIR_NAME = 'regressiontests'
...@@ -40,7 +36,6 @@ ALWAYS_INSTALLED_APPS = [ ...@@ -40,7 +36,6 @@ ALWAYS_INSTALLED_APPS = [
'django.contrib.comments', 'django.contrib.comments',
'django.contrib.admin', 'django.contrib.admin',
'django.contrib.admindocs', 'django.contrib.admindocs',
'django.contrib.databrowse',
'django.contrib.staticfiles', 'django.contrib.staticfiles',
'django.contrib.humanize', 'django.contrib.humanize',
'regressiontests.staticfiles_tests', 'regressiontests.staticfiles_tests',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment