Django

Code

root/django/branches/unicode/django/db/models/options.py

Revision 5531, 12.1 kB (checked in by mtredinnick, 1 year ago)

unicode: Merged from trunk up to [5530]. Oracle backend has not been ported to
support unicode yet.

  • Property svn:eol-style set to native
Line 
1 from django.conf import settings
2 from django.db.models.related import RelatedObject
3 from django.db.models.fields.related import ManyToManyRel
4 from django.db.models.fields import AutoField, FieldDoesNotExist
5 from django.db.models.loading import get_models
6 from django.db.models.query import orderlist2sql
7 from django.db.models import Manager
8 from django.utils.translation import activate, deactivate_all, get_language, string_concat
9 from django.utils.encoding import force_unicode, smart_str
10 from bisect import bisect
11 import re
12
13 # Calculate the verbose_name by converting from InitialCaps to "lowercase with spaces".
14 get_verbose_name = lambda class_name: re.sub('(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]|$)))', ' \\1', class_name).lower().strip()
15
16 DEFAULT_NAMES = ('verbose_name', 'db_table', 'ordering',
17                  'unique_together', 'permissions', 'get_latest_by',
18                  'order_with_respect_to', 'app_label', 'db_tablespace')
19
20 class Options(object):
21     def __init__(self, meta):
22         self.fields, self.many_to_many = [], []
23         self.module_name, self.verbose_name = None, None
24         self.verbose_name_plural = None
25         self.db_table = ''
26         self.ordering = []
27         self.unique_together =  []
28         self.permissions =  []
29         self.object_name, self.app_label = None, None
30         self.get_latest_by = None
31         self.order_with_respect_to = None
32         self.db_tablespace = None
33         self.admin = None
34         self.meta = meta
35         self.pk = None
36         self.has_auto_field = False
37         self.one_to_one_field = None
38         self.parents = []
39
40     def contribute_to_class(self, cls, name):
41         cls._meta = self
42         self.installed = re.sub('\.models$', '', cls.__module__) in settings.INSTALLED_APPS
43         # First, construct the default values for these options.
44         self.object_name = cls.__name__
45         self.module_name = self.object_name.lower()
46         self.verbose_name = get_verbose_name(self.object_name)
47
48         # Next, apply any overridden values from 'class Meta'.
49         if self.meta:
50             meta_attrs = self.meta.__dict__
51             del meta_attrs['__module__']
52             del meta_attrs['__doc__']
53             for attr_name in DEFAULT_NAMES:
54                 setattr(self, attr_name, meta_attrs.pop(attr_name, getattr(self, attr_name)))
55             # verbose_name_plural is a special case because it uses a 's'
56             # by default.
57             setattr(self, 'verbose_name_plural', meta_attrs.pop('verbose_name_plural', string_concat(self.verbose_name, 's')))
58             # Any leftover attributes must be invalid.
59             if meta_attrs != {}:
60                 raise TypeError, "'class Meta' got invalid attribute(s): %s" % ','.join(meta_attrs.keys())
61         else:
62             self.verbose_name_plural = string_concat(self.verbose_name, 's')
63         del self.meta
64
65     def _prepare(self, model):
66         from django.db import backend
67         from django.db.backends.util import truncate_name
68         if self.order_with_respect_to:
69             self.order_with_respect_to = self.get_field(self.order_with_respect_to)
70             self.ordering = ('_order',)
71         else:
72             self.order_with_respect_to = None
73
74         if self.pk is None:
75             auto = AutoField(verbose_name='ID', primary_key=True)
76             auto.creation_counter = -1
77             model.add_to_class('id', auto)
78
79         # If the db_table wasn't provided, use the app_label + module_name.
80         if not self.db_table:
81             self.db_table = "%s_%s" % (self.app_label, self.module_name)
82             self.db_table = truncate_name(self.db_table,
83                                           backend.get_max_name_length())
84
85     def add_field(self, field):
86         # Insert the given field in the order in which it was created, using
87         # the "creation_counter" attribute of the field.
88         # Move many-to-many related fields from self.fields into self.many_to_many.
89         if field.rel and isinstance(field.rel, ManyToManyRel):
90             self.many_to_many.insert(bisect(self.many_to_many, field), field)
91         else:
92             self.fields.insert(bisect(self.fields, field), field)
93             if not self.pk and field.primary_key:
94                 self.pk = field
95                 field.serialize = False
96
97     def __repr__(self):
98         return '<Options for %s>' % self.object_name
99
100     def __str__(self):
101         return "%s.%s" % (smart_str(self.app_label), smart_str(self.module_name))
102
103     def verbose_name_raw(self):
104         """
105         There are a few places where the untranslated verbose name is needed
106         (so that we get the same value regardless of currently active
107         locale).
108         """
109         lang = get_language()
110         deactivate_all()
111         raw = force_unicode(self.verbose_name)
112         activate(lang)
113         return raw
114     verbose_name_raw = property(verbose_name_raw)
115
116     def get_field(self, name, many_to_many=True):
117         "Returns the requested field by name. Raises FieldDoesNotExist on error."
118         to_search = many_to_many and (self.fields + self.many_to_many) or self.fields
119         for f in to_search:
120             if f.name == name:
121                 return f
122         raise FieldDoesNotExist, '%s has no field named %r' % (self.object_name, name)
123
124     def get_order_sql(self, table_prefix=''):
125         "Returns the full 'ORDER BY' clause for this object, according to self.ordering."
126         if not self.ordering: return ''
127         pre = table_prefix and (table_prefix + '.') or ''
128         return 'ORDER BY ' + orderlist2sql(self.ordering, self, pre)
129
130     def get_add_permission(self):
131         return 'add_%s' % self.object_name.lower()
132
133     def get_change_permission(self):
134         return 'change_%s' % self.object_name.lower()
135
136     def get_delete_permission(self):
137         return 'delete_%s' % self.object_name.lower()
138
139     def get_all_related_objects(self):
140         try: # Try the cache first.
141             return self._all_related_objects
142         except AttributeError:
143             rel_objs = []
144             for klass in get_models():
145                 for f in klass._meta.fields:
146                     if f.rel and self == f.rel.to._meta:
147                         rel_objs.append(RelatedObject(f.rel.to, klass, f))
148             self._all_related_objects = rel_objs
149             return rel_objs
150
151     def get_followed_related_objects(self, follow=None):
152         if follow == None:
153             follow = self.get_follow()
154         return [f for f in self.get_all_related_objects() if follow.get(f.name, None)]
155
156     def get_data_holders(self, follow=None):
157         if follow == None:
158             follow = self.get_follow()
159         return [f for f in self.fields + self.many_to_many + self.get_all_related_objects() if follow.get(f.name, None)]
160
161     def get_follow(self, override=None):
162         follow = {}
163         for f in self.fields + self.many_to_many + self.get_all_related_objects():
164             if override and f.name in override:
165                 child_override = override[f.name]
166             else:
167                 child_override = None
168             fol = f.get_follow(child_override)
169             if fol != None:
170                 follow[f.name] = fol
171         return follow
172
173     def get_all_related_many_to_many_objects(self):
174         try: # Try the cache first.
175             return self._all_related_many_to_many_objects
176         except AttributeError:
177             rel_objs = []
178             for klass in get_models():
179                 for f in klass._meta.many_to_many:
180                     if f.rel and self == f.rel.to._meta:
181                         rel_objs.append(RelatedObject(f.rel.to, klass, f))
182             self._all_related_many_to_many_objects = rel_objs
183             return rel_objs
184
185     def get_ordered_objects(self):
186         "Returns a list of Options objects that are ordered with respect to this object."
187         if not hasattr(self, '_ordered_objects'):
188             objects = []
189             # TODO
190             #for klass in get_models(get_app(self.app_label)):
191             #    opts = klass._meta
192             #    if opts.order_with_respect_to and opts.order_with_respect_to.rel \
193             #        and self == opts.order_with_respect_to.rel.to._meta:
194             #        objects.append(opts)
195             self._ordered_objects = objects
196         return self._ordered_objects
197
198     def has_field_type(self, field_type, follow=None):
199         """
200         Returns True if this object's admin form has at least one of the given
201         field_type (e.g. FileField).
202         """
203         # TODO: follow
204         if not hasattr(self, '_field_types'):
205             self._field_types = {}
206         if field_type not in self._field_types:
207             try:
208                 # First check self.fields.
209                 for f in self.fields:
210                     if isinstance(f, field_type):
211                         raise StopIteration
212                 # Failing that, check related fields.
213                 for related in self.get_followed_related_objects(follow):
214                     for f in related.opts.fields:
215                         if isinstance(f, field_type):
216                             raise StopIteration
217             except StopIteration:
218                 self._field_types[field_type] = True
219             else:
220                 self._field_types[field_type] = False
221         return self._field_types[field_type]
222
223 class AdminOptions(object):
224     def __init__(self, fields=None, js=None, list_display=None, list_display_links=None, list_filter=None,
225         date_hierarchy=None, save_as=False, ordering=None, search_fields=None,
226         save_on_top=False, list_select_related=False, manager=None, list_per_page=100):
227         self.fields = fields
228         self.js = js or []
229         self.list_display = list_display or ['__str__']
230         self.list_display_links = list_display_links or []
231         self.list_filter = list_filter or []
232         self.date_hierarchy = date_hierarchy
233         self.save_as, self.ordering = save_as, ordering
234         self.search_fields = search_fields or []
235         self.save_on_top = save_on_top
236         self.list_select_related = list_select_related
237         self.list_per_page = list_per_page
238         self.manager = manager or Manager()
239
240     def get_field_sets(self, opts):
241         "Returns a list of AdminFieldSet objects for this AdminOptions object."
242         if self.fields is None:
243             field_struct = ((None, {'fields': [f.name for f in opts.fields + opts.many_to_many if f.editable and not isinstance(f, AutoField)]}),)
244         else:
245             field_struct = self.fields
246         new_fieldset_list = []
247         for fieldset in field_struct:
248             fs_options = fieldset[1]
249             classes = fs_options.get('classes', ())
250             description = fs_options.get('description', '')
251             new_fieldset_list.append(AdminFieldSet(fieldset[0], classes,
252                 opts.get_field, fs_options['fields'], description))
253         return new_fieldset_list
254
255     def contribute_to_class(self, cls, name):
256         cls._meta.admin = self
257         # Make sure the admin manager has access to the model
258         self.manager.model = cls
259
260 class AdminFieldSet(object):
261     def __init__(self, name, classes, field_locator_func, line_specs, description):
262         self.name = name
263         self.field_lines = [AdminFieldLine(field_locator_func, line_spec) for line_spec in line_specs]
264         self.classes = classes
265         self.description = description
266
267     def __repr__(self):
268         return "FieldSet: (%s, %s)" % (self.name, self.field_lines)
269
270     def bind(self, field_mapping, original, bound_field_set_class):
271         return bound_field_set_class(self, field_mapping, original)
272
273     def __iter__(self):
274         for field_line in self.field_lines:
275             yield field_line
276
277     def __len__(self):
278         return len(self.field_lines)
279
280 class AdminFieldLine(object):
281     def __init__(self, field_locator_func, linespec):
282         if isinstance(linespec, basestring):
283             self.fields = [field_locator_func(linespec)]
284         else:
285             self.fields = [field_locator_func(field_name) for field_name in linespec]
286
287     def bind(self, field_mapping, original, bound_field_line_class):
288         return bound_field_line_class(self, field_mapping, original)
289
290     def __iter__(self):
291         for field in self.fields:
292             yield field
293
294     def __len__(self):
295         return len(self.fields)
Note: See TracBrowser for help on using the browser.