web/lib/django/db/models/options.py
changeset 0 0d40e90630ef
child 29 cc9b7e14412b
equal deleted inserted replaced
-1:000000000000 0:0d40e90630ef
       
     1 import re
       
     2 from bisect import bisect
       
     3 try:
       
     4     set
       
     5 except NameError:
       
     6     from sets import Set as set     # Python 2.3 fallback
       
     7 
       
     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
       
    17 
       
    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()
       
    20 
       
    21 DEFAULT_NAMES = ('verbose_name', 'db_table', 'ordering',
       
    22                  'unique_together', 'permissions', 'get_latest_by',
       
    23                  'order_with_respect_to', 'app_label', 'db_tablespace',
       
    24                  'abstract', 'managed', 'proxy')
       
    25 
       
    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
       
    32         self.db_table = ''
       
    33         self.ordering = []
       
    34         self.unique_together =  []
       
    35         self.permissions =  []
       
    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
       
    40         self.admin = None
       
    41         self.meta = meta
       
    42         self.pk = None
       
    43         self.has_auto_field, self.auto_field = False, None
       
    44         self.abstract = False
       
    45         self.managed = True
       
    46         self.proxy = False
       
    47         self.proxy_for_model = None
       
    48         self.parents = SortedDict()
       
    49         self.duplicate_targets = {}
       
    50 
       
    51         # To handle various inheritance situations, we need to track where
       
    52         # managers came from (concrete or abstract base classes).
       
    53         self.abstract_managers = []
       
    54         self.concrete_managers = []
       
    55 
       
    56     def contribute_to_class(self, cls, name):
       
    57         from django.db import connection
       
    58         from django.db.backends.util import truncate_name
       
    59 
       
    60         cls._meta = self
       
    61         self.installed = re.sub('\.models$', '', cls.__module__) in settings.INSTALLED_APPS
       
    62         # First, construct the default values for these options.
       
    63         self.object_name = cls.__name__
       
    64         self.module_name = self.object_name.lower()
       
    65         self.verbose_name = get_verbose_name(self.object_name)
       
    66 
       
    67         # Next, apply any overridden values from 'class Meta'.
       
    68         if self.meta:
       
    69             meta_attrs = self.meta.__dict__.copy()
       
    70             for name in self.meta.__dict__:
       
    71                 # Ignore any private attributes that Django doesn't care about.
       
    72                 # NOTE: We can't modify a dictionary's contents while looping
       
    73                 # over it, so we loop over the *original* dictionary instead.
       
    74                 if name.startswith('_'):
       
    75                     del meta_attrs[name]
       
    76             for attr_name in DEFAULT_NAMES:
       
    77                 if attr_name in meta_attrs:
       
    78                     setattr(self, attr_name, meta_attrs.pop(attr_name))
       
    79                 elif hasattr(self.meta, attr_name):
       
    80                     setattr(self, attr_name, getattr(self.meta, attr_name))
       
    81 
       
    82             # unique_together can be either a tuple of tuples, or a single
       
    83             # tuple of two strings. Normalize it to a tuple of tuples, so that
       
    84             # calling code can uniformly expect that.
       
    85             ut = meta_attrs.pop('unique_together', getattr(self, 'unique_together'))
       
    86             if ut and not isinstance(ut[0], (tuple, list)):
       
    87                 ut = (ut,)
       
    88             setattr(self, 'unique_together', ut)
       
    89 
       
    90             # verbose_name_plural is a special case because it uses a 's'
       
    91             # by default.
       
    92             setattr(self, 'verbose_name_plural', meta_attrs.pop('verbose_name_plural', string_concat(self.verbose_name, 's')))
       
    93 
       
    94             # Any leftover attributes must be invalid.
       
    95             if meta_attrs != {}:
       
    96                 raise TypeError, "'class Meta' got invalid attribute(s): %s" % ','.join(meta_attrs.keys())
       
    97         else:
       
    98             self.verbose_name_plural = string_concat(self.verbose_name, 's')
       
    99         del self.meta
       
   100 
       
   101         # If the db_table wasn't provided, use the app_label + module_name.
       
   102         if not self.db_table:
       
   103             self.db_table = "%s_%s" % (self.app_label, self.module_name)
       
   104             self.db_table = truncate_name(self.db_table, connection.ops.max_name_length())
       
   105 
       
   106 
       
   107     def _prepare(self, model):
       
   108         if self.order_with_respect_to:
       
   109             self.order_with_respect_to = self.get_field(self.order_with_respect_to)
       
   110             self.ordering = ('_order',)
       
   111         else:
       
   112             self.order_with_respect_to = None
       
   113 
       
   114         if self.pk is None:
       
   115             if self.parents:
       
   116                 # Promote the first parent link in lieu of adding yet another
       
   117                 # field.
       
   118                 field = self.parents.value_for_index(0)
       
   119                 field.primary_key = True
       
   120                 self.setup_pk(field)
       
   121             else:
       
   122                 auto = AutoField(verbose_name='ID', primary_key=True,
       
   123                         auto_created=True)
       
   124                 model.add_to_class('id', auto)
       
   125 
       
   126         # Determine any sets of fields that are pointing to the same targets
       
   127         # (e.g. two ForeignKeys to the same remote model). The query
       
   128         # construction code needs to know this. At the end of this,
       
   129         # self.duplicate_targets will map each duplicate field column to the
       
   130         # columns it duplicates.
       
   131         collections = {}
       
   132         for column, target in self.duplicate_targets.iteritems():
       
   133             try:
       
   134                 collections[target].add(column)
       
   135             except KeyError:
       
   136                 collections[target] = set([column])
       
   137         self.duplicate_targets = {}
       
   138         for elt in collections.itervalues():
       
   139             if len(elt) == 1:
       
   140                 continue
       
   141             for column in elt:
       
   142                 self.duplicate_targets[column] = elt.difference(set([column]))
       
   143 
       
   144     def add_field(self, field):
       
   145         # Insert the given field in the order in which it was created, using
       
   146         # the "creation_counter" attribute of the field.
       
   147         # Move many-to-many related fields from self.fields into
       
   148         # self.many_to_many.
       
   149         if field.rel and isinstance(field.rel, ManyToManyRel):
       
   150             self.local_many_to_many.insert(bisect(self.local_many_to_many, field), field)
       
   151             if hasattr(self, '_m2m_cache'):
       
   152                 del self._m2m_cache
       
   153         else:
       
   154             self.local_fields.insert(bisect(self.local_fields, field), field)
       
   155             self.setup_pk(field)
       
   156             if hasattr(self, '_field_cache'):
       
   157                 del self._field_cache
       
   158                 del self._field_name_cache
       
   159 
       
   160         if hasattr(self, '_name_map'):
       
   161             del self._name_map
       
   162 
       
   163     def add_virtual_field(self, field):
       
   164         self.virtual_fields.append(field)
       
   165 
       
   166     def setup_pk(self, field):
       
   167         if not self.pk and field.primary_key:
       
   168             self.pk = field
       
   169             field.serialize = False
       
   170 
       
   171     def setup_proxy(self, target):
       
   172         """
       
   173         Does the internal setup so that the current model is a proxy for
       
   174         "target".
       
   175         """
       
   176         self.pk = target._meta.pk
       
   177         self.proxy_for_model = target
       
   178         self.db_table = target._meta.db_table
       
   179 
       
   180     def __repr__(self):
       
   181         return '<Options for %s>' % self.object_name
       
   182 
       
   183     def __str__(self):
       
   184         return "%s.%s" % (smart_str(self.app_label), smart_str(self.module_name))
       
   185 
       
   186     def verbose_name_raw(self):
       
   187         """
       
   188         There are a few places where the untranslated verbose name is needed
       
   189         (so that we get the same value regardless of currently active
       
   190         locale).
       
   191         """
       
   192         lang = get_language()
       
   193         deactivate_all()
       
   194         raw = force_unicode(self.verbose_name)
       
   195         activate(lang)
       
   196         return raw
       
   197     verbose_name_raw = property(verbose_name_raw)
       
   198 
       
   199     def _fields(self):
       
   200         """
       
   201         The getter for self.fields. This returns the list of field objects
       
   202         available to this model (including through parent models).
       
   203 
       
   204         Callers are not permitted to modify this list, since it's a reference
       
   205         to this instance (not a copy).
       
   206         """
       
   207         try:
       
   208             self._field_name_cache
       
   209         except AttributeError:
       
   210             self._fill_fields_cache()
       
   211         return self._field_name_cache
       
   212     fields = property(_fields)
       
   213 
       
   214     def get_fields_with_model(self):
       
   215         """
       
   216         Returns a sequence of (field, model) pairs for all fields. The "model"
       
   217         element is None for fields on the current model. Mostly of use when
       
   218         constructing queries so that we know which model a field belongs to.
       
   219         """
       
   220         try:
       
   221             self._field_cache
       
   222         except AttributeError:
       
   223             self._fill_fields_cache()
       
   224         return self._field_cache
       
   225 
       
   226     def _fill_fields_cache(self):
       
   227         cache = []
       
   228         for parent in self.parents:
       
   229             for field, model in parent._meta.get_fields_with_model():
       
   230                 if model:
       
   231                     cache.append((field, model))
       
   232                 else:
       
   233                     cache.append((field, parent))
       
   234         cache.extend([(f, None) for f in self.local_fields])
       
   235         self._field_cache = tuple(cache)
       
   236         self._field_name_cache = [x for x, _ in cache]
       
   237 
       
   238     def _many_to_many(self):
       
   239         try:
       
   240             self._m2m_cache
       
   241         except AttributeError:
       
   242             self._fill_m2m_cache()
       
   243         return self._m2m_cache.keys()
       
   244     many_to_many = property(_many_to_many)
       
   245 
       
   246     def get_m2m_with_model(self):
       
   247         """
       
   248         The many-to-many version of get_fields_with_model().
       
   249         """
       
   250         try:
       
   251             self._m2m_cache
       
   252         except AttributeError:
       
   253             self._fill_m2m_cache()
       
   254         return self._m2m_cache.items()
       
   255 
       
   256     def _fill_m2m_cache(self):
       
   257         cache = SortedDict()
       
   258         for parent in self.parents:
       
   259             for field, model in parent._meta.get_m2m_with_model():
       
   260                 if model:
       
   261                     cache[field] = model
       
   262                 else:
       
   263                     cache[field] = parent
       
   264         for field in self.local_many_to_many:
       
   265             cache[field] = None
       
   266         self._m2m_cache = cache
       
   267 
       
   268     def get_field(self, name, many_to_many=True):
       
   269         """
       
   270         Returns the requested field by name. Raises FieldDoesNotExist on error.
       
   271         """
       
   272         to_search = many_to_many and (self.fields + self.many_to_many) or self.fields
       
   273         for f in to_search:
       
   274             if f.name == name:
       
   275                 return f
       
   276         raise FieldDoesNotExist, '%s has no field named %r' % (self.object_name, name)
       
   277 
       
   278     def get_field_by_name(self, name):
       
   279         """
       
   280         Returns the (field_object, model, direct, m2m), where field_object is
       
   281         the Field instance for the given name, model is the model containing
       
   282         this field (None for local fields), direct is True if the field exists
       
   283         on this model, and m2m is True for many-to-many relations. When
       
   284         'direct' is False, 'field_object' is the corresponding RelatedObject
       
   285         for this field (since the field doesn't have an instance associated
       
   286         with it).
       
   287 
       
   288         Uses a cache internally, so after the first access, this is very fast.
       
   289         """
       
   290         try:
       
   291             try:
       
   292                 return self._name_map[name]
       
   293             except AttributeError:
       
   294                 cache = self.init_name_map()
       
   295                 return cache[name]
       
   296         except KeyError:
       
   297             raise FieldDoesNotExist('%s has no field named %r'
       
   298                     % (self.object_name, name))
       
   299 
       
   300     def get_all_field_names(self):
       
   301         """
       
   302         Returns a list of all field names that are possible for this model
       
   303         (including reverse relation names). This is used for pretty printing
       
   304         debugging output (a list of choices), so any internal-only field names
       
   305         are not included.
       
   306         """
       
   307         try:
       
   308             cache = self._name_map
       
   309         except AttributeError:
       
   310             cache = self.init_name_map()
       
   311         names = cache.keys()
       
   312         names.sort()
       
   313         # Internal-only names end with "+" (symmetrical m2m related names being
       
   314         # the main example). Trim them.
       
   315         return [val for val in names if not val.endswith('+')]
       
   316 
       
   317     def init_name_map(self):
       
   318         """
       
   319         Initialises the field name -> field object mapping.
       
   320         """
       
   321         cache = {}
       
   322         # We intentionally handle related m2m objects first so that symmetrical
       
   323         # m2m accessor names can be overridden, if necessary.
       
   324         for f, model in self.get_all_related_m2m_objects_with_model():
       
   325             cache[f.field.related_query_name()] = (f, model, False, True)
       
   326         for f, model in self.get_all_related_objects_with_model():
       
   327             cache[f.field.related_query_name()] = (f, model, False, False)
       
   328         for f, model in self.get_m2m_with_model():
       
   329             cache[f.name] = (f, model, True, True)
       
   330         for f, model in self.get_fields_with_model():
       
   331             cache[f.name] = (f, model, True, False)
       
   332         if self.order_with_respect_to:
       
   333             cache['_order'] = OrderWrt(), None, True, False
       
   334         if app_cache_ready():
       
   335             self._name_map = cache
       
   336         return cache
       
   337 
       
   338     def get_add_permission(self):
       
   339         return 'add_%s' % self.object_name.lower()
       
   340 
       
   341     def get_change_permission(self):
       
   342         return 'change_%s' % self.object_name.lower()
       
   343 
       
   344     def get_delete_permission(self):
       
   345         return 'delete_%s' % self.object_name.lower()
       
   346 
       
   347     def get_all_related_objects(self, local_only=False):
       
   348         try:
       
   349             self._related_objects_cache
       
   350         except AttributeError:
       
   351             self._fill_related_objects_cache()
       
   352         if local_only:
       
   353             return [k for k, v in self._related_objects_cache.items() if not v]
       
   354         return self._related_objects_cache.keys()
       
   355 
       
   356     def get_all_related_objects_with_model(self):
       
   357         """
       
   358         Returns a list of (related-object, model) pairs. Similar to
       
   359         get_fields_with_model().
       
   360         """
       
   361         try:
       
   362             self._related_objects_cache
       
   363         except AttributeError:
       
   364             self._fill_related_objects_cache()
       
   365         return self._related_objects_cache.items()
       
   366 
       
   367     def _fill_related_objects_cache(self):
       
   368         cache = SortedDict()
       
   369         parent_list = self.get_parent_list()
       
   370         for parent in self.parents:
       
   371             for obj, model in parent._meta.get_all_related_objects_with_model():
       
   372                 if (obj.field.creation_counter < 0 or obj.field.rel.parent_link) and obj.model not in parent_list:
       
   373                     continue
       
   374                 if not model:
       
   375                     cache[obj] = parent
       
   376                 else:
       
   377                     cache[obj] = model
       
   378         for klass in get_models():
       
   379             for f in klass._meta.local_fields:
       
   380                 if f.rel and not isinstance(f.rel.to, str) and self == f.rel.to._meta:
       
   381                     cache[RelatedObject(f.rel.to, klass, f)] = None
       
   382         self._related_objects_cache = cache
       
   383 
       
   384     def get_all_related_many_to_many_objects(self, local_only=False):
       
   385         try:
       
   386             cache = self._related_many_to_many_cache
       
   387         except AttributeError:
       
   388             cache = self._fill_related_many_to_many_cache()
       
   389         if local_only:
       
   390             return [k for k, v in cache.items() if not v]
       
   391         return cache.keys()
       
   392 
       
   393     def get_all_related_m2m_objects_with_model(self):
       
   394         """
       
   395         Returns a list of (related-m2m-object, model) pairs. Similar to
       
   396         get_fields_with_model().
       
   397         """
       
   398         try:
       
   399             cache = self._related_many_to_many_cache
       
   400         except AttributeError:
       
   401             cache = self._fill_related_many_to_many_cache()
       
   402         return cache.items()
       
   403 
       
   404     def _fill_related_many_to_many_cache(self):
       
   405         cache = SortedDict()
       
   406         parent_list = self.get_parent_list()
       
   407         for parent in self.parents:
       
   408             for obj, model in parent._meta.get_all_related_m2m_objects_with_model():
       
   409                 if obj.field.creation_counter < 0 and obj.model not in parent_list:
       
   410                     continue
       
   411                 if not model:
       
   412                     cache[obj] = parent
       
   413                 else:
       
   414                     cache[obj] = model
       
   415         for klass in get_models():
       
   416             for f in klass._meta.local_many_to_many:
       
   417                 if f.rel and not isinstance(f.rel.to, str) and self == f.rel.to._meta:
       
   418                     cache[RelatedObject(f.rel.to, klass, f)] = None
       
   419         if app_cache_ready():
       
   420             self._related_many_to_many_cache = cache
       
   421         return cache
       
   422 
       
   423     def get_base_chain(self, model):
       
   424         """
       
   425         Returns a list of parent classes leading to 'model' (order from closet
       
   426         to most distant ancestor). This has to handle the case were 'model' is
       
   427         a granparent or even more distant relation.
       
   428         """
       
   429         if not self.parents:
       
   430             return
       
   431         if model in self.parents:
       
   432             return [model]
       
   433         for parent in self.parents:
       
   434             res = parent._meta.get_base_chain(model)
       
   435             if res:
       
   436                 res.insert(0, parent)
       
   437                 return res
       
   438         raise TypeError('%r is not an ancestor of this model'
       
   439                 % model._meta.module_name)
       
   440 
       
   441     def get_parent_list(self):
       
   442         """
       
   443         Returns a list of all the ancestor of this model as a list. Useful for
       
   444         determining if something is an ancestor, regardless of lineage.
       
   445         """
       
   446         result = set()
       
   447         for parent in self.parents:
       
   448             result.add(parent)
       
   449             result.update(parent._meta.get_parent_list())
       
   450         return result
       
   451 
       
   452     def get_ancestor_link(self, ancestor):
       
   453         """
       
   454         Returns the field on the current model which points to the given
       
   455         "ancestor". This is possible an indirect link (a pointer to a parent
       
   456         model, which points, eventually, to the ancestor). Used when
       
   457         constructing table joins for model inheritance.
       
   458 
       
   459         Returns None if the model isn't an ancestor of this one.
       
   460         """
       
   461         if ancestor in self.parents:
       
   462             return self.parents[ancestor]
       
   463         for parent in self.parents:
       
   464             # Tries to get a link field from the immediate parent
       
   465             parent_link = parent._meta.get_ancestor_link(ancestor)
       
   466             if parent_link:
       
   467                 # In case of a proxied model, the first link
       
   468                 # of the chain to the ancestor is that parent
       
   469                 # links
       
   470                 return self.parents[parent] or parent_link
       
   471 
       
   472     def get_ordered_objects(self):
       
   473         "Returns a list of Options objects that are ordered with respect to this object."
       
   474         if not hasattr(self, '_ordered_objects'):
       
   475             objects = []
       
   476             # TODO
       
   477             #for klass in get_models(get_app(self.app_label)):
       
   478             #    opts = klass._meta
       
   479             #    if opts.order_with_respect_to and opts.order_with_respect_to.rel \
       
   480             #        and self == opts.order_with_respect_to.rel.to._meta:
       
   481             #        objects.append(opts)
       
   482             self._ordered_objects = objects
       
   483         return self._ordered_objects
       
   484 
       
   485     def pk_index(self):
       
   486         """
       
   487         Returns the index of the primary key field in the self.fields list.
       
   488         """
       
   489         return self.fields.index(self.pk)
       
   490