Ticket #6418: datastructures.py

File datastructures.py, 9.3 KB (added by Manish Singh <mdsingh@…>, 17 years ago)
Line 
1"""
2These classes are light wrappers around Django's database API that provide
3convenience functionality and permalink functions for the databrowse app.
4"""
5
6from django.db import models
7from django.utils import dateformat
8from django.utils.text import capfirst
9from django.utils.translation import get_date_formats
10from django.utils.encoding import smart_unicode, smart_str, iri_to_uri
11from django.utils.safestring import mark_safe
12from django.db.models.query import QuerySet
13from django.conf import settings
14
15EMPTY_VALUE = '(None)'
16DISPLAY_SIZE = 100
17
18class EasyModel(object):
19 def __init__(self, site, model):
20 self.site = site
21 self.model = model
22 self.model_list = site.registry.keys()
23 self.verbose_name = model._meta.verbose_name
24 self.verbose_name_plural = model._meta.verbose_name_plural
25
26 def __repr__(self):
27 return '<EasyModel for %s>' % smart_str(self.model._meta.object_name)
28
29 def model_databrowse(self):
30 "Returns the ModelDatabrowse class for this model."
31 return self.site.registry[self.model]
32
33 def url(self):
34 return mark_safe('%s%s/%s/' % (self.site.root_url, self.model._meta.app_label, self.model._meta.module_name))
35
36 def objects(self, **kwargs):
37 return self.get_query_set().filter(**kwargs)
38
39 def get_query_set(self):
40 easy_qs = self.model._default_manager.get_query_set()._clone(klass=EasyQuerySet)
41 easy_qs._easymodel = self
42 return easy_qs
43
44 def object_by_pk(self, pk):
45 return EasyInstance(self, self.model._default_manager.get(pk=pk))
46
47 def sample_objects(self):
48 for obj in self.model._default_manager.all()[:3]:
49 yield EasyInstance(self, obj)
50
51 def field(self, name):
52 try:
53 f = self.model._meta.get_field(name)
54 except models.FieldDoesNotExist:
55 return None
56 return EasyField(self, f)
57
58 def fields(self):
59 return [EasyField(self, f) for f in (self.model._meta.fields + self.model._meta.many_to_many)]
60
61class EasyField(object):
62 def __init__(self, easy_model, field):
63 self.model, self.field = easy_model, field
64
65 def __repr__(self):
66 return smart_str(u'<EasyField for %s.%s>' % (self.model.model._meta.object_name, self.field.name))
67
68 def choices(self):
69 for value, label in self.field.choices:
70 yield EasyChoice(self.model, self, value, label)
71
72 def url(self):
73 if self.field.choices:
74 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))
75 elif self.field.rel:
76 return mark_safe('%s%s/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name))
77
78class EasyChoice(object):
79 def __init__(self, easy_model, field, value, label):
80 self.model, self.field = easy_model, field
81 self.value, self.label = value, label
82
83 def __repr__(self):
84 return smart_str(u'<EasyChoice for %s.%s>' % (self.model.model._meta.object_name, self.field.name))
85
86 def url(self):
87 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)))
88
89class EasyInstance(object):
90 def __init__(self, easy_model, instance):
91 self.model, self.instance = easy_model, instance
92
93 def __repr__(self):
94 return smart_str(u'<EasyInstance for %s (%s)>' % (self.model.model._meta.object_name, self.instance._get_pk_val()))
95
96 def __unicode__(self):
97 val = smart_unicode(self.instance)
98 if len(val) > DISPLAY_SIZE:
99 return val[:DISPLAY_SIZE] + u'...'
100 return val
101
102 def __str__(self):
103 return self.__unicode__().encode('utf-8')
104
105 def pk(self):
106 return self.instance._get_pk_val()
107
108 def url(self):
109 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()))
110
111 def fields(self):
112 """
113 Generator that yields EasyInstanceFields for each field in this
114 EasyInstance's model.
115 """
116 for f in self.model.model._meta.fields + self.model.model._meta.many_to_many:
117 yield EasyInstanceField(self.model, self, f)
118
119 def related_objects(self):
120 """
121 Generator that yields dictionaries of all models that have this
122 EasyInstance's model as a ForeignKey or ManyToManyField, along with
123 lists of related objects.
124 """
125 for rel_object in self.model.model._meta.get_all_related_objects() + self.model.model._meta.get_all_related_many_to_many_objects():
126 if rel_object.model not in self.model.model_list:
127 continue # Skip models that aren't in the model_list
128 em = EasyModel(self.model.site, rel_object.model)
129 yield {
130 'model': em,
131 'related_field': rel_object.field.verbose_name,
132 'object_list': [EasyInstance(em, i) for i in getattr(self.instance, rel_object.get_accessor_name()).all()],
133 }
134
135class EasyInstanceField(object):
136 def __init__(self, easy_model, instance, field):
137 self.model, self.field, self.instance = easy_model, field, instance
138 self.raw_value = getattr(instance.instance, field.name)
139
140 def __repr__(self):
141 return smart_str(u'<EasyInstanceField for %s.%s>' % (self.model.model._meta.object_name, self.field.name))
142
143 def values(self):
144 """
145 Returns a list of values for this field for this instance. It's a list
146 so we can accomodate many-to-many fields.
147 """
148 # This import is deliberately inside the function because it causes
149 # some settings to be imported, and we don't want to do that at the
150 # module level.
151 if self.field.rel:
152 if isinstance(self.field.rel, models.ManyToOneRel):
153 objs = getattr(self.instance.instance, self.field.name)
154 elif isinstance(self.field.rel, models.ManyToManyRel): # ManyToManyRel
155 return list(getattr(self.instance.instance, self.field.name).all())
156 elif self.field.choices:
157 objs = dict(self.field.choices).get(self.raw_value, EMPTY_VALUE)
158 elif isinstance(self.field, models.DateField) or isinstance(self.field, models.TimeField):
159 if self.raw_value:
160 date_format, datetime_format, time_format = get_date_formats()
161 if isinstance(self.field, models.DateTimeField):
162 objs = capfirst(dateformat.format(self.raw_value, datetime_format))
163 elif isinstance(self.field, models.TimeField):
164 objs = capfirst(dateformat.time_format(self.raw_value, time_format))
165 else:
166 objs = capfirst(dateformat.format(self.raw_value, date_format))
167 else:
168 objs = EMPTY_VALUE
169 elif isinstance(self.field, models.BooleanField) or isinstance(self.field, models.NullBooleanField):
170 objs = {True: 'Yes', False: 'No', None: 'Unknown'}[self.raw_value]
171 else:
172 objs = self.raw_value
173 return [objs]
174
175 def urls(self):
176 "Returns a list of (value, URL) tuples."
177 # First, check the urls() method for each plugin.
178 plugin_urls = []
179 for plugin_name, plugin in self.model.model_databrowse().plugins.items():
180 urls = plugin.urls(plugin_name, self)
181 if urls is not None and settings.MEDIA_URL:
182 if isinstance(self.field, models.FileField):
183 urls = [settings.MEDIA_URL + self.values()[0].replace('\\', '/')]
184 #plugin_urls.append(urls)
185 values = self.values()
186 return zip(self.values(), urls)
187 if self.field.rel:
188 m = EasyModel(self.model.site, self.field.rel.to)
189 if self.field.rel.to in self.model.model_list:
190 lst = []
191 for value in self.values():
192 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())))
193 lst.append((smart_unicode(value), url))
194 else:
195 lst = [(value, None) for value in self.values()]
196 elif self.field.choices:
197 lst = []
198 for value in self.values():
199 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)))
200 lst.append((value, url))
201 elif isinstance(self.field, models.URLField):
202 val = self.values()[0]
203 lst = [(val, iri_to_uri(val))]
204 else:
205 lst = [(self.values()[0], None)]
206 return lst
207
208class EasyQuerySet(QuerySet):
209 """
210 When creating (or cloning to) an `EasyQuerySet`, make sure to set the
211 `_easymodel` variable to the related `EasyModel`.
212 """
213 def iterator(self, *args, **kwargs):
214 for obj in super(EasyQuerySet, self).iterator(*args, **kwargs):
215 yield EasyInstance(self._easymodel, obj)
216
217 def _clone(self, *args, **kwargs):
218 c = super(EasyQuerySet, self)._clone(*args, **kwargs)
219 c._easymodel = self._easymodel
220 return c
Back to Top