| """ |
| 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 |