2007-04-17 05:56:10 +08:00
|
|
|
"""
|
|
|
|
These classes are light wrappers around Django's database API that provide
|
|
|
|
convenience functionality and permalink functions for the databrowse app.
|
|
|
|
"""
|
2012-06-08 00:08:47 +08:00
|
|
|
from __future__ import unicode_literals
|
2007-04-17 05:56:10 +08:00
|
|
|
|
|
|
|
from django.db import models
|
2009-12-23 01:58:49 +08:00
|
|
|
from django.utils import formats
|
2007-04-17 05:56:10 +08:00
|
|
|
from django.utils.text import capfirst
|
2012-08-30 04:40:51 +08:00
|
|
|
from django.utils.encoding import smart_text, force_str, iri_to_uri
|
2007-08-20 01:01:54 +08:00
|
|
|
from django.db.models.query import QuerySet
|
2012-08-12 18:32:08 +08:00
|
|
|
from django.utils.encoding import python_2_unicode_compatible
|
2007-04-17 05:56:10 +08:00
|
|
|
|
2007-04-17 15:08:42 +08:00
|
|
|
EMPTY_VALUE = '(None)'
|
2007-12-19 11:58:53 +08:00
|
|
|
DISPLAY_SIZE = 100
|
2007-04-17 15:08:42 +08:00
|
|
|
|
2007-04-17 05:56:10 +08:00
|
|
|
class EasyModel(object):
|
|
|
|
def __init__(self, site, model):
|
|
|
|
self.site = site
|
|
|
|
self.model = model
|
2012-07-21 03:14:27 +08:00
|
|
|
self.model_list = list(site.registry.keys())
|
2007-04-17 05:56:10 +08:00
|
|
|
self.verbose_name = model._meta.verbose_name
|
|
|
|
self.verbose_name_plural = model._meta.verbose_name_plural
|
|
|
|
|
|
|
|
def __repr__(self):
|
2012-08-30 04:40:51 +08:00
|
|
|
return force_str('<EasyModel for %s>' % self.model._meta.object_name)
|
2007-04-17 05:56:10 +08:00
|
|
|
|
|
|
|
def model_databrowse(self):
|
|
|
|
"Returns the ModelDatabrowse class for this model."
|
|
|
|
return self.site.registry[self.model]
|
|
|
|
|
|
|
|
def url(self):
|
2012-07-03 07:33:44 +08:00
|
|
|
return '%s%s/%s/' % (self.site.root_url, self.model._meta.app_label, self.model._meta.module_name)
|
2007-04-17 05:56:10 +08:00
|
|
|
|
|
|
|
def objects(self, **kwargs):
|
2007-08-20 01:01:54 +08:00
|
|
|
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
|
2007-04-17 05:56:10 +08:00
|
|
|
|
|
|
|
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):
|
2012-08-30 04:40:51 +08:00
|
|
|
return force_str('<EasyField for %s.%s>' % (self.model.model._meta.object_name, self.field.name))
|
2007-04-17 05:56:10 +08:00
|
|
|
|
|
|
|
def choices(self):
|
|
|
|
for value, label in self.field.choices:
|
|
|
|
yield EasyChoice(self.model, self, value, label)
|
|
|
|
|
|
|
|
def url(self):
|
|
|
|
if self.field.choices:
|
2012-07-03 07:33:44 +08:00
|
|
|
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)
|
2007-04-17 05:56:10 +08:00
|
|
|
elif self.field.rel:
|
2012-07-03 07:33:44 +08:00
|
|
|
return '%s%s/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name)
|
2007-04-17 05:56:10 +08:00
|
|
|
|
|
|
|
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):
|
2012-08-30 04:40:51 +08:00
|
|
|
return force_str('<EasyChoice for %s.%s>' % (self.model.model._meta.object_name, self.field.name))
|
2007-04-17 05:56:10 +08:00
|
|
|
|
|
|
|
def url(self):
|
2012-07-03 07:33:44 +08:00
|
|
|
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))
|
2007-04-17 05:56:10 +08:00
|
|
|
|
2012-08-12 18:32:08 +08:00
|
|
|
@python_2_unicode_compatible
|
2007-04-17 05:56:10 +08:00
|
|
|
class EasyInstance(object):
|
|
|
|
def __init__(self, easy_model, instance):
|
|
|
|
self.model, self.instance = easy_model, instance
|
|
|
|
|
|
|
|
def __repr__(self):
|
2012-08-30 04:40:51 +08:00
|
|
|
return force_str('<EasyInstance for %s (%s)>' % (self.model.model._meta.object_name, self.instance._get_pk_val()))
|
2007-04-17 05:56:10 +08:00
|
|
|
|
2012-08-12 18:32:08 +08:00
|
|
|
def __str__(self):
|
2012-07-21 16:00:10 +08:00
|
|
|
val = smart_text(self.instance)
|
2007-12-19 11:58:53 +08:00
|
|
|
if len(val) > DISPLAY_SIZE:
|
2012-06-08 00:08:47 +08:00
|
|
|
return val[:DISPLAY_SIZE] + '...'
|
2007-04-17 05:56:10 +08:00
|
|
|
return val
|
|
|
|
|
|
|
|
def pk(self):
|
|
|
|
return self.instance._get_pk_val()
|
|
|
|
|
|
|
|
def url(self):
|
2012-07-03 07:33:44 +08:00
|
|
|
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()))
|
2007-04-17 05:56:10 +08:00
|
|
|
|
|
|
|
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):
|
2012-08-30 04:40:51 +08:00
|
|
|
return force_str('<EasyInstanceField for %s.%s>' % (self.model.model._meta.object_name, self.field.name))
|
2007-04-17 05:56:10 +08:00
|
|
|
|
|
|
|
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.
|
|
|
|
"""
|
2007-04-17 08:40:11 +08:00
|
|
|
# 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.
|
2007-04-17 05:56:10 +08:00
|
|
|
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:
|
2007-04-17 15:08:42 +08:00
|
|
|
objs = dict(self.field.choices).get(self.raw_value, EMPTY_VALUE)
|
2007-04-17 05:56:10 +08:00
|
|
|
elif isinstance(self.field, models.DateField) or isinstance(self.field, models.TimeField):
|
|
|
|
if self.raw_value:
|
|
|
|
if isinstance(self.field, models.DateTimeField):
|
2009-12-23 01:58:49 +08:00
|
|
|
objs = capfirst(formats.date_format(self.raw_value, 'DATETIME_FORMAT'))
|
2007-04-17 05:56:10 +08:00
|
|
|
elif isinstance(self.field, models.TimeField):
|
2010-01-02 05:36:36 +08:00
|
|
|
objs = capfirst(formats.time_format(self.raw_value, 'TIME_FORMAT'))
|
2007-04-17 05:56:10 +08:00
|
|
|
else:
|
2009-12-23 01:58:49 +08:00
|
|
|
objs = capfirst(formats.date_format(self.raw_value, 'DATE_FORMAT'))
|
2007-04-17 05:56:10 +08:00
|
|
|
else:
|
2007-04-17 15:08:42 +08:00
|
|
|
objs = EMPTY_VALUE
|
2007-04-17 05:56:10 +08:00
|
|
|
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():
|
2011-09-22 14:37:50 +08:00
|
|
|
if value is None:
|
|
|
|
continue
|
2012-07-03 07:33:44 +08:00
|
|
|
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()))
|
2012-07-21 16:00:10 +08:00
|
|
|
lst.append((smart_text(value), url))
|
2007-04-17 05:56:10 +08:00
|
|
|
else:
|
|
|
|
lst = [(value, None) for value in self.values()]
|
|
|
|
elif self.field.choices:
|
|
|
|
lst = []
|
|
|
|
for value in self.values():
|
2012-07-03 07:33:44 +08:00
|
|
|
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))
|
2007-04-17 05:56:10 +08:00
|
|
|
lst.append((value, url))
|
|
|
|
elif isinstance(self.field, models.URLField):
|
2012-07-21 03:14:27 +08:00
|
|
|
val = list(self.values())[0]
|
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
|
|
|
lst = [(val, iri_to_uri(val))]
|
2007-04-17 05:56:10 +08:00
|
|
|
else:
|
2012-07-21 03:14:27 +08:00
|
|
|
lst = [(list(self.values())[0], None)]
|
2007-04-17 05:56:10 +08:00
|
|
|
return lst
|
2007-08-20 01:01:54 +08:00
|
|
|
|
|
|
|
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
|