diff --git a/django/contrib/admin/templatetags/breadcrumbs.py b/django/contrib/admin/templatetags/breadcrumbs.py index ab4eaa083d..bca5e04e19 100644 --- a/django/contrib/admin/templatetags/breadcrumbs.py +++ b/django/contrib/admin/templatetags/breadcrumbs.py @@ -4,13 +4,13 @@ register = Library() def path_breadcrumbs(path, overrides="", front=0, back=0): overs = overrides.split('/') - comps = [""] * int(front) + path.split('/')[:-1] + comps = [""] * int(front) + path.split('/')[:-1] backs = int(back) + len(comps) - overs.extend( [None for x in range(len(overs) -1 ,len(comps)) ] ) + overs.extend([None for x in range(len(overs) -1, len(comps))]) text = [] - for comp, ov in zip(comps,overs): + for comp, ov in zip(comps, overs): label = ov or comp - text.append("%s›\n" % ( "../" * backs , label ) ) + text.append("%s›\n" % ("../" * backs, label)) backs -= 1 return "".join(text) -path_breadcrumbs = register.simple_tag(path_breadcrumbs) \ No newline at end of file +path_breadcrumbs = register.simple_tag(path_breadcrumbs) diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py index 05d243712c..08d233507b 100644 --- a/django/contrib/admin/views/main.py +++ b/django/contrib/admin/views/main.py @@ -4,28 +4,25 @@ from django.contrib.admin.views.decorators import staff_member_required from django.contrib.admin.filterspecs import FilterSpec from django.core import formfields, template from django.core.template import loader +from django.db import models from django.db.models.fields import BoundField, BoundFieldLine, BoundFieldSet +from django.db.models.query import handle_legacy_orderlist from django.core.exceptions import Http404, ImproperlyConfigured, ObjectDoesNotExist, PermissionDenied from django.core.extensions import DjangoContext as Context from django.core.extensions import get_object_or_404, render_to_response from django.core.paginator import ObjectPaginator, InvalidPage -from django.conf.settings import ADMIN_MEDIA_PREFIX try: from django.contrib.admin.models import LogEntry, ADDITION, CHANGE, DELETION except ImportError: raise ImproperlyConfigured, "You don't have 'django.contrib.admin' in INSTALLED_APPS." -from django.db import models -from django.utils.html import strip_tags -from django.utils.httpwrappers import HttpResponse, HttpResponseRedirect -from django.utils.text import capfirst, get_text_list from django.utils import dateformat from django.utils.dates import MONTHS -from django.utils.html import escape +from django.utils.html import escape, strip_tags +from django.utils.httpwrappers import HttpResponse, HttpResponseRedirect +from django.utils.text import capfirst, get_text_list import operator from itertools import izip -from django.db.models.query import handle_legacy_orderlist - # The system will display a "Show all" link only if the total result count # is less than or equal to this setting. MAX_SHOW_ALL_ALLOWED = 200 @@ -59,7 +56,7 @@ def matches_app(mod, comps): modcomps = mod.__name__.split('.')[:-1] #HACK: leave off 'models' for c, mc in izip(comps, modcomps): if c != mc: - return ([],False) + return ([], False) return (comps[len(modcomps):], True) def find_model(mod, remaining): @@ -92,13 +89,13 @@ def get_app_label(mod): def get_model_and_app(path): comps = path.split('/') comps = comps[:-1] # remove '' after final / - for mod in models.get_installed_models(): + for mod in models.get_installed_models(): remaining, matched = matches_app(mod, comps) if matched and len(remaining) > 0: - # print "matched ", mod + # print "matched ", mod # print "left", remaining return ( find_model(mod, remaining), get_app_label(mod) ) - + raise Http404 # Couldn't find app _model_urls = {} @@ -108,7 +105,7 @@ def url_for_model(model): return _model_urls[model] except KeyError: comps = model.__module__.split('.') - for mod in models.get_installed_models(): + for mod in models.get_installed_models(): remaining, matched = matches_app(mod, comps) if matched and len(remaining) > 0: comps = comps[: - len(remaining)] + remaining[1:] @@ -166,7 +163,7 @@ class ChangeList(object): self.model, self.app_label = get_model_and_app(path) # _get_mod_opts(app_label, module_name) self.opts = self.model._meta - + if not request.user.has_perm(self.app_label + '.' + self.opts.get_change_permission()): raise PermissionDenied @@ -312,7 +309,7 @@ def change_list(request, path): c = Context(request, { 'title': cl.title, 'is_popup': cl.is_popup, - 'cl' : cl, + 'cl': cl, 'path': path[:path.rindex('/')] }) c.update({'has_add_permission': c['perms'][cl.app_label][cl.opts.get_add_permission()]}), @@ -323,7 +320,7 @@ change_list = staff_member_required(change_list) use_raw_id_admin = lambda field: isinstance(field.rel, (models.ManyToOne, models.ManyToMany)) and field.rel.raw_id_admin -def get_javascript_imports(opts,auto_populated_fields, ordered_objects, field_sets): +def get_javascript_imports(opts, auto_populated_fields, ordered_objects, field_sets): # Put in any necessary JavaScript imports. js = ['js/core.js', 'js/admin/RelatedObjectLookups.js'] if auto_populated_fields: @@ -476,14 +473,14 @@ def render_change_form(model, manipulator, app_label, context, add=False, change "admin/%s/change_form" % app_label , "admin/change_form"], context_instance=context) -def log_add_message(user, opts,manipulator,new_object): +def log_add_message(user, opts, manipulator, new_object): pk_value = getattr(new_object, opts.pk.attname) LogEntry.objects.log_action(user.id, opts.get_content_type_id(), pk_value, str(new_object), ADDITION) def add_stage(request, path, show_delete=False, form_url='', post_url='../change/', post_url_continue='../%s/', object_id_override=None): model, app_label = get_model_and_app(path) opts = model._meta - + if not request.user.has_perm(app_label + '.' + opts.get_add_permission()): raise PermissionDenied manipulator = model.AddManipulator() @@ -496,9 +493,9 @@ def add_stage(request, path, show_delete=False, form_url='', post_url='../change if not errors and not request.POST.has_key("_preview"): new_object = manipulator.save(new_data) - log_add_message(request.user, opts,manipulator,new_object) - msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name':opts.verbose_name, 'obj':new_object} - pk_value = getattr(new_object,opts.pk.attname) + log_add_message(request.user, opts, manipulator, new_object) + msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': opts.verbose_name, 'obj': new_object} + pk_value = getattr(new_object, opts.pk.attname) # Here, we distinguish between different save types by checking for # the presence of keys in request.POST. if request.POST.has_key("_continue"): @@ -531,16 +528,16 @@ def add_stage(request, path, show_delete=False, form_url='', post_url='../change 'form': form, 'is_popup': request.REQUEST.has_key('_popup'), 'show_delete': show_delete, - 'path' : path , + 'path': path , }) - + if object_id_override is not None: c['object_id'] = object_id_override return render_change_form(model, manipulator, app_label, c, add=True) add_stage = staff_member_required(add_stage) -def log_change_message(user, opts,manipulator,new_object): +def log_change_message(user, opts, manipulator, new_object): pk_value = getattr(new_object, opts.pk.column) # Construct the change message. change_message = [] @@ -556,7 +553,6 @@ def log_change_message(user, opts,manipulator,new_object): LogEntry.objects.log_action(user.id, opts.get_content_type_id(), pk_value, str(new_object), CHANGE, change_message) def change_stage(request, path, object_id): - model, app_label = get_model_and_app(path) opts = model._meta #mod, opts = _get_mod_opts(app_label, module_name) @@ -580,9 +576,9 @@ def change_stage(request, path, object_id): manipulator.do_html2python(new_data) if not errors and not request.POST.has_key("_preview"): new_object = manipulator.save(new_data) - log_change_message(request.user,opts,manipulator,new_object) - msg = _('The %(name)s "%(obj)s" was changed successfully.') % {'name': opts.verbose_name, 'obj':new_object} - pk_value = getattr(new_object,opts.pk.attname) + log_change_message(request.user, opts, manipulator, new_object) + msg = _('The %(name)s "%(obj)s" was changed successfully.') % {'name': opts.verbose_name, 'obj': new_object} + pk_value = getattr(new_object, opts.pk.attname) if request.POST.has_key("_continue"): request.user.add_message(msg + ' ' + _("You may edit it again below.")) if request.REQUEST.has_key('_popup'): @@ -632,11 +628,10 @@ def change_stage(request, path, object_id): 'form': form, 'object_id': object_id, 'original': manipulator.original_object, - 'is_popup' : request.REQUEST.has_key('_popup'), - 'path' : path , + 'is_popup': request.REQUEST.has_key('_popup'), + 'path': path , }) - - return render_change_form(model,manipulator, app_label, c, change=True) + return render_change_form(model, manipulator, app_label, c, change=True) def _nest_help(obj, depth, val): current = obj diff --git a/django/db/models/base.py b/django/db/models/base.py index ddb515cfe2..11a33e2188 100644 --- a/django/db/models/base.py +++ b/django/db/models/base.py @@ -1,18 +1,15 @@ import django.db.models.manipulators import django.db.models.manager - -from django.db.models.fields import AutoField +from django.db.models.fields import AutoField from django.db.models.fields.related import OneToOne, ManyToOne from django.db.models.related import RelatedObject from django.db.models.query import orderlist2sql from django.db.models.options import Options from django.db import connection, backend from django.db.models import signals - from django.dispatch import dispatcher from django.core.exceptions import ObjectDoesNotExist from django.utils.functional import curry - import re import types import sys @@ -27,7 +24,6 @@ get_module_name = lambda class_name: class_name.lower() + 's' # Calculate the verbose_name by converting from InitialCaps to "lowercase with spaces". get_verbose_name = lambda class_name: re.sub('([A-Z])', ' \\1', class_name).lower().strip() - class ModelBase(type): "Metaclass for all models" def __new__(cls, name, bases, attrs): @@ -42,13 +38,13 @@ class ModelBase(type): except KeyError: meta_attrs = {} - # Create the class, we need to add the options to it. - new_class = type.__new__(cls, name, bases, { '__module__' : attrs.pop('__module__') }) + # Create the class. + new_class = type.__new__(cls, name, bases, {'__module__': attrs.pop('__module__')}) opts = Options( module_name = meta_attrs.pop('module_name', get_module_name(name)), # If the verbose_name wasn't given, use the class name, - # converted from InitialCaps to "lowercase with spaces". + # converted from "InitialCaps" to "lowercase with spaces". verbose_name = meta_attrs.pop('verbose_name', get_verbose_name(name)), verbose_name_plural = meta_attrs.pop('verbose_name_plural', ''), db_table = meta_attrs.pop('db_table', ''), @@ -81,12 +77,10 @@ class ModelBase(type): # Cache the app label. opts.app_label = app_label - #Add all attributes to the class + # Add all attributes to the class. for obj_name, obj in attrs.items(): new_class.add_to_class(obj_name, obj) - - # Give the class a docstring -- its definition. if new_class.__doc__ is None: new_class.__doc__ = "%s.%s(%s)" % (opts.module_name, name, ", ".join([f.name for f in opts.fields])) @@ -97,12 +91,9 @@ class ModelBase(type): opts._prepare() new_class._prepare() - - # Populate the _MODELS member on the module the class is in. app_package.__dict__.setdefault('_MODELS', []).append(new_class) - return new_class def cmp_cls(x, y): @@ -117,13 +108,6 @@ def cmp_cls(x, y): class Model(object): __metaclass__ = ModelBase - def add_to_class(cls, name, attribute): - if hasattr(attribute, 'contribute_to_class'): - attribute.contribute_to_class(cls, name) - else: - setattr(cls, name, attribute) - add_to_class = classmethod(add_to_class) - def __repr__(self): return '<%s object>' % self.__class__.__name__ @@ -134,7 +118,7 @@ class Model(object): return not self.__eq__(other) def __init__(self, *args, **kwargs): - dispatcher.send( signal = signals.pre_init, sender = self.__class__, args=args, kwargs=kwargs) + dispatcher.send(signal=signals.pre_init, sender=self.__class__, args=args, kwargs=kwargs) if kwargs: for f in self._meta.fields: if isinstance(f.rel, ManyToOne): @@ -165,7 +149,14 @@ class Model(object): raise TypeError, "'%s' is an invalid keyword argument for this function" % kwargs.keys()[0] for i, arg in enumerate(args): setattr(self, self._meta.fields[i].attname, arg) - dispatcher.send( signal = signals.post_init, sender = self.__class__, instance=self) + dispatcher.send(signal=signals.post_init, sender=self.__class__, instance=self) + + def add_to_class(cls, name, attribute): + if hasattr(attribute, 'contribute_to_class'): + attribute.contribute_to_class(cls, name) + else: + setattr(cls, name, attribute) + add_to_class = classmethod(add_to_class) def _prepare(cls): # Creates some methods once self._meta has been populated. @@ -173,7 +164,7 @@ class Model(object): cls.get_next_in_order = curry(cls._get_next_or_previous_in_order, is_next=True) cls.get_previous_in_order = curry(cls._get_next_or_previous_in_order, is_next=False) - dispatcher.send( signal = signals.class_prepared, sender = cls) + dispatcher.send(signal=signals.class_prepared, sender=cls) #RelatedField.do_pending_lookups(cls) _prepare = classmethod(_prepare) @@ -182,7 +173,7 @@ class Model(object): # Run any pre-save hooks. if hasattr(self, '_pre_save'): self._pre_save() - dispatcher.send( signal=signals.pre_save, sender = self.__class__, instance = self ) + dispatcher.send(signal=signals.pre_save, sender=self.__class__, instance=self) non_pks = [f for f in self._meta.fields if not f.primary_key] cursor = connection.cursor() @@ -261,8 +252,7 @@ class Model(object): def delete(self, ignore_objects=None): assert getattr(self, self._meta.pk.attname) is not None, "%r can't be deleted because it doesn't have an ID." - ignore_objects = \ - ignore_objects and dict([ (o.__class,o.__get_pk_val) for o in ignore_objects ]) or {} + ignore_objects = ignore_objects and dict([(o.__class,o.__get_pk_val) for o in ignore_objects]) or {} seen_objs = {} self.__collect_sub_objects(seen_objs, ignore_objects) @@ -282,7 +272,7 @@ class Model(object): if hasattr(instance, '_pre_delete'): instance._pre_delete() - dispatcher.send(signal=signals.pre_delete, sender = cls, instance = instance ) + dispatcher.send(signal=signals.pre_delete, sender=cls, instance=instance) for related in cls._meta.get_all_related_many_to_many_objects(): cursor.execute("DELETE FROM %s WHERE %s=%%s" % \ @@ -294,14 +284,11 @@ class Model(object): (backend.quote_name(f.get_m2m_db_table(cls._meta)), backend.quote_name(cls._meta.object_name.lower() + '_id')), [pk_val]) - for field in cls._meta.fields: if field.rel and field.null and field.rel.to in seen_cls: - cursor.execute("UPDATE %s SET %s = NULL WHERE %s =%%s" % \ - ( backend.quote_name(cls._meta.db_table), - backend.quote_name(field.column), - backend.quote_name(cls._meta.pk.column)), - [pk_val] ) + cursor.execute("UPDATE %s SET %s = NULL WHERE %s=%%s" % \ + (backend.quote_name(cls._meta.db_table), backend.quote_name(field.column), + backend.quote_name(cls._meta.pk.column)), [pk_val]) seen_tups.reverse() @@ -312,7 +299,7 @@ class Model(object): setattr(self, cls._meta.pk.attname, None) - dispatcher.send(signal=signals.post_delete, sender = cls, instance = instance ) + dispatcher.send(signal=signals.post_delete, sender=cls, instance=instance) if hasattr(instance, '_post_delete'): instance._post_delete() @@ -321,7 +308,6 @@ class Model(object): delete.alters_data = True - def _get_FIELD_display(self, field): value = getattr(self, field.attname) return dict(field.choices).get(value, value) @@ -504,7 +490,6 @@ class Model(object): _add_related.alters_data = True - # Handles related many-to-many object retrieval. # Examples: Album.get_song(), Album.get_song_list(), Album.get_song_count() def _get_related_many_to_many(self, method_name, rel_class, rel_field, **kwargs): @@ -529,10 +514,6 @@ class Model(object): cursor.executemany(sql, [(this_id, i) for i in id_list]) connection.commit() - - - - ############################################ # HELPER FUNCTIONS (CURRIED MODEL METHODS) # ############################################ @@ -568,5 +549,3 @@ def method_get_order(ordered_obj, self): def get_absolute_url(opts, func, self): return settings.ABSOLUTE_URL_OVERRIDES.get('%s.%s' % (opts.app_label, opts.module_name), func)(self) - - diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index fe7a16639b..b0fb245830 100644 --- a/django/db/models/fields/__init__.py +++ b/django/db/models/fields/__init__.py @@ -8,7 +8,6 @@ from django.utils.text import capfirst from django.utils.translation import gettext_lazy, ngettext import datetime, os - # Random entropy string used by "default" param. NOT_PROVIDED = 'oijpwojefiojpanv' @@ -35,9 +34,7 @@ def manipulator_valid_rel_key(f, self, field_data, all_data): def manipulator_validator_unique(f, opts, self, field_data, all_data): "Validates that the value is unique for this field." - lookup_type = f.get_validator_unique_lookup_type() - try: old_obj = self.__class__._default_manager.get_object(**{lookup_type: field_data}) except ObjectDoesNotExist: @@ -97,7 +94,6 @@ class Field(object): help_text='', db_column=None): self.name = name self.verbose_name = verbose_name - self.primary_key = primary_key self.maxlength, self.unique = maxlength, unique self.blank, self.null = blank, null @@ -118,9 +114,8 @@ class Field(object): self.creation_counter = Field.creation_counter Field.creation_counter += 1 - def __cmp__(self,other ): - #This is because bisect does not take a comparison function. grrr. + # This is needed because bisect does not take a comparison function. return cmp(self.creation_counter, other.creation_counter) def set_attributes_from_name(self, name): @@ -292,7 +287,6 @@ class Field(object): first_choice = include_blank and blank_choice or [] if self.choices: return first_choice + list(self.choices) - rel_model = self.rel.to return first_choice + [(getattr(x, rel_model._meta.pk.attname), str(x)) for x in rel_model._default_manager.get_list(**rel_model._meta.limit_choices_to)] @@ -365,7 +359,7 @@ class DateField(Field): empty_strings_allowed = False def __init__(self, verbose_name=None, name=None, auto_now=False, auto_now_add=False, **kwargs): self.auto_now, self.auto_now_add = auto_now, auto_now_add - #HACKs : auto_now_add/auto_now should be done as a default or a pre_save... + #HACKs : auto_now_add/auto_now should be done as a default or a pre_save. if auto_now or auto_now_add: kwargs['editable'] = False kwargs['blank'] = True diff --git a/django/db/models/options.py b/django/db/models/options.py index b891ca1be8..6781f0ebd0 100644 --- a/django/db/models/options.py +++ b/django/db/models/options.py @@ -15,7 +15,6 @@ class Options: order_with_respect_to=None, module_constants=None): # Move many-to-many related fields from self.fields into self.many_to_many. self.fields, self.many_to_many = [], [] - self.module_name, self.verbose_name = module_name, verbose_name self.verbose_name_plural = verbose_name_plural or verbose_name + 's' self.db_table = db_table @@ -27,10 +26,9 @@ class Options: self.object_name, self.app_label = object_name, app_label self.get_latest_by = get_latest_by self.order_with_respect_to = order_with_respect_to - self.module_constants = module_constants or {} self.admin = admin - + def contribute_to_class(self, cls, name): self.model = cls cls._meta = self @@ -41,7 +39,7 @@ class Options: self.ordering = ('_order',) else: self.order_with_respect_to = None - + # Calculate one_to_one_field. self.one_to_one_field = None for f in self.fields: @@ -71,20 +69,18 @@ class Options: self.has_auto_field = True #HACK self.limit_choices_to = {} - + # If the db_table wasn't provided, use the app_label + module_name. if not self.db_table: self.db_table = "%s_%s" % (self.app_label, self.module_name) def add_field(self, field): - # Insert the fields in the order that they were created. The - # "creation_counter" is needed because metaclasses don't preserve the - # attribute order. + # Insert the given field in the order in which it was created, using + # the "creation_counter" attribute of the field. if field.rel and isinstance(field.rel, ManyToMany): self.many_to_many.insert(bisect(self.many_to_many, field), field) else: - self.fields.insert(bisect(self.fields,field),field) - + self.fields.insert(bisect(self.fields, field), field) def __repr__(self): return '' % self.module_name @@ -95,11 +91,10 @@ class Options: def get_content_type_id(self): "Returns the content-type ID for this object type." if not hasattr(self, '_content_type_id'): - import django.models.core - manager = django.models.core.ContentType.objects - self._content_type_id = \ - manager.get_object(python_module_name__exact=self.module_name, - package__label__exact=self.app_label).id + from django.models.core import ContentType + self._content_type_id = ContentType.objects.get_object( + python_module_name__exact=self.module_name, + package__label__exact=self.app_label).id return self._content_type_id def get_field(self, name, many_to_many=True): @@ -209,4 +204,4 @@ class Options: self._field_types[field_type] = True else: self._field_types[field_type] = False - return self._field_types[field_type] \ No newline at end of file + return self._field_types[field_type]