2
from bisect import bisect
6
from sets import Set as set # Python 2.3 fallback
8
from django.conf import settings
9
from django.db.models.related import RelatedObject
10
from django.db.models.fields.related import ManyToManyRel
11
from django.db.models.fields import AutoField, FieldDoesNotExist
12
from django.db.models.fields.proxy import OrderWrt
13
from django.db.models.loading import get_models, app_cache_ready
14
from django.utils.translation import activate, deactivate_all, get_language, string_concat
15
from django.utils.encoding import force_unicode, smart_str
16
from django.utils.datastructures import SortedDict
18
# Calculate the verbose_name by converting from InitialCaps to "lowercase with spaces".
19
get_verbose_name = lambda class_name: re.sub('(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]|$)))', ' \\1', class_name).lower().strip()
21
DEFAULT_NAMES = ('verbose_name', 'db_table', 'ordering',
22
'unique_together', 'permissions', 'get_latest_by',
23
'order_with_respect_to', 'app_label', 'db_tablespace',
26
class Options(object):
27
def __init__(self, meta, app_label=None):
28
self.local_fields, self.local_many_to_many = [], []
29
self.virtual_fields = []
30
self.module_name, self.verbose_name = None, None
31
self.verbose_name_plural = None
34
self.unique_together = []
36
self.object_name, self.app_label = None, app_label
37
self.get_latest_by = None
38
self.order_with_respect_to = None
39
self.db_tablespace = settings.DEFAULT_TABLESPACE
43
self.has_auto_field, self.auto_field = False, None
44
self.one_to_one_field = None
46
self.parents = SortedDict()
47
self.duplicate_targets = {}
48
# Managers that have been inherited from abstract base classes. These
49
# are passed onto any children.
50
self.abstract_managers = []
52
def contribute_to_class(self, cls, name):
53
from django.db import connection
54
from django.db.backends.util import truncate_name
57
self.installed = re.sub('\.models$', '', cls.__module__) in settings.INSTALLED_APPS
58
# First, construct the default values for these options.
59
self.object_name = cls.__name__
60
self.module_name = self.object_name.lower()
61
self.verbose_name = get_verbose_name(self.object_name)
63
# Next, apply any overridden values from 'class Meta'.
65
meta_attrs = self.meta.__dict__.copy()
66
for name in self.meta.__dict__:
67
# Ignore any private attributes that Django doesn't care about.
68
# NOTE: We can't modify a dictionary's contents while looping
69
# over it, so we loop over the *original* dictionary instead.
70
if name.startswith('_'):
72
for attr_name in DEFAULT_NAMES:
73
if attr_name in meta_attrs:
74
setattr(self, attr_name, meta_attrs.pop(attr_name))
75
elif hasattr(self.meta, attr_name):
76
setattr(self, attr_name, getattr(self.meta, attr_name))
78
# unique_together can be either a tuple of tuples, or a single
79
# tuple of two strings. Normalize it to a tuple of tuples, so that
80
# calling code can uniformly expect that.
81
ut = meta_attrs.pop('unique_together', getattr(self, 'unique_together'))
82
if ut and not isinstance(ut[0], (tuple, list)):
84
setattr(self, 'unique_together', ut)
86
# verbose_name_plural is a special case because it uses a 's'
88
setattr(self, 'verbose_name_plural', meta_attrs.pop('verbose_name_plural', string_concat(self.verbose_name, 's')))
90
# Any leftover attributes must be invalid.
92
raise TypeError, "'class Meta' got invalid attribute(s): %s" % ','.join(meta_attrs.keys())
94
self.verbose_name_plural = string_concat(self.verbose_name, 's')
97
# If the db_table wasn't provided, use the app_label + module_name.
99
self.db_table = "%s_%s" % (self.app_label, self.module_name)
100
self.db_table = truncate_name(self.db_table, connection.ops.max_name_length())
103
def _prepare(self, model):
104
if self.order_with_respect_to:
105
self.order_with_respect_to = self.get_field(self.order_with_respect_to)
106
self.ordering = ('_order',)
108
self.order_with_respect_to = None
112
# Promote the first parent link in lieu of adding yet another
114
field = self.parents.value_for_index(0)
115
field.primary_key = True
118
auto = AutoField(verbose_name='ID', primary_key=True,
120
model.add_to_class('id', auto)
122
# Determine any sets of fields that are pointing to the same targets
123
# (e.g. two ForeignKeys to the same remote model). The query
124
# construction code needs to know this. At the end of this,
125
# self.duplicate_targets will map each duplicate field column to the
126
# columns it duplicates.
128
for column, target in self.duplicate_targets.iteritems():
130
collections[target].add(column)
132
collections[target] = set([column])
133
self.duplicate_targets = {}
134
for elt in collections.itervalues():
138
self.duplicate_targets[column] = elt.difference(set([column]))
140
def add_field(self, field):
141
# Insert the given field in the order in which it was created, using
142
# the "creation_counter" attribute of the field.
143
# Move many-to-many related fields from self.fields into
145
if field.rel and isinstance(field.rel, ManyToManyRel):
146
self.local_many_to_many.insert(bisect(self.local_many_to_many, field), field)
147
if hasattr(self, '_m2m_cache'):
150
self.local_fields.insert(bisect(self.local_fields, field), field)
152
if hasattr(self, '_field_cache'):
153
del self._field_cache
154
del self._field_name_cache
156
if hasattr(self, '_name_map'):
159
def add_virtual_field(self, field):
160
self.virtual_fields.append(field)
162
def setup_pk(self, field):
163
if not self.pk and field.primary_key:
165
field.serialize = False
168
return '<Options for %s>' % self.object_name
171
return "%s.%s" % (smart_str(self.app_label), smart_str(self.module_name))
173
def verbose_name_raw(self):
175
There are a few places where the untranslated verbose name is needed
176
(so that we get the same value regardless of currently active
179
lang = get_language()
181
raw = force_unicode(self.verbose_name)
184
verbose_name_raw = property(verbose_name_raw)
188
The getter for self.fields. This returns the list of field objects
189
available to this model (including through parent models).
191
Callers are not permitted to modify this list, since it's a reference
192
to this instance (not a copy).
195
self._field_name_cache
196
except AttributeError:
197
self._fill_fields_cache()
198
return self._field_name_cache
199
fields = property(_fields)
201
def get_fields_with_model(self):
203
Returns a sequence of (field, model) pairs for all fields. The "model"
204
element is None for fields on the current model. Mostly of use when
205
constructing queries so that we know which model a field belongs to.
209
except AttributeError:
210
self._fill_fields_cache()
211
return self._field_cache
213
def _fill_fields_cache(self):
215
for parent in self.parents:
216
for field, model in parent._meta.get_fields_with_model():
218
cache.append((field, model))
220
cache.append((field, parent))
221
cache.extend([(f, None) for f in self.local_fields])
222
self._field_cache = tuple(cache)
223
self._field_name_cache = [x for x, _ in cache]
225
def _many_to_many(self):
228
except AttributeError:
229
self._fill_m2m_cache()
230
return self._m2m_cache.keys()
231
many_to_many = property(_many_to_many)
233
def get_m2m_with_model(self):
235
The many-to-many version of get_fields_with_model().
239
except AttributeError:
240
self._fill_m2m_cache()
241
return self._m2m_cache.items()
243
def _fill_m2m_cache(self):
245
for parent in self.parents:
246
for field, model in parent._meta.get_m2m_with_model():
250
cache[field] = parent
251
for field in self.local_many_to_many:
253
self._m2m_cache = cache
255
def get_field(self, name, many_to_many=True):
257
Returns the requested field by name. Raises FieldDoesNotExist on error.
259
to_search = many_to_many and (self.fields + self.many_to_many) or self.fields
263
raise FieldDoesNotExist, '%s has no field named %r' % (self.object_name, name)
265
def get_field_by_name(self, name):
267
Returns the (field_object, model, direct, m2m), where field_object is
268
the Field instance for the given name, model is the model containing
269
this field (None for local fields), direct is True if the field exists
270
on this model, and m2m is True for many-to-many relations. When
271
'direct' is False, 'field_object' is the corresponding RelatedObject
272
for this field (since the field doesn't have an instance associated
275
Uses a cache internally, so after the first access, this is very fast.
279
return self._name_map[name]
280
except AttributeError:
281
cache = self.init_name_map()
284
raise FieldDoesNotExist('%s has no field named %r'
285
% (self.object_name, name))
287
def get_all_field_names(self):
289
Returns a list of all field names that are possible for this model
290
(including reverse relation names). This is used for pretty printing
291
debugging output (a list of choices), so any internal-only field names
295
cache = self._name_map
296
except AttributeError:
297
cache = self.init_name_map()
300
# Internal-only names end with "+" (symmetrical m2m related names being
301
# the main example). Trim them.
302
return [val for val in names if not val.endswith('+')]
304
def init_name_map(self):
306
Initialises the field name -> field object mapping.
309
# We intentionally handle related m2m objects first so that symmetrical
310
# m2m accessor names can be overridden, if necessary.
311
for f, model in self.get_all_related_m2m_objects_with_model():
312
cache[f.field.related_query_name()] = (f, model, False, True)
313
for f, model in self.get_all_related_objects_with_model():
314
cache[f.field.related_query_name()] = (f, model, False, False)
315
for f, model in self.get_m2m_with_model():
316
cache[f.name] = (f, model, True, True)
317
for f, model in self.get_fields_with_model():
318
cache[f.name] = (f, model, True, False)
319
if self.order_with_respect_to:
320
cache['_order'] = OrderWrt(), None, True, False
321
if app_cache_ready():
322
self._name_map = cache
325
def get_add_permission(self):
326
return 'add_%s' % self.object_name.lower()
328
def get_change_permission(self):
329
return 'change_%s' % self.object_name.lower()
331
def get_delete_permission(self):
332
return 'delete_%s' % self.object_name.lower()
334
def get_all_related_objects(self, local_only=False):
336
self._related_objects_cache
337
except AttributeError:
338
self._fill_related_objects_cache()
340
return [k for k, v in self._related_objects_cache.items() if not v]
341
return self._related_objects_cache.keys()
343
def get_all_related_objects_with_model(self):
345
Returns a list of (related-object, model) pairs. Similar to
346
get_fields_with_model().
349
self._related_objects_cache
350
except AttributeError:
351
self._fill_related_objects_cache()
352
return self._related_objects_cache.items()
354
def _fill_related_objects_cache(self):
356
parent_list = self.get_parent_list()
357
for parent in self.parents:
358
for obj, model in parent._meta.get_all_related_objects_with_model():
359
if (obj.field.creation_counter < 0 or obj.field.rel.parent_link) and obj.model not in parent_list:
365
for klass in get_models():
366
for f in klass._meta.local_fields:
367
if f.rel and not isinstance(f.rel.to, str) and self == f.rel.to._meta:
368
cache[RelatedObject(f.rel.to, klass, f)] = None
369
self._related_objects_cache = cache
371
def get_all_related_many_to_many_objects(self, local_only=False):
373
cache = self._related_many_to_many_cache
374
except AttributeError:
375
cache = self._fill_related_many_to_many_cache()
377
return [k for k, v in cache.items() if not v]
380
def get_all_related_m2m_objects_with_model(self):
382
Returns a list of (related-m2m-object, model) pairs. Similar to
383
get_fields_with_model().
386
cache = self._related_many_to_many_cache
387
except AttributeError:
388
cache = self._fill_related_many_to_many_cache()
391
def _fill_related_many_to_many_cache(self):
393
parent_list = self.get_parent_list()
394
for parent in self.parents:
395
for obj, model in parent._meta.get_all_related_m2m_objects_with_model():
396
if obj.field.creation_counter < 0 and obj.model not in parent_list:
402
for klass in get_models():
403
for f in klass._meta.local_many_to_many:
404
if f.rel and not isinstance(f.rel.to, str) and self == f.rel.to._meta:
405
cache[RelatedObject(f.rel.to, klass, f)] = None
406
if app_cache_ready():
407
self._related_many_to_many_cache = cache
410
def get_base_chain(self, model):
412
Returns a list of parent classes leading to 'model' (order from closet
413
to most distant ancestor). This has to handle the case were 'model' is
414
a granparent or even more distant relation.
418
if model in self.parents:
420
for parent in self.parents:
421
res = parent._meta.get_base_chain(model)
423
res.insert(0, parent)
425
raise TypeError('%r is not an ancestor of this model'
426
% model._meta.module_name)
428
def get_parent_list(self):
430
Returns a list of all the ancestor of this model as a list. Useful for
431
determining if something is an ancestor, regardless of lineage.
434
for parent in self.parents:
436
result.update(parent._meta.get_parent_list())
439
def get_ordered_objects(self):
440
"Returns a list of Options objects that are ordered with respect to this object."
441
if not hasattr(self, '_ordered_objects'):
444
#for klass in get_models(get_app(self.app_label)):
446
# if opts.order_with_respect_to and opts.order_with_respect_to.rel \
447
# and self == opts.order_with_respect_to.rel.to._meta:
448
# objects.append(opts)
449
self._ordered_objects = objects
450
return self._ordered_objects