summaryrefslogtreecommitdiffstats
path: root/webapp/django/contrib/databrowse/datastructures.py
diff options
context:
space:
mode:
Diffstat (limited to 'webapp/django/contrib/databrowse/datastructures.py')
-rw-r--r--webapp/django/contrib/databrowse/datastructures.py217
1 files changed, 217 insertions, 0 deletions
diff --git a/webapp/django/contrib/databrowse/datastructures.py b/webapp/django/contrib/databrowse/datastructures.py
new file mode 100644
index 0000000000..5fdbdbe134
--- /dev/null
+++ b/webapp/django/contrib/databrowse/datastructures.py
@@ -0,0 +1,217 @@
+"""
+These classes are light wrappers around Django's database API that provide
+convenience functionality and permalink functions for the databrowse app.
+"""
+
+from django.db import models
+from django.utils import dateformat
+from django.utils.text import capfirst
+from django.utils.translation import get_date_formats
+from django.utils.encoding import smart_unicode, smart_str, iri_to_uri
+from django.utils.safestring import mark_safe
+from django.db.models.query import QuerySet
+
+EMPTY_VALUE = '(None)'
+DISPLAY_SIZE = 100
+
+class EasyModel(object):
+ def __init__(self, site, model):
+ self.site = site
+ self.model = model
+ self.model_list = site.registry.keys()
+ self.verbose_name = model._meta.verbose_name
+ self.verbose_name_plural = model._meta.verbose_name_plural
+
+ def __repr__(self):
+ return '<EasyModel for %s>' % smart_str(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 mark_safe('%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 smart_str(u'<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 mark_safe('%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 mark_safe('%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 smart_str(u'<EasyChoice for %s.%s>' % (self.model.model._meta.object_name, self.field.name))
+
+ def url(self):
+ return mark_safe('%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)))
+
+class EasyInstance(object):
+ def __init__(self, easy_model, instance):
+ self.model, self.instance = easy_model, instance
+
+ def __repr__(self):
+ return smart_str(u'<EasyInstance for %s (%s)>' % (self.model.model._meta.object_name, self.instance._get_pk_val()))
+
+ def __unicode__(self):
+ val = smart_unicode(self.instance)
+ if len(val) > DISPLAY_SIZE:
+ return val[:DISPLAY_SIZE] + u'...'
+ return val
+
+ def __str__(self):
+ return self.__unicode__().encode('utf-8')
+
+ def pk(self):
+ return self.instance._get_pk_val()
+
+ def url(self):
+ return mark_safe('%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 smart_str(u'<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:
+ date_format, datetime_format, time_format = get_date_formats()
+ if isinstance(self.field, models.DateTimeField):
+ objs = capfirst(dateformat.format(self.raw_value, datetime_format))
+ elif isinstance(self.field, models.TimeField):
+ objs = capfirst(dateformat.time_format(self.raw_value, time_format))
+ else:
+ objs = capfirst(dateformat.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:
+ #plugin_urls.append(urls)
+ values = self.values()
+ 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():
+ url = mark_safe('%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_unicode(value), url))
+ else:
+ lst = [(value, None) for value in self.values()]
+ elif self.field.choices:
+ lst = []
+ for value in self.values():
+ url = mark_safe('%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 = self.values()[0]
+ lst = [(val, iri_to_uri(val))]
+ else:
+ lst = [(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