Ticket #7847: unused.imports.diff

File unused.imports.diff, 124.8 KB (added by Julien Phalip, 16 years ago)
  • django/django/db/models/sql/query.py

     
    77all about the internals of models in order to get the information it needs.
    88"""
    99
    10 import datetime
    1110from copy import deepcopy
    1211
    1312from django.utils.tree import Node
  • django/django/db/models/base.py

     
    1212import django.db.models.manager         # Ditto.
    1313from django.core import validators
    1414from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned, FieldError
    15 from django.db.models.fields import AutoField, ImageField, FieldDoesNotExist
     15from django.db.models.fields import AutoField, ImageField
    1616from django.db.models.fields.related import OneToOneRel, ManyToOneRel, OneToOneField
    1717from django.db.models.query import delete_objects, Q, CollectedObjects
    1818from django.db.models.options import Options
     
    2020from django.db.models import signals
    2121from django.db.models.loading import register_models, get_model
    2222from django.dispatch import dispatcher
    23 from django.utils.datastructures import SortedDict
    2423from django.utils.functional import curry
    2524from django.utils.encoding import smart_str, force_unicode, smart_unicode
    2625from django.core.files.move import file_move_safe
  • django/django/db/models/fields/related.py

     
    33from django.db.models.fields import AutoField, Field, IntegerField, PositiveIntegerField, PositiveSmallIntegerField, FieldDoesNotExist
    44from django.db.models.related import RelatedObject
    55from django.db.models.query_utils import QueryWrapper
    6 from django.utils.text import capfirst
    76from django.utils.translation import ugettext_lazy, string_concat, ungettext, ugettext as _
    87from django.utils.functional import curry
    9 from django.utils.encoding import smart_unicode
    108from django.core import validators
    119from django import oldforms
    1210from django import forms
  • django/django/db/models/__init__.py

     
    1010from django.db.models.fields.subclassing import SubfieldBase
    1111from django.db.models.fields.related import ForeignKey, OneToOneField, ManyToManyField, ManyToOneRel, ManyToManyRel, OneToOneRel, TABULAR, STACKED
    1212from django.db.models import signals
    13 from django.utils.functional import curry
    14 from django.utils.text import capfirst
    1513
    1614# Admin stages.
    1715ADD, CHANGE, BOTH = 1, 2, 3
  • django/django/db/backends/oracle/base.py

     
    88
    99from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, BaseDatabaseOperations, util
    1010from django.db.backends.oracle import query
    11 from django.utils.datastructures import SortedDict
    1211from django.utils.encoding import smart_str, force_unicode
    1312
    1413# Oracle takes client-side character set encoding from the environment.
  • django/django/forms/util.py

     
    11from django.utils.html import escape
    22from django.utils.encoding import smart_unicode, StrAndUnicode, force_unicode
    3 from django.utils.functional import Promise
    43from django.utils.safestring import mark_safe
    54
    65def flatatt(attrs):
  • django/django/forms/formsets.py

     
    22from django.utils.encoding import StrAndUnicode
    33from django.utils.safestring import mark_safe
    44from fields import IntegerField, BooleanField
    5 from widgets import Media, HiddenInput, TextInput
     5from widgets import Media, HiddenInput
    66from util import ErrorList, ValidationError
    77
    88__all__ = ('BaseFormSet', 'all_valid')
  • django/django/forms/models.py

     
    88from django.utils.translation import ugettext_lazy as _
    99from django.utils.encoding import smart_unicode
    1010from django.utils.datastructures import SortedDict
    11 from django.core.exceptions import ImproperlyConfigured
    1211
    1312from util import ValidationError, ErrorList
    1413from forms import BaseForm, get_declared_fields
  • django/django/forms/fields.py

     
    2323    from sets import Set as set
    2424
    2525from django.utils.translation import ugettext_lazy as _
    26 from django.utils.encoding import StrAndUnicode, smart_unicode, smart_str
     26from django.utils.encoding import smart_unicode, smart_str
    2727
    2828from util import ErrorList, ValidationError
    2929from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, DateTimeInput
  • django/django/core/files/uploadhandler.py

     
    11"""
    22Base file upload handler classes, and the built-in concrete subclasses
    33"""
    4 import os
    5 import tempfile
    64try:
    75    from cStringIO import StringIO
    86except ImportError:
  • django/django/core/management/commands/compilemessages.py

     
    22import sys
    33from optparse import make_option
    44from django.core.management.base import BaseCommand
    5 from django.core.management.color import no_style
    65
    76try:
    87    set
  • django/django/core/management/commands/testserver.py

     
    1717    requires_model_validation = False
    1818
    1919    def handle(self, *fixture_labels, **options):
    20         from django.conf import settings
    2120        from django.core.management import call_command
    2221        from django.test.utils import create_test_db
    2322
  • django/django/core/management/commands/test.py

     
    1717
    1818    def handle(self, *test_labels, **options):
    1919        from django.conf import settings
    20         from django.db.models import get_app, get_apps
    2120
    2221        verbosity = int(options.get('verbosity', 1))
    2322        interactive = options.get('interactive', True)
  • django/django/views/generic/simple.py

     
    1 from django.shortcuts import render_to_response
    21from django.template import loader, RequestContext
    32from django.http import HttpResponse, HttpResponsePermanentRedirect, HttpResponseGone
    43
  • django/django/dispatch/saferef.py

     
    11"""Refactored "safe reference" from dispatcher.py"""
    22import weakref, traceback
    3 from django.utils.functional import curry
    43
    54def safeRef(target, onDelete = None):
    65    """Return a *safe* weak reference to a callable target
  • django/django/dispatch/dispatcher.py

     
    2525        deletion, (considerably speeds up the cleanup process
    2626        vs. the original code.)
    2727"""
    28 import types, weakref
     28import weakref
    2929from django.dispatch import saferef, robustapply, errors
    3030
    3131__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
  • django/django/contrib/formtools/tests.py

     
    11from django import forms
    22from django.contrib.formtools import preview
    33from django import http
    4 from django.conf import settings
    54from django.test import TestCase
    65
    76success_string = "Done was called!"
  • django/django/contrib/syndication/feeds.py

     
    11from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist
    2 from django.template import Context, loader, Template, TemplateDoesNotExist
     2from django.template import loader, Template, TemplateDoesNotExist
    33from django.contrib.sites.models import Site, RequestSite
    44from django.utils import feedgenerator
    55from django.utils.encoding import smart_unicode, iri_to_uri
  • django/django/contrib/admin/options.py

     
    1 from django import oldforms, template
    2 from django import forms
    3 from django.forms.formsets import all_valid
    4 from django.forms.models import modelform_factory, inlineformset_factory
    5 from django.forms.models import BaseInlineFormset
    6 from django.contrib.contenttypes.models import ContentType
    7 from django.contrib.admin import widgets
    8 from django.contrib.admin.util import quote, unquote, get_deleted_objects
    9 from django.core.exceptions import ImproperlyConfigured, PermissionDenied
    10 from django.db import models, transaction
    11 from django.http import Http404, HttpResponse, HttpResponseRedirect
    12 from django.shortcuts import get_object_or_404, render_to_response
    13 from django.utils.html import escape
    14 from django.utils.safestring import mark_safe
    15 from django.utils.text import capfirst, get_text_list
    16 from django.utils.translation import ugettext as _
    17 from django.utils.encoding import force_unicode
    18 import sets
    19 
    20 HORIZONTAL, VERTICAL = 1, 2
    21 # returns the <ul> class for a given radio_admin field
    22 get_ul_class = lambda x: 'radiolist%s' % ((x == HORIZONTAL) and ' inline' or '')
    23 
    24 class IncorrectLookupParameters(Exception):
    25     pass
    26 
    27 def flatten_fieldsets(fieldsets):
    28     """Returns a list of field names from an admin fieldsets structure."""
    29     field_names = []
    30     for name, opts in fieldsets:
    31         for field in opts['fields']:
    32             # type checking feels dirty, but it seems like the best way here
    33             if type(field) == tuple:
    34                 field_names.extend(field)
    35             else:
    36                 field_names.append(field)
    37     return field_names
    38 
    39 class AdminForm(object):
    40     def __init__(self, form, fieldsets, prepopulated_fields):
    41         self.form, self.fieldsets = form, fieldsets
    42         self.prepopulated_fields = [{
    43             'field': form[field_name],
    44             'dependencies': [form[f] for f in dependencies]
    45         } for field_name, dependencies in prepopulated_fields.items()]
    46 
    47     def __iter__(self):
    48         for name, options in self.fieldsets:
    49             yield Fieldset(self.form, name, **options)
    50 
    51     def first_field(self):
    52         for bf in self.form:
    53             return bf
    54 
    55     def _media(self):
    56         media = self.form.media
    57         for fs in self:
    58             media = media + fs.media
    59         return media
    60     media = property(_media)
    61 
    62 class Fieldset(object):
    63     def __init__(self, form, name=None, fields=(), classes=(), description=None):
    64         self.form = form
    65         self.name, self.fields = name, fields
    66         self.classes = u' '.join(classes)
    67         self.description = description
    68 
    69     def _media(self):
    70         from django.conf import settings
    71         if 'collapse' in self.classes:
    72             return forms.Media(js=['%sjs/admin/CollapsedFieldsets.js' % settings.ADMIN_MEDIA_PREFIX])
    73         return forms.Media()
    74     media = property(_media)
    75 
    76     def __iter__(self):
    77         for field in self.fields:
    78             yield Fieldline(self.form, field)
    79 
    80 class Fieldline(object):
    81     def __init__(self, form, field):
    82         self.form = form # A django.forms.Form instance
    83         if isinstance(field, basestring):
    84             self.fields = [field]
    85         else:
    86             self.fields = field
    87 
    88     def __iter__(self):
    89         for i, field in enumerate(self.fields):
    90             yield AdminField(self.form, field, is_first=(i == 0))
    91 
    92     def errors(self):
    93         return mark_safe(u'\n'.join([self.form[f].errors.as_ul() for f in self.fields]))
    94 
    95 class AdminField(object):
    96     def __init__(self, form, field, is_first):
    97         self.field = form[field] # A django.forms.BoundField instance
    98         self.is_first = is_first # Whether this field is first on the line
    99         self.is_checkbox = isinstance(self.field.field.widget, forms.CheckboxInput)
    100 
    101     def label_tag(self):
    102         classes = []
    103         if self.is_checkbox:
    104             classes.append(u'vCheckboxLabel')
    105             contents = escape(self.field.label)
    106         else:
    107             contents = force_unicode(escape(self.field.label)) + u':'
    108         if self.field.field.required:
    109             classes.append(u'required')
    110         if not self.is_first:
    111             classes.append(u'inline')
    112         attrs = classes and {'class': u' '.join(classes)} or {}
    113         return self.field.label_tag(contents=contents, attrs=attrs)
    114 
    115 class BaseModelAdmin(object):
    116     """Functionality common to both ModelAdmin and InlineAdmin."""
    117     raw_id_fields = ()
    118     fields = None
    119     fieldsets = None
    120     form = forms.ModelForm
    121     filter_vertical = ()
    122     filter_horizontal = ()
    123     radio_fields = {}
    124     prepopulated_fields = {}
    125 
    126     def formfield_for_dbfield(self, db_field, **kwargs):
    127         """
    128         Hook for specifying the form Field instance for a given database Field
    129         instance.
    130 
    131         If kwargs are given, they're passed to the form Field's constructor.
    132         """
    133         # For DateTimeFields, use a special field and widget.
    134         if isinstance(db_field, models.DateTimeField):
    135             kwargs['form_class'] = forms.SplitDateTimeField
    136             kwargs['widget'] = widgets.AdminSplitDateTime()
    137             return db_field.formfield(**kwargs)
    138 
    139         # For DateFields, add a custom CSS class.
    140         if isinstance(db_field, models.DateField):
    141             kwargs['widget'] = widgets.AdminDateWidget
    142             return db_field.formfield(**kwargs)
    143 
    144         # For TimeFields, add a custom CSS class.
    145         if isinstance(db_field, models.TimeField):
    146             kwargs['widget'] = widgets.AdminTimeWidget
    147             return db_field.formfield(**kwargs)
    148 
    149         # For FileFields and ImageFields add a link to the current file.
    150         if isinstance(db_field, models.ImageField) or isinstance(db_field, models.FileField):
    151             kwargs['widget'] = widgets.AdminFileWidget
    152             return db_field.formfield(**kwargs)
    153 
    154         # For ForeignKey or ManyToManyFields, use a special widget.
    155         if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)):
    156             if isinstance(db_field, models.ForeignKey) and db_field.name in self.raw_id_fields:
    157                 kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel)
    158             elif isinstance(db_field, models.ForeignKey) and db_field.name in self.radio_fields:
    159                 kwargs['widget'] = widgets.AdminRadioSelect(attrs={
    160                     'class': get_ul_class(self.radio_fields[db_field.name]),
    161                 })
    162                 kwargs['empty_label'] = db_field.blank and _('None') or None
    163             else:
    164                 if isinstance(db_field, models.ManyToManyField):
    165                     if db_field.name in self.raw_id_fields:
    166                         kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel)
    167                         kwargs['help_text'] = ''
    168                     elif db_field.name in (self.filter_vertical + self.filter_horizontal):
    169                         kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical))
    170             # Wrap the widget's render() method with a method that adds
    171             # extra HTML to the end of the rendered output.
    172             formfield = db_field.formfield(**kwargs)
    173             # Don't wrap raw_id fields. Their add function is in the popup window.
    174             if not db_field.name in self.raw_id_fields:
    175                 formfield.widget = widgets.RelatedFieldWidgetWrapper(formfield.widget, db_field.rel, self.admin_site)
    176             return formfield
    177        
    178         if db_field.choices and db_field.name in self.radio_fields:
    179             kwargs['widget'] = widgets.AdminRadioSelect(
    180                 choices=db_field.get_choices(include_blank=db_field.blank,
    181                     blank_choice=[('', _('None'))]),
    182                 attrs={
    183                     'class': get_ul_class(self.radio_fields[db_field.name]),
    184                 }
    185             )
    186 
    187         # For any other type of field, just call its formfield() method.
    188         return db_field.formfield(**kwargs)
    189 
    190     def _declared_fieldsets(self):
    191         if self.fieldsets:
    192             return self.fieldsets
    193         elif self.fields:
    194             return [(None, {'fields': self.fields})]
    195         return None
    196     declared_fieldsets = property(_declared_fieldsets)
    197 
    198 class ModelAdmin(BaseModelAdmin):
    199     "Encapsulates all admin options and functionality for a given model."
    200     __metaclass__ = forms.MediaDefiningClass
    201 
    202     list_display = ('__str__',)
    203     list_display_links = ()
    204     list_filter = ()
    205     list_select_related = False
    206     list_per_page = 100
    207     search_fields = ()
    208     date_hierarchy = None
    209     save_as = False
    210     save_on_top = False
    211     ordering = None
    212     inlines = []
    213    
    214     # Custom templates (designed to be over-ridden in subclasses)
    215     change_form_template = None
    216     change_list_template = None
    217     delete_confirmation_template = None
    218     object_history_template = None
    219 
    220     def __init__(self, model, admin_site):
    221         self.model = model
    222         self.opts = model._meta
    223         self.admin_site = admin_site
    224         self.inline_instances = []
    225         for inline_class in self.inlines:
    226             inline_instance = inline_class(self.model, self.admin_site)
    227             self.inline_instances.append(inline_instance)
    228         super(ModelAdmin, self).__init__()
    229 
    230     def __call__(self, request, url):
    231         # Check that LogEntry, ContentType and the auth context processor are installed.
    232         from django.conf import settings
    233         if settings.DEBUG:
    234             from django.contrib.admin.models import LogEntry
    235             if not LogEntry._meta.installed:
    236                 raise ImproperlyConfigured("Put 'django.contrib.admin' in your INSTALLED_APPS setting in order to use the admin application.")
    237             if not ContentType._meta.installed:
    238                 raise ImproperlyConfigured("Put 'django.contrib.contenttypes' in your INSTALLED_APPS setting in order to use the admin application.")
    239             if 'django.core.context_processors.auth' not in settings.TEMPLATE_CONTEXT_PROCESSORS:
    240                 raise ImproperlyConfigured("Put 'django.core.context_processors.auth' in your TEMPLATE_CONTEXT_PROCESSORS setting in order to use the admin application.")
    241 
    242         # Delegate to the appropriate method, based on the URL.
    243         if url is None:
    244             return self.changelist_view(request)
    245         elif url.endswith('add'):
    246             return self.add_view(request)
    247         elif url.endswith('history'):
    248             return self.history_view(request, unquote(url[:-8]))
    249         elif url.endswith('delete'):
    250             return self.delete_view(request, unquote(url[:-7]))
    251         else:
    252             return self.change_view(request, unquote(url))
    253 
    254     def _media(self):
    255         from django.conf import settings
    256 
    257         js = ['js/core.js', 'js/admin/RelatedObjectLookups.js']
    258         if self.prepopulated_fields:
    259             js.append('js/urlify.js')
    260         if self.opts.get_ordered_objects():
    261             js.extend(['js/getElementsBySelector.js', 'js/dom-drag.js' , 'js/admin/ordering.js'])
    262         if self.filter_vertical or self.filter_horizontal:
    263             js.extend(['js/SelectBox.js' , 'js/SelectFilter2.js'])
    264        
    265         return forms.Media(js=['%s%s' % (settings.ADMIN_MEDIA_PREFIX, url) for url in js])
    266     media = property(_media)
    267 
    268     def has_add_permission(self, request):
    269         "Returns True if the given request has permission to add an object."
    270         opts = self.opts
    271         return request.user.has_perm(opts.app_label + '.' + opts.get_add_permission())
    272 
    273     def has_change_permission(self, request, obj=None):
    274         """
    275         Returns True if the given request has permission to change the given
    276         Django model instance.
    277 
    278         If `obj` is None, this should return True if the given request has
    279         permission to change *any* object of the given type.
    280         """
    281         opts = self.opts
    282         return request.user.has_perm(opts.app_label + '.' + opts.get_change_permission())
    283 
    284     def has_delete_permission(self, request, obj=None):
    285         """
    286         Returns True if the given request has permission to change the given
    287         Django model instance.
    288 
    289         If `obj` is None, this should return True if the given request has
    290         permission to delete *any* object of the given type.
    291         """
    292         opts = self.opts
    293         return request.user.has_perm(opts.app_label + '.' + opts.get_delete_permission())
    294 
    295     def queryset(self, request):
    296         """
    297         Returns a QuerySet of all model instances that can be edited by the
    298         admin site. This is used by changelist_view.
    299         """
    300         qs = self.model._default_manager.get_query_set()
    301         # TODO: this should be handled by some parameter to the ChangeList.
    302         ordering = self.ordering or () # otherwise we might try to *None, which is bad ;)
    303         if ordering:
    304             qs = qs.order_by(*ordering)
    305         return qs
    306 
    307     def get_fieldsets(self, request, obj=None):
    308         "Hook for specifying fieldsets for the add form."
    309         if self.declared_fieldsets:
    310             return self.declared_fieldsets
    311         form = self.get_form(request)
    312         return [(None, {'fields': form.base_fields.keys()})]
    313 
    314     def get_form(self, request, obj=None):
    315         """
    316         Returns a Form class for use in the admin add view. This is used by
    317         add_view and change_view.
    318         """
    319         if self.declared_fieldsets:
    320             fields = flatten_fieldsets(self.declared_fieldsets)
    321         else:
    322             fields = None
    323         return modelform_factory(self.model, form=self.form, fields=fields, formfield_callback=self.formfield_for_dbfield)
    324 
    325     def get_formsets(self, request, obj=None):
    326         for inline in self.inline_instances:
    327             yield inline.get_formset(request, obj)
    328 
    329     def save_add(self, request, form, formsets, post_url_continue):
    330         """
    331         Saves the object in the "add" stage and returns an HttpResponseRedirect.
    332 
    333         `form` is a bound Form instance that's verified to be valid.
    334         """
    335         from django.contrib.admin.models import LogEntry, ADDITION
    336         opts = self.model._meta
    337         new_object = form.save(commit=True)
    338 
    339         if formsets:
    340             for formset in formsets:
    341                 # HACK: it seems like the parent obejct should be passed into
    342                 # a method of something, not just set as an attribute
    343                 formset.instance = new_object
    344                 formset.save()
    345 
    346         pk_value = new_object._get_pk_val()
    347         LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(self.model).id, pk_value, force_unicode(new_object), ADDITION)
    348         msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': opts.verbose_name, 'obj': new_object}
    349         # Here, we distinguish between different save types by checking for
    350         # the presence of keys in request.POST.
    351         if request.POST.has_key("_continue"):
    352             request.user.message_set.create(message=msg + ' ' + _("You may edit it again below."))
    353             if request.POST.has_key("_popup"):
    354                 post_url_continue += "?_popup=1"
    355             return HttpResponseRedirect(post_url_continue % pk_value)
    356 
    357         if request.POST.has_key("_popup"):
    358             return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, "%s", "%s");</script>' % \
    359                 # escape() calls force_unicode.
    360                 (escape(pk_value), escape(new_object)))
    361         elif request.POST.has_key("_addanother"):
    362             request.user.message_set.create(message=msg + ' ' + (_("You may add another %s below.") % opts.verbose_name))
    363             return HttpResponseRedirect(request.path)
    364         else:
    365             request.user.message_set.create(message=msg)
    366             # Figure out where to redirect. If the user has change permission,
    367             # redirect to the change-list page for this object. Otherwise,
    368             # redirect to the admin index.
    369             if self.has_change_permission(request, None):
    370                 post_url = '../'
    371             else:
    372                 post_url = '../../../'
    373             return HttpResponseRedirect(post_url)
    374     save_add = transaction.commit_on_success(save_add)
    375 
    376     def save_change(self, request, form, formsets=None):
    377         """
    378         Saves the object in the "change" stage and returns an HttpResponseRedirect.
    379 
    380         `form` is a bound Form instance that's verified to be valid.
    381        
    382         `formsets` is a sequence of InlineFormSet instances that are verified to be valid.
    383         """
    384         from django.contrib.admin.models import LogEntry, CHANGE
    385         opts = self.model._meta
    386         new_object = form.save(commit=True)
    387         pk_value = new_object._get_pk_val()
    388 
    389         if formsets:
    390             for formset in formsets:
    391                 formset.save()
    392 
    393         # Construct the change message.
    394         change_message = []
    395         if form.changed_data:
    396             change_message.append(_('Changed %s.') % get_text_list(form.changed_data, _('and')))
    397            
    398         if formsets:
    399             for formset in formsets:
    400                 for added_object in formset.new_objects:
    401                     change_message.append(_('Added %(name)s "%(object)s".')
    402                                           % {'name': added_object._meta.verbose_name,
    403                                              'object': added_object})
    404                 for changed_object, changed_fields in formset.changed_objects:
    405                     change_message.append(_('Changed %(list)s for %(name)s "%(object)s".')
    406                                           % {'list': get_text_list(changed_fields, _('and')),
    407                                              'name': changed_object._meta.verbose_name,
    408                                              'object': changed_object})
    409                 for deleted_object in formset.deleted_objects:
    410                     change_message.append(_('Deleted %(name)s "%(object)s".')
    411                                           % {'name': deleted_object._meta.verbose_name,
    412                                              'object': deleted_object})
    413         change_message = ' '.join(change_message)
    414         if not change_message:
    415             change_message = _('No fields changed.')
    416         LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(self.model).id, pk_value, force_unicode(new_object), CHANGE, change_message)
    417 
    418         msg = _('The %(name)s "%(obj)s" was changed successfully.') % {'name': opts.verbose_name, 'obj': new_object}
    419         if request.POST.has_key("_continue"):
    420             request.user.message_set.create(message=msg + ' ' + _("You may edit it again below."))
    421             if request.REQUEST.has_key('_popup'):
    422                 return HttpResponseRedirect(request.path + "?_popup=1")
    423             else:
    424                 return HttpResponseRedirect(request.path)
    425         elif request.POST.has_key("_saveasnew"):
    426             request.user.message_set.create(message=_('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % {'name': opts.verbose_name, 'obj': new_object})
    427             return HttpResponseRedirect("../%s/" % pk_value)
    428         elif request.POST.has_key("_addanother"):
    429             request.user.message_set.create(message=msg + ' ' + (_("You may add another %s below.") % opts.verbose_name))
    430             return HttpResponseRedirect("../add/")
    431         else:
    432             request.user.message_set.create(message=msg)
    433             return HttpResponseRedirect("../")
    434     save_change = transaction.commit_on_success(save_change)
    435 
    436     def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
    437         opts = self.model._meta
    438         app_label = opts.app_label
    439         ordered_objects = opts.get_ordered_objects()
    440         context.update({
    441             'add': add,
    442             'change': change,
    443             'has_add_permission': self.has_add_permission(request),
    444             'has_change_permission': self.has_change_permission(request, obj),
    445             'has_delete_permission': self.has_delete_permission(request, obj),
    446             'has_file_field': True, # FIXME - this should check if form or formsets have a FileField,
    447             'has_absolute_url': hasattr(self.model, 'get_absolute_url'),
    448             'ordered_objects': ordered_objects,
    449             'form_url': mark_safe(form_url),
    450             'opts': opts,
    451             'content_type_id': ContentType.objects.get_for_model(self.model).id,
    452             'save_as': self.save_as,
    453             'save_on_top': self.save_on_top,
    454             'root_path': self.admin_site.root_path,
    455         })
    456         return render_to_response(self.change_form_template or [
    457             "admin/%s/%s/change_form.html" % (app_label, opts.object_name.lower()),
    458             "admin/%s/change_form.html" % app_label,
    459             "admin/change_form.html"
    460         ], context, context_instance=template.RequestContext(request))
    461 
    462     def add_view(self, request, form_url='', extra_context=None):
    463         "The 'add' admin view for this model."
    464         model = self.model
    465         opts = model._meta
    466         app_label = opts.app_label
    467 
    468         if not self.has_add_permission(request):
    469             raise PermissionDenied
    470 
    471         if self.has_change_permission(request, None):
    472             # redirect to list view
    473             post_url = '../'
    474         else:
    475             # Object list will give 'Permission Denied', so go back to admin home
    476             post_url = '../../../'
    477 
    478         ModelForm = self.get_form(request)
    479         inline_formsets = []
    480         obj = self.model()
    481         if request.method == 'POST':
    482             form = ModelForm(request.POST, request.FILES)
    483             for FormSet in self.get_formsets(request):
    484                 inline_formset = FormSet(data=request.POST, files=request.FILES,
    485                     instance=obj, save_as_new=request.POST.has_key("_saveasnew"))
    486                 inline_formsets.append(inline_formset)
    487             if all_valid(inline_formsets) and form.is_valid():
    488                 return self.save_add(request, form, inline_formsets, '../%s/')
    489         else:
    490             form = ModelForm(initial=dict(request.GET.items()))
    491             for FormSet in self.get_formsets(request):
    492                 inline_formset = FormSet(instance=obj)
    493                 inline_formsets.append(inline_formset)
    494 
    495         adminForm = AdminForm(form, list(self.get_fieldsets(request)), self.prepopulated_fields)
    496         media = self.media + adminForm.media
    497         for fs in inline_formsets:
    498             media = media + fs.media
    499 
    500         inline_admin_formsets = []
    501         for inline, formset in zip(self.inline_instances, inline_formsets):
    502             fieldsets = list(inline.get_fieldsets(request))
    503             inline_admin_formset = InlineAdminFormSet(inline, formset, fieldsets)
    504             inline_admin_formsets.append(inline_admin_formset)
    505 
    506         context = {
    507             'title': _('Add %s') % opts.verbose_name,
    508             'adminform': adminForm,
    509             'is_popup': request.REQUEST.has_key('_popup'),
    510             'show_delete': False,
    511             'media': mark_safe(media),
    512             'inline_admin_formsets': inline_admin_formsets,
    513             'errors': AdminErrorList(form, inline_formsets),
    514             'root_path': self.admin_site.root_path,
    515         }
    516         context.update(extra_context or {})
    517         return self.render_change_form(request, context, add=True)
    518 
    519     def change_view(self, request, object_id, extra_context=None):
    520         "The 'change' admin view for this model."
    521         model = self.model
    522         opts = model._meta
    523         app_label = opts.app_label
    524 
    525         try:
    526             obj = model._default_manager.get(pk=object_id)
    527         except model.DoesNotExist:
    528             # Don't raise Http404 just yet, because we haven't checked
    529             # permissions yet. We don't want an unauthenticated user to be able
    530             # to determine whether a given object exists.
    531             obj = None
    532 
    533         if not self.has_change_permission(request, obj):
    534             raise PermissionDenied
    535 
    536         if obj is None:
    537             raise Http404('%s object with primary key %r does not exist.' % (opts.verbose_name, escape(object_id)))
    538 
    539         if request.POST and request.POST.has_key("_saveasnew"):
    540             return self.add_view(request, form_url='../../add/')
    541 
    542         ModelForm = self.get_form(request, obj)
    543         inline_formsets = []
    544         if request.method == 'POST':
    545             form = ModelForm(request.POST, request.FILES, instance=obj)
    546             for FormSet in self.get_formsets(request, obj):
    547                 inline_formset = FormSet(request.POST, request.FILES, instance=obj)
    548                 inline_formsets.append(inline_formset)
    549 
    550             if all_valid(inline_formsets) and form.is_valid():
    551                 return self.save_change(request, form, inline_formsets)
    552         else:
    553             form = ModelForm(instance=obj)
    554             for FormSet in self.get_formsets(request, obj):
    555                 inline_formset = FormSet(instance=obj)
    556                 inline_formsets.append(inline_formset)
    557 
    558         adminForm = AdminForm(form, self.get_fieldsets(request, obj), self.prepopulated_fields)
    559         media = self.media + adminForm.media
    560         for fs in inline_formsets:
    561             media = media + fs.media
    562 
    563         inline_admin_formsets = []
    564         for inline, formset in zip(self.inline_instances, inline_formsets):
    565             fieldsets = list(inline.get_fieldsets(request, obj))
    566             inline_admin_formset = InlineAdminFormSet(inline, formset, fieldsets)
    567             inline_admin_formsets.append(inline_admin_formset)
    568 
    569         context = {
    570             'title': _('Change %s') % opts.verbose_name,
    571             'adminform': adminForm,
    572             'object_id': object_id,
    573             'original': obj,
    574             'is_popup': request.REQUEST.has_key('_popup'),
    575             'media': mark_safe(media),
    576             'inline_admin_formsets': inline_admin_formsets,
    577             'errors': AdminErrorList(form, inline_formsets),
    578             'root_path': self.admin_site.root_path,
    579         }
    580         context.update(extra_context or {})
    581         return self.render_change_form(request, context, change=True, obj=obj)
    582 
    583     def changelist_view(self, request, extra_context=None):
    584         "The 'change list' admin view for this model."
    585         from django.contrib.admin.views.main import ChangeList, ERROR_FLAG
    586         opts = self.model._meta
    587         app_label = opts.app_label
    588         if not self.has_change_permission(request, None):
    589             raise PermissionDenied
    590         try:
    591             cl = ChangeList(request, self.model, self.list_display, self.list_display_links, self.list_filter,
    592                 self.date_hierarchy, self.search_fields, self.list_select_related, self.list_per_page, self)
    593         except IncorrectLookupParameters:
    594             # Wacky lookup parameters were given, so redirect to the main
    595             # changelist page, without parameters, and pass an 'invalid=1'
    596             # parameter via the query string. If wacky parameters were given and
    597             # the 'invalid=1' parameter was already in the query string, something
    598             # is screwed up with the database, so display an error page.
    599             if ERROR_FLAG in request.GET.keys():
    600                 return render_to_response('admin/invalid_setup.html', {'title': _('Database error')})
    601             return HttpResponseRedirect(request.path + '?' + ERROR_FLAG + '=1')
    602        
    603         context = {
    604             'title': cl.title,
    605             'is_popup': cl.is_popup,
    606             'cl': cl,
    607             'has_add_permission': self.has_add_permission(request),
    608             'root_path': self.admin_site.root_path,
    609         }
    610         context.update(extra_context or {})
    611         return render_to_response(self.change_list_template or [
    612             'admin/%s/%s/change_list.html' % (app_label, opts.object_name.lower()),
    613             'admin/%s/change_list.html' % app_label,
    614             'admin/change_list.html'
    615         ], context, context_instance=template.RequestContext(request))
    616 
    617     def delete_view(self, request, object_id, extra_context=None):
    618         "The 'delete' admin view for this model."
    619         from django.contrib.admin.models import LogEntry, DELETION
    620         opts = self.model._meta
    621         app_label = opts.app_label
    622 
    623         try:
    624             obj = self.model._default_manager.get(pk=object_id)
    625         except self.model.DoesNotExist:
    626             # Don't raise Http404 just yet, because we haven't checked
    627             # permissions yet. We don't want an unauthenticated user to be able
    628             # to determine whether a given object exists.
    629             obj = None
    630 
    631         if not self.has_delete_permission(request, obj):
    632             raise PermissionDenied
    633 
    634         if obj is None:
    635             raise Http404('%s object with primary key %r does not exist.' % (opts.verbose_name, escape(object_id)))
    636 
    637         # Populate deleted_objects, a data structure of all related objects that
    638         # will also be deleted.
    639         deleted_objects = [mark_safe(u'%s: <a href="../../%s/">%s</a>' % (escape(force_unicode(capfirst(opts.verbose_name))), quote(object_id), escape(obj))), []]
    640         perms_needed = sets.Set()
    641         get_deleted_objects(deleted_objects, perms_needed, request.user, obj, opts, 1, self.admin_site)
    642 
    643         if request.POST: # The user has already confirmed the deletion.
    644             if perms_needed:
    645                 raise PermissionDenied
    646             obj_display = str(obj)
    647             obj.delete()
    648             LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(self.model).id, object_id, obj_display, DELETION)
    649             request.user.message_set.create(message=_('The %(name)s "%(obj)s" was deleted successfully.') % {'name': force_unicode(opts.verbose_name), 'obj': force_unicode(obj_display)})
    650             if not self.has_change_permission(request, None):
    651                 return HttpResponseRedirect("../../../../")
    652             return HttpResponseRedirect("../../")
    653        
    654         context = {
    655             "title": _("Are you sure?"),
    656             "object_name": opts.verbose_name,
    657             "object": obj,
    658             "deleted_objects": deleted_objects,
    659             "perms_lacking": perms_needed,
    660             "opts": opts,
    661             "root_path": self.admin_site.root_path,
    662         }
    663         context.update(extra_context or {})
    664         return render_to_response(self.delete_confirmation_template or [
    665             "admin/%s/%s/delete_confirmation.html" % (app_label, opts.object_name.lower()),
    666             "admin/%s/delete_confirmation.html" % app_label,
    667             "admin/delete_confirmation.html"
    668         ], context, context_instance=template.RequestContext(request))
    669 
    670     def history_view(self, request, object_id, extra_context=None):
    671         "The 'history' admin view for this model."
    672         from django.contrib.admin.models import LogEntry
    673         model = self.model
    674         opts = model._meta
    675         action_list = LogEntry.objects.filter(
    676             object_id = object_id,
    677             content_type__id__exact = ContentType.objects.get_for_model(model).id
    678         ).select_related().order_by('action_time')
    679         # If no history was found, see whether this object even exists.
    680         obj = get_object_or_404(model, pk=object_id)
    681         context = {
    682             'title': _('Change history: %s') % force_unicode(obj),
    683             'action_list': action_list,
    684             'module_name': capfirst(opts.verbose_name_plural),
    685             'object': obj,
    686             'root_path': self.admin_site.root_path,
    687         }
    688         context.update(extra_context or {})
    689         return render_to_response(self.object_history_template or [
    690             "admin/%s/%s/object_history.html" % (opts.app_label, opts.object_name.lower()),
    691             "admin/%s/object_history.html" % opts.app_label,
    692             "admin/object_history.html"
    693         ], context, context_instance=template.RequestContext(request))
    694 
    695 class InlineModelAdmin(BaseModelAdmin):
    696     """
    697     Options for inline editing of ``model`` instances.
    698 
    699     Provide ``name`` to specify the attribute name of the ``ForeignKey`` from
    700     ``model`` to its parent. This is required if ``model`` has more than one
    701     ``ForeignKey`` to its parent.
    702     """
    703     model = None
    704     fk_name = None
    705     formset = BaseInlineFormset
    706     extra = 3
    707     max_num = 0
    708     template = None
    709     verbose_name = None
    710     verbose_name_plural = None
    711 
    712     def __init__(self, parent_model, admin_site):
    713         self.admin_site = admin_site
    714         self.parent_model = parent_model
    715         self.opts = self.model._meta
    716         super(InlineModelAdmin, self).__init__()
    717         if self.verbose_name is None:
    718             self.verbose_name = self.model._meta.verbose_name
    719         if self.verbose_name_plural is None:
    720             self.verbose_name_plural = self.model._meta.verbose_name_plural
    721 
    722     def get_formset(self, request, obj=None):
    723         """Returns a BaseInlineFormSet class for use in admin add/change views."""
    724         if self.declared_fieldsets:
    725             fields = flatten_fieldsets(self.declared_fieldsets)
    726         else:
    727             fields = None
    728         return inlineformset_factory(self.parent_model, self.model,
    729             form=self.form, formset=self.formset, fk_name=self.fk_name,
    730             fields=fields, formfield_callback=self.formfield_for_dbfield,
    731             extra=self.extra, max_num=self.max_num)
    732 
    733     def get_fieldsets(self, request, obj=None):
    734         if self.declared_fieldsets:
    735             return self.declared_fieldsets
    736         form = self.get_formset(request).form
    737         return [(None, {'fields': form.base_fields.keys()})]
    738 
    739 class StackedInline(InlineModelAdmin):
    740     template = 'admin/edit_inline/stacked.html'
    741 
    742 class TabularInline(InlineModelAdmin):
    743     template = 'admin/edit_inline/tabular.html'
    744 
    745 class InlineAdminFormSet(object):
    746     """
    747     A wrapper around an inline formset for use in the admin system.
    748     """
    749     def __init__(self, inline, formset, fieldsets):
    750         self.opts = inline
    751         self.formset = formset
    752         self.fieldsets = fieldsets
    753 
    754     def __iter__(self):
    755         for form, original in zip(self.formset.initial_forms, self.formset.get_queryset()):
    756             yield InlineAdminForm(self.formset, form, self.fieldsets, self.opts.prepopulated_fields, original)
    757         for form in self.formset.extra_forms:
    758             yield InlineAdminForm(self.formset, form, self.fieldsets, self.opts.prepopulated_fields, None)
    759 
    760     def fields(self):
    761         for field_name in flatten_fieldsets(self.fieldsets):
    762             yield self.formset.form.base_fields[field_name]
    763 
    764 class InlineAdminForm(AdminForm):
    765     """
    766     A wrapper around an inline form for use in the admin system.
    767     """
    768     def __init__(self, formset, form, fieldsets, prepopulated_fields, original):
    769         self.formset = formset
    770         self.original = original
    771         self.show_url = original and hasattr(original, 'get_absolute_url')
    772         super(InlineAdminForm, self).__init__(form, fieldsets, prepopulated_fields)
    773 
    774     def pk_field(self):
    775         return AdminField(self.form, self.formset._pk_field_name, False)
    776 
    777     def deletion_field(self):
    778         from django.forms.formsets import DELETION_FIELD_NAME
    779         return AdminField(self.form, DELETION_FIELD_NAME, False)
    780 
    781     def ordering_field(self):
    782         from django.forms.formsets import ORDERING_FIELD_NAME
    783         return AdminField(self.form, ORDERING_FIELD_NAME, False)
    784 
    785 class AdminErrorList(forms.util.ErrorList):
    786     """
    787     Stores all errors for the form/formsets in an add/change stage view.
    788     """
    789     def __init__(self, form, inline_formsets):
    790         if form.is_bound:
    791             self.extend(form.errors.values())
    792             for inline_formset in inline_formsets:
    793                 self.extend(inline_formset.non_form_errors())
    794                 for errors_in_inline_form in inline_formset.errors:
    795                     self.extend(errors_in_inline_form.values())
     1from django import template
     2from django import forms
     3from django.forms.formsets import all_valid
     4from django.forms.models import modelform_factory, inlineformset_factory
     5from django.forms.models import BaseInlineFormset
     6from django.contrib.contenttypes.models import ContentType
     7from django.contrib.admin import widgets
     8from django.contrib.admin.util import quote, unquote, get_deleted_objects
     9from django.core.exceptions import ImproperlyConfigured, PermissionDenied
     10from django.db import models, transaction
     11from django.http import Http404, HttpResponse, HttpResponseRedirect
     12from django.shortcuts import get_object_or_404, render_to_response
     13from django.utils.html import escape
     14from django.utils.safestring import mark_safe
     15from django.utils.text import capfirst, get_text_list
     16from django.utils.translation import ugettext as _
     17from django.utils.encoding import force_unicode
     18import sets
     19
     20HORIZONTAL, VERTICAL = 1, 2
     21# returns the <ul> class for a given radio_admin field
     22get_ul_class = lambda x: 'radiolist%s' % ((x == HORIZONTAL) and ' inline' or '')
     23
     24class IncorrectLookupParameters(Exception):
     25    pass
     26
     27def flatten_fieldsets(fieldsets):
     28    """Returns a list of field names from an admin fieldsets structure."""
     29    field_names = []
     30    for name, opts in fieldsets:
     31        for field in opts['fields']:
     32            # type checking feels dirty, but it seems like the best way here
     33            if type(field) == tuple:
     34                field_names.extend(field)
     35            else:
     36                field_names.append(field)
     37    return field_names
     38
     39class AdminForm(object):
     40    def __init__(self, form, fieldsets, prepopulated_fields):
     41        self.form, self.fieldsets = form, fieldsets
     42        self.prepopulated_fields = [{
     43            'field': form[field_name],
     44            'dependencies': [form[f] for f in dependencies]
     45        } for field_name, dependencies in prepopulated_fields.items()]
     46
     47    def __iter__(self):
     48        for name, options in self.fieldsets:
     49            yield Fieldset(self.form, name, **options)
     50
     51    def first_field(self):
     52        for bf in self.form:
     53            return bf
     54
     55    def _media(self):
     56        media = self.form.media
     57        for fs in self:
     58            media = media + fs.media
     59        return media
     60    media = property(_media)
     61
     62class Fieldset(object):
     63    def __init__(self, form, name=None, fields=(), classes=(), description=None):
     64        self.form = form
     65        self.name, self.fields = name, fields
     66        self.classes = u' '.join(classes)
     67        self.description = description
     68
     69    def _media(self):
     70        from django.conf import settings
     71        if 'collapse' in self.classes:
     72            return forms.Media(js=['%sjs/admin/CollapsedFieldsets.js' % settings.ADMIN_MEDIA_PREFIX])
     73        return forms.Media()
     74    media = property(_media)
     75
     76    def __iter__(self):
     77        for field in self.fields:
     78            yield Fieldline(self.form, field)
     79
     80class Fieldline(object):
     81    def __init__(self, form, field):
     82        self.form = form # A django.forms.Form instance
     83        if isinstance(field, basestring):
     84            self.fields = [field]
     85        else:
     86            self.fields = field
     87
     88    def __iter__(self):
     89        for i, field in enumerate(self.fields):
     90            yield AdminField(self.form, field, is_first=(i == 0))
     91
     92    def errors(self):
     93        return mark_safe(u'\n'.join([self.form[f].errors.as_ul() for f in self.fields]))
     94
     95class AdminField(object):
     96    def __init__(self, form, field, is_first):
     97        self.field = form[field] # A django.forms.BoundField instance
     98        self.is_first = is_first # Whether this field is first on the line
     99        self.is_checkbox = isinstance(self.field.field.widget, forms.CheckboxInput)
     100
     101    def label_tag(self):
     102        classes = []
     103        if self.is_checkbox:
     104            classes.append(u'vCheckboxLabel')
     105            contents = escape(self.field.label)
     106        else:
     107            contents = force_unicode(escape(self.field.label)) + u':'
     108        if self.field.field.required:
     109            classes.append(u'required')
     110        if not self.is_first:
     111            classes.append(u'inline')
     112        attrs = classes and {'class': u' '.join(classes)} or {}
     113        return self.field.label_tag(contents=contents, attrs=attrs)
     114
     115class BaseModelAdmin(object):
     116    """Functionality common to both ModelAdmin and InlineAdmin."""
     117    raw_id_fields = ()
     118    fields = None
     119    fieldsets = None
     120    form = forms.ModelForm
     121    filter_vertical = ()
     122    filter_horizontal = ()
     123    radio_fields = {}
     124    prepopulated_fields = {}
     125
     126    def formfield_for_dbfield(self, db_field, **kwargs):
     127        """
     128        Hook for specifying the form Field instance for a given database Field
     129        instance.
     130
     131        If kwargs are given, they're passed to the form Field's constructor.
     132        """
     133        # For DateTimeFields, use a special field and widget.
     134        if isinstance(db_field, models.DateTimeField):
     135            kwargs['form_class'] = forms.SplitDateTimeField
     136            kwargs['widget'] = widgets.AdminSplitDateTime()
     137            return db_field.formfield(**kwargs)
     138
     139        # For DateFields, add a custom CSS class.
     140        if isinstance(db_field, models.DateField):
     141            kwargs['widget'] = widgets.AdminDateWidget
     142            return db_field.formfield(**kwargs)
     143
     144        # For TimeFields, add a custom CSS class.
     145        if isinstance(db_field, models.TimeField):
     146            kwargs['widget'] = widgets.AdminTimeWidget
     147            return db_field.formfield(**kwargs)
     148
     149        # For FileFields and ImageFields add a link to the current file.
     150        if isinstance(db_field, models.ImageField) or isinstance(db_field, models.FileField):
     151            kwargs['widget'] = widgets.AdminFileWidget
     152            return db_field.formfield(**kwargs)
     153
     154        # For ForeignKey or ManyToManyFields, use a special widget.
     155        if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)):
     156            if isinstance(db_field, models.ForeignKey) and db_field.name in self.raw_id_fields:
     157                kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel)
     158            elif isinstance(db_field, models.ForeignKey) and db_field.name in self.radio_fields:
     159                kwargs['widget'] = widgets.AdminRadioSelect(attrs={
     160                    'class': get_ul_class(self.radio_fields[db_field.name]),
     161                })
     162                kwargs['empty_label'] = db_field.blank and _('None') or None
     163            else:
     164                if isinstance(db_field, models.ManyToManyField):
     165                    if db_field.name in self.raw_id_fields:
     166                        kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel)
     167                        kwargs['help_text'] = ''
     168                    elif db_field.name in (self.filter_vertical + self.filter_horizontal):
     169                        kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical))
     170            # Wrap the widget's render() method with a method that adds
     171            # extra HTML to the end of the rendered output.
     172            formfield = db_field.formfield(**kwargs)
     173            # Don't wrap raw_id fields. Their add function is in the popup window.
     174            if not db_field.name in self.raw_id_fields:
     175                formfield.widget = widgets.RelatedFieldWidgetWrapper(formfield.widget, db_field.rel, self.admin_site)
     176            return formfield
     177       
     178        if db_field.choices and db_field.name in self.radio_fields:
     179            kwargs['widget'] = widgets.AdminRadioSelect(
     180                choices=db_field.get_choices(include_blank=db_field.blank,
     181                    blank_choice=[('', _('None'))]),
     182                attrs={
     183                    'class': get_ul_class(self.radio_fields[db_field.name]),
     184                }
     185            )
     186
     187        # For any other type of field, just call its formfield() method.
     188        return db_field.formfield(**kwargs)
     189
     190    def _declared_fieldsets(self):
     191        if self.fieldsets:
     192            return self.fieldsets
     193        elif self.fields:
     194            return [(None, {'fields': self.fields})]
     195        return None
     196    declared_fieldsets = property(_declared_fieldsets)
     197
     198class ModelAdmin(BaseModelAdmin):
     199    "Encapsulates all admin options and functionality for a given model."
     200    __metaclass__ = forms.MediaDefiningClass
     201
     202    list_display = ('__str__',)
     203    list_display_links = ()
     204    list_filter = ()
     205    list_select_related = False
     206    list_per_page = 100
     207    search_fields = ()
     208    date_hierarchy = None
     209    save_as = False
     210    save_on_top = False
     211    ordering = None
     212    inlines = []
     213   
     214    # Custom templates (designed to be over-ridden in subclasses)
     215    change_form_template = None
     216    change_list_template = None
     217    delete_confirmation_template = None
     218    object_history_template = None
     219
     220    def __init__(self, model, admin_site):
     221        self.model = model
     222        self.opts = model._meta
     223        self.admin_site = admin_site
     224        self.inline_instances = []
     225        for inline_class in self.inlines:
     226            inline_instance = inline_class(self.model, self.admin_site)
     227            self.inline_instances.append(inline_instance)
     228        super(ModelAdmin, self).__init__()
     229
     230    def __call__(self, request, url):
     231        # Check that LogEntry, ContentType and the auth context processor are installed.
     232        from django.conf import settings
     233        if settings.DEBUG:
     234            from django.contrib.admin.models import LogEntry
     235            if not LogEntry._meta.installed:
     236                raise ImproperlyConfigured("Put 'django.contrib.admin' in your INSTALLED_APPS setting in order to use the admin application.")
     237            if not ContentType._meta.installed:
     238                raise ImproperlyConfigured("Put 'django.contrib.contenttypes' in your INSTALLED_APPS setting in order to use the admin application.")
     239            if 'django.core.context_processors.auth' not in settings.TEMPLATE_CONTEXT_PROCESSORS:
     240                raise ImproperlyConfigured("Put 'django.core.context_processors.auth' in your TEMPLATE_CONTEXT_PROCESSORS setting in order to use the admin application.")
     241
     242        # Delegate to the appropriate method, based on the URL.
     243        if url is None:
     244            return self.changelist_view(request)
     245        elif url.endswith('add'):
     246            return self.add_view(request)
     247        elif url.endswith('history'):
     248            return self.history_view(request, unquote(url[:-8]))
     249        elif url.endswith('delete'):
     250            return self.delete_view(request, unquote(url[:-7]))
     251        else:
     252            return self.change_view(request, unquote(url))
     253
     254    def _media(self):
     255        from django.conf import settings
     256
     257        js = ['js/core.js', 'js/admin/RelatedObjectLookups.js']
     258        if self.prepopulated_fields:
     259            js.append('js/urlify.js')
     260        if self.opts.get_ordered_objects():
     261            js.extend(['js/getElementsBySelector.js', 'js/dom-drag.js' , 'js/admin/ordering.js'])
     262        if self.filter_vertical or self.filter_horizontal:
     263            js.extend(['js/SelectBox.js' , 'js/SelectFilter2.js'])
     264       
     265        return forms.Media(js=['%s%s' % (settings.ADMIN_MEDIA_PREFIX, url) for url in js])
     266    media = property(_media)
     267
     268    def has_add_permission(self, request):
     269        "Returns True if the given request has permission to add an object."
     270        opts = self.opts
     271        return request.user.has_perm(opts.app_label + '.' + opts.get_add_permission())
     272
     273    def has_change_permission(self, request, obj=None):
     274        """
     275        Returns True if the given request has permission to change the given
     276        Django model instance.
     277
     278        If `obj` is None, this should return True if the given request has
     279        permission to change *any* object of the given type.
     280        """
     281        opts = self.opts
     282        return request.user.has_perm(opts.app_label + '.' + opts.get_change_permission())
     283
     284    def has_delete_permission(self, request, obj=None):
     285        """
     286        Returns True if the given request has permission to change the given
     287        Django model instance.
     288
     289        If `obj` is None, this should return True if the given request has
     290        permission to delete *any* object of the given type.
     291        """
     292        opts = self.opts
     293        return request.user.has_perm(opts.app_label + '.' + opts.get_delete_permission())
     294
     295    def queryset(self, request):
     296        """
     297        Returns a QuerySet of all model instances that can be edited by the
     298        admin site. This is used by changelist_view.
     299        """
     300        qs = self.model._default_manager.get_query_set()
     301        # TODO: this should be handled by some parameter to the ChangeList.
     302        ordering = self.ordering or () # otherwise we might try to *None, which is bad ;)
     303        if ordering:
     304            qs = qs.order_by(*ordering)
     305        return qs
     306
     307    def get_fieldsets(self, request, obj=None):
     308        "Hook for specifying fieldsets for the add form."
     309        if self.declared_fieldsets:
     310            return self.declared_fieldsets
     311        form = self.get_form(request)
     312        return [(None, {'fields': form.base_fields.keys()})]
     313
     314    def get_form(self, request, obj=None):
     315        """
     316        Returns a Form class for use in the admin add view. This is used by
     317        add_view and change_view.
     318        """
     319        if self.declared_fieldsets:
     320            fields = flatten_fieldsets(self.declared_fieldsets)
     321        else:
     322            fields = None
     323        return modelform_factory(self.model, form=self.form, fields=fields, formfield_callback=self.formfield_for_dbfield)
     324
     325    def get_formsets(self, request, obj=None):
     326        for inline in self.inline_instances:
     327            yield inline.get_formset(request, obj)
     328
     329    def save_add(self, request, form, formsets, post_url_continue):
     330        """
     331        Saves the object in the "add" stage and returns an HttpResponseRedirect.
     332
     333        `form` is a bound Form instance that's verified to be valid.
     334        """
     335        from django.contrib.admin.models import LogEntry, ADDITION
     336        opts = self.model._meta
     337        new_object = form.save(commit=True)
     338
     339        if formsets:
     340            for formset in formsets:
     341                # HACK: it seems like the parent obejct should be passed into
     342                # a method of something, not just set as an attribute
     343                formset.instance = new_object
     344                formset.save()
     345
     346        pk_value = new_object._get_pk_val()
     347        LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(self.model).id, pk_value, force_unicode(new_object), ADDITION)
     348        msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': opts.verbose_name, 'obj': new_object}
     349        # Here, we distinguish between different save types by checking for
     350        # the presence of keys in request.POST.
     351        if request.POST.has_key("_continue"):
     352            request.user.message_set.create(message=msg + ' ' + _("You may edit it again below."))
     353            if request.POST.has_key("_popup"):
     354                post_url_continue += "?_popup=1"
     355            return HttpResponseRedirect(post_url_continue % pk_value)
     356
     357        if request.POST.has_key("_popup"):
     358            return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, "%s", "%s");</script>' % \
     359                # escape() calls force_unicode.
     360                (escape(pk_value), escape(new_object)))
     361        elif request.POST.has_key("_addanother"):
     362            request.user.message_set.create(message=msg + ' ' + (_("You may add another %s below.") % opts.verbose_name))
     363            return HttpResponseRedirect(request.path)
     364        else:
     365            request.user.message_set.create(message=msg)
     366            # Figure out where to redirect. If the user has change permission,
     367            # redirect to the change-list page for this object. Otherwise,
     368            # redirect to the admin index.
     369            if self.has_change_permission(request, None):
     370                post_url = '../'
     371            else:
     372                post_url = '../../../'
     373            return HttpResponseRedirect(post_url)
     374    save_add = transaction.commit_on_success(save_add)
     375
     376    def save_change(self, request, form, formsets=None):
     377        """
     378        Saves the object in the "change" stage and returns an HttpResponseRedirect.
     379
     380        `form` is a bound Form instance that's verified to be valid.
     381       
     382        `formsets` is a sequence of InlineFormSet instances that are verified to be valid.
     383        """
     384        from django.contrib.admin.models import LogEntry, CHANGE
     385        opts = self.model._meta
     386        new_object = form.save(commit=True)
     387        pk_value = new_object._get_pk_val()
     388
     389        if formsets:
     390            for formset in formsets:
     391                formset.save()
     392
     393        # Construct the change message.
     394        change_message = []
     395        if form.changed_data:
     396            change_message.append(_('Changed %s.') % get_text_list(form.changed_data, _('and')))
     397           
     398        if formsets:
     399            for formset in formsets:
     400                for added_object in formset.new_objects:
     401                    change_message.append(_('Added %(name)s "%(object)s".')
     402                                          % {'name': added_object._meta.verbose_name,
     403                                             'object': added_object})
     404                for changed_object, changed_fields in formset.changed_objects:
     405                    change_message.append(_('Changed %(list)s for %(name)s "%(object)s".')
     406                                          % {'list': get_text_list(changed_fields, _('and')),
     407                                             'name': changed_object._meta.verbose_name,
     408                                             'object': changed_object})
     409                for deleted_object in formset.deleted_objects:
     410                    change_message.append(_('Deleted %(name)s "%(object)s".')
     411                                          % {'name': deleted_object._meta.verbose_name,
     412                                             'object': deleted_object})
     413        change_message = ' '.join(change_message)
     414        if not change_message:
     415            change_message = _('No fields changed.')
     416        LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(self.model).id, pk_value, force_unicode(new_object), CHANGE, change_message)
     417
     418        msg = _('The %(name)s "%(obj)s" was changed successfully.') % {'name': opts.verbose_name, 'obj': new_object}
     419        if request.POST.has_key("_continue"):
     420            request.user.message_set.create(message=msg + ' ' + _("You may edit it again below."))
     421            if request.REQUEST.has_key('_popup'):
     422                return HttpResponseRedirect(request.path + "?_popup=1")
     423            else:
     424                return HttpResponseRedirect(request.path)
     425        elif request.POST.has_key("_saveasnew"):
     426            request.user.message_set.create(message=_('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % {'name': opts.verbose_name, 'obj': new_object})
     427            return HttpResponseRedirect("../%s/" % pk_value)
     428        elif request.POST.has_key("_addanother"):
     429            request.user.message_set.create(message=msg + ' ' + (_("You may add another %s below.") % opts.verbose_name))
     430            return HttpResponseRedirect("../add/")
     431        else:
     432            request.user.message_set.create(message=msg)
     433            return HttpResponseRedirect("../")
     434    save_change = transaction.commit_on_success(save_change)
     435
     436    def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
     437        opts = self.model._meta
     438        app_label = opts.app_label
     439        ordered_objects = opts.get_ordered_objects()
     440        context.update({
     441            'add': add,
     442            'change': change,
     443            'has_add_permission': self.has_add_permission(request),
     444            'has_change_permission': self.has_change_permission(request, obj),
     445            'has_delete_permission': self.has_delete_permission(request, obj),
     446            'has_file_field': True, # FIXME - this should check if form or formsets have a FileField,
     447            'has_absolute_url': hasattr(self.model, 'get_absolute_url'),
     448            'ordered_objects': ordered_objects,
     449            'form_url': mark_safe(form_url),
     450            'opts': opts,
     451            'content_type_id': ContentType.objects.get_for_model(self.model).id,
     452            'save_as': self.save_as,
     453            'save_on_top': self.save_on_top,
     454            'root_path': self.admin_site.root_path,
     455        })
     456        return render_to_response(self.change_form_template or [
     457            "admin/%s/%s/change_form.html" % (app_label, opts.object_name.lower()),
     458            "admin/%s/change_form.html" % app_label,
     459            "admin/change_form.html"
     460        ], context, context_instance=template.RequestContext(request))
     461
     462    def add_view(self, request, form_url='', extra_context=None):
     463        "The 'add' admin view for this model."
     464        model = self.model
     465        opts = model._meta
     466        app_label = opts.app_label
     467
     468        if not self.has_add_permission(request):
     469            raise PermissionDenied
     470
     471        if self.has_change_permission(request, None):
     472            # redirect to list view
     473            post_url = '../'
     474        else:
     475            # Object list will give 'Permission Denied', so go back to admin home
     476            post_url = '../../../'
     477
     478        ModelForm = self.get_form(request)
     479        inline_formsets = []
     480        obj = self.model()
     481        if request.method == 'POST':
     482            form = ModelForm(request.POST, request.FILES)
     483            for FormSet in self.get_formsets(request):
     484                inline_formset = FormSet(data=request.POST, files=request.FILES,
     485                    instance=obj, save_as_new=request.POST.has_key("_saveasnew"))
     486                inline_formsets.append(inline_formset)
     487            if all_valid(inline_formsets) and form.is_valid():
     488                return self.save_add(request, form, inline_formsets, '../%s/')
     489        else:
     490            form = ModelForm(initial=dict(request.GET.items()))
     491            for FormSet in self.get_formsets(request):
     492                inline_formset = FormSet(instance=obj)
     493                inline_formsets.append(inline_formset)
     494
     495        adminForm = AdminForm(form, list(self.get_fieldsets(request)), self.prepopulated_fields)
     496        media = self.media + adminForm.media
     497        for fs in inline_formsets:
     498            media = media + fs.media
     499
     500        inline_admin_formsets = []
     501        for inline, formset in zip(self.inline_instances, inline_formsets):
     502            fieldsets = list(inline.get_fieldsets(request))
     503            inline_admin_formset = InlineAdminFormSet(inline, formset, fieldsets)
     504            inline_admin_formsets.append(inline_admin_formset)
     505
     506        context = {
     507            'title': _('Add %s') % opts.verbose_name,
     508            'adminform': adminForm,
     509            'is_popup': request.REQUEST.has_key('_popup'),
     510            'show_delete': False,
     511            'media': mark_safe(media),
     512            'inline_admin_formsets': inline_admin_formsets,
     513            'errors': AdminErrorList(form, inline_formsets),
     514            'root_path': self.admin_site.root_path,
     515        }
     516        context.update(extra_context or {})
     517        return self.render_change_form(request, context, add=True)
     518
     519    def change_view(self, request, object_id, extra_context=None):
     520        "The 'change' admin view for this model."
     521        model = self.model
     522        opts = model._meta
     523        app_label = opts.app_label
     524
     525        try:
     526            obj = model._default_manager.get(pk=object_id)
     527        except model.DoesNotExist:
     528            # Don't raise Http404 just yet, because we haven't checked
     529            # permissions yet. We don't want an unauthenticated user to be able
     530            # to determine whether a given object exists.
     531            obj = None
     532
     533        if not self.has_change_permission(request, obj):
     534            raise PermissionDenied
     535
     536        if obj is None:
     537            raise Http404('%s object with primary key %r does not exist.' % (opts.verbose_name, escape(object_id)))
     538
     539        if request.POST and request.POST.has_key("_saveasnew"):
     540            return self.add_view(request, form_url='../../add/')
     541
     542        ModelForm = self.get_form(request, obj)
     543        inline_formsets = []
     544        if request.method == 'POST':
     545            form = ModelForm(request.POST, request.FILES, instance=obj)
     546            for FormSet in self.get_formsets(request, obj):
     547                inline_formset = FormSet(request.POST, request.FILES, instance=obj)
     548                inline_formsets.append(inline_formset)
     549
     550            if all_valid(inline_formsets) and form.is_valid():
     551                return self.save_change(request, form, inline_formsets)
     552        else:
     553            form = ModelForm(instance=obj)
     554            for FormSet in self.get_formsets(request, obj):
     555                inline_formset = FormSet(instance=obj)
     556                inline_formsets.append(inline_formset)
     557
     558        adminForm = AdminForm(form, self.get_fieldsets(request, obj), self.prepopulated_fields)
     559        media = self.media + adminForm.media
     560        for fs in inline_formsets:
     561            media = media + fs.media
     562
     563        inline_admin_formsets = []
     564        for inline, formset in zip(self.inline_instances, inline_formsets):
     565            fieldsets = list(inline.get_fieldsets(request, obj))
     566            inline_admin_formset = InlineAdminFormSet(inline, formset, fieldsets)
     567            inline_admin_formsets.append(inline_admin_formset)
     568
     569        context = {
     570            'title': _('Change %s') % opts.verbose_name,
     571            'adminform': adminForm,
     572            'object_id': object_id,
     573            'original': obj,
     574            'is_popup': request.REQUEST.has_key('_popup'),
     575            'media': mark_safe(media),
     576            'inline_admin_formsets': inline_admin_formsets,
     577            'errors': AdminErrorList(form, inline_formsets),
     578            'root_path': self.admin_site.root_path,
     579        }
     580        context.update(extra_context or {})
     581        return self.render_change_form(request, context, change=True, obj=obj)
     582
     583    def changelist_view(self, request, extra_context=None):
     584        "The 'change list' admin view for this model."
     585        from django.contrib.admin.views.main import ChangeList, ERROR_FLAG
     586        opts = self.model._meta
     587        app_label = opts.app_label
     588        if not self.has_change_permission(request, None):
     589            raise PermissionDenied
     590        try:
     591            cl = ChangeList(request, self.model, self.list_display, self.list_display_links, self.list_filter,
     592                self.date_hierarchy, self.search_fields, self.list_select_related, self.list_per_page, self)
     593        except IncorrectLookupParameters:
     594            # Wacky lookup parameters were given, so redirect to the main
     595            # changelist page, without parameters, and pass an 'invalid=1'
     596            # parameter via the query string. If wacky parameters were given and
     597            # the 'invalid=1' parameter was already in the query string, something
     598            # is screwed up with the database, so display an error page.
     599            if ERROR_FLAG in request.GET.keys():
     600                return render_to_response('admin/invalid_setup.html', {'title': _('Database error')})
     601            return HttpResponseRedirect(request.path + '?' + ERROR_FLAG + '=1')
     602       
     603        context = {
     604            'title': cl.title,
     605            'is_popup': cl.is_popup,
     606            'cl': cl,
     607            'has_add_permission': self.has_add_permission(request),
     608            'root_path': self.admin_site.root_path,
     609        }
     610        context.update(extra_context or {})
     611        return render_to_response(self.change_list_template or [
     612            'admin/%s/%s/change_list.html' % (app_label, opts.object_name.lower()),
     613            'admin/%s/change_list.html' % app_label,
     614            'admin/change_list.html'
     615        ], context, context_instance=template.RequestContext(request))
     616
     617    def delete_view(self, request, object_id, extra_context=None):
     618        "The 'delete' admin view for this model."
     619        from django.contrib.admin.models import LogEntry, DELETION
     620        opts = self.model._meta
     621        app_label = opts.app_label
     622
     623        try:
     624            obj = self.model._default_manager.get(pk=object_id)
     625        except self.model.DoesNotExist:
     626            # Don't raise Http404 just yet, because we haven't checked
     627            # permissions yet. We don't want an unauthenticated user to be able
     628            # to determine whether a given object exists.
     629            obj = None
     630
     631        if not self.has_delete_permission(request, obj):
     632            raise PermissionDenied
     633
     634        if obj is None:
     635            raise Http404('%s object with primary key %r does not exist.' % (opts.verbose_name, escape(object_id)))
     636
     637        # Populate deleted_objects, a data structure of all related objects that
     638        # will also be deleted.
     639        deleted_objects = [mark_safe(u'%s: <a href="../../%s/">%s</a>' % (escape(force_unicode(capfirst(opts.verbose_name))), quote(object_id), escape(obj))), []]
     640        perms_needed = sets.Set()
     641        get_deleted_objects(deleted_objects, perms_needed, request.user, obj, opts, 1, self.admin_site)
     642
     643        if request.POST: # The user has already confirmed the deletion.
     644            if perms_needed:
     645                raise PermissionDenied
     646            obj_display = str(obj)
     647            obj.delete()
     648            LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(self.model).id, object_id, obj_display, DELETION)
     649            request.user.message_set.create(message=_('The %(name)s "%(obj)s" was deleted successfully.') % {'name': force_unicode(opts.verbose_name), 'obj': force_unicode(obj_display)})
     650            if not self.has_change_permission(request, None):
     651                return HttpResponseRedirect("../../../../")
     652            return HttpResponseRedirect("../../")
     653       
     654        context = {
     655            "title": _("Are you sure?"),
     656            "object_name": opts.verbose_name,
     657            "object": obj,
     658            "deleted_objects": deleted_objects,
     659            "perms_lacking": perms_needed,
     660            "opts": opts,
     661            "root_path": self.admin_site.root_path,
     662        }
     663        context.update(extra_context or {})
     664        return render_to_response(self.delete_confirmation_template or [
     665            "admin/%s/%s/delete_confirmation.html" % (app_label, opts.object_name.lower()),
     666            "admin/%s/delete_confirmation.html" % app_label,
     667            "admin/delete_confirmation.html"
     668        ], context, context_instance=template.RequestContext(request))
     669
     670    def history_view(self, request, object_id, extra_context=None):
     671        "The 'history' admin view for this model."
     672        from django.contrib.admin.models import LogEntry
     673        model = self.model
     674        opts = model._meta
     675        action_list = LogEntry.objects.filter(
     676            object_id = object_id,
     677            content_type__id__exact = ContentType.objects.get_for_model(model).id
     678        ).select_related().order_by('action_time')
     679        # If no history was found, see whether this object even exists.
     680        obj = get_object_or_404(model, pk=object_id)
     681        context = {
     682            'title': _('Change history: %s') % force_unicode(obj),
     683            'action_list': action_list,
     684            'module_name': capfirst(opts.verbose_name_plural),
     685            'object': obj,
     686            'root_path': self.admin_site.root_path,
     687        }
     688        context.update(extra_context or {})
     689        return render_to_response(self.object_history_template or [
     690            "admin/%s/%s/object_history.html" % (opts.app_label, opts.object_name.lower()),
     691            "admin/%s/object_history.html" % opts.app_label,
     692            "admin/object_history.html"
     693        ], context, context_instance=template.RequestContext(request))
     694
     695class InlineModelAdmin(BaseModelAdmin):
     696    """
     697    Options for inline editing of ``model`` instances.
     698
     699    Provide ``name`` to specify the attribute name of the ``ForeignKey`` from
     700    ``model`` to its parent. This is required if ``model`` has more than one
     701    ``ForeignKey`` to its parent.
     702    """
     703    model = None
     704    fk_name = None
     705    formset = BaseInlineFormset
     706    extra = 3
     707    max_num = 0
     708    template = None
     709    verbose_name = None
     710    verbose_name_plural = None
     711
     712    def __init__(self, parent_model, admin_site):
     713        self.admin_site = admin_site
     714        self.parent_model = parent_model
     715        self.opts = self.model._meta
     716        super(InlineModelAdmin, self).__init__()
     717        if self.verbose_name is None:
     718            self.verbose_name = self.model._meta.verbose_name
     719        if self.verbose_name_plural is None:
     720            self.verbose_name_plural = self.model._meta.verbose_name_plural
     721
     722    def get_formset(self, request, obj=None):
     723        """Returns a BaseInlineFormSet class for use in admin add/change views."""
     724        if self.declared_fieldsets:
     725            fields = flatten_fieldsets(self.declared_fieldsets)
     726        else:
     727            fields = None
     728        return inlineformset_factory(self.parent_model, self.model,
     729            form=self.form, formset=self.formset, fk_name=self.fk_name,
     730            fields=fields, formfield_callback=self.formfield_for_dbfield,
     731            extra=self.extra, max_num=self.max_num)
     732
     733    def get_fieldsets(self, request, obj=None):
     734        if self.declared_fieldsets:
     735            return self.declared_fieldsets
     736        form = self.get_formset(request).form
     737        return [(None, {'fields': form.base_fields.keys()})]
     738
     739class StackedInline(InlineModelAdmin):
     740    template = 'admin/edit_inline/stacked.html'
     741
     742class TabularInline(InlineModelAdmin):
     743    template = 'admin/edit_inline/tabular.html'
     744
     745class InlineAdminFormSet(object):
     746    """
     747    A wrapper around an inline formset for use in the admin system.
     748    """
     749    def __init__(self, inline, formset, fieldsets):
     750        self.opts = inline
     751        self.formset = formset
     752        self.fieldsets = fieldsets
     753
     754    def __iter__(self):
     755        for form, original in zip(self.formset.initial_forms, self.formset.get_queryset()):
     756            yield InlineAdminForm(self.formset, form, self.fieldsets, self.opts.prepopulated_fields, original)
     757        for form in self.formset.extra_forms:
     758            yield InlineAdminForm(self.formset, form, self.fieldsets, self.opts.prepopulated_fields, None)
     759
     760    def fields(self):
     761        for field_name in flatten_fieldsets(self.fieldsets):
     762            yield self.formset.form.base_fields[field_name]
     763
     764class InlineAdminForm(AdminForm):
     765    """
     766    A wrapper around an inline form for use in the admin system.
     767    """
     768    def __init__(self, formset, form, fieldsets, prepopulated_fields, original):
     769        self.formset = formset
     770        self.original = original
     771        self.show_url = original and hasattr(original, 'get_absolute_url')
     772        super(InlineAdminForm, self).__init__(form, fieldsets, prepopulated_fields)
     773
     774    def pk_field(self):
     775        return AdminField(self.form, self.formset._pk_field_name, False)
     776
     777    def deletion_field(self):
     778        from django.forms.formsets import DELETION_FIELD_NAME
     779        return AdminField(self.form, DELETION_FIELD_NAME, False)
     780
     781    def ordering_field(self):
     782        from django.forms.formsets import ORDERING_FIELD_NAME
     783        return AdminField(self.form, ORDERING_FIELD_NAME, False)
     784
     785class AdminErrorList(forms.util.ErrorList):
     786    """
     787    Stores all errors for the form/formsets in an add/change stage view.
     788    """
     789    def __init__(self, form, inline_formsets):
     790        if form.is_bound:
     791            self.extend(form.errors.values())
     792            for inline_formset in inline_formsets:
     793                self.extend(inline_formset.non_form_errors())
     794                for errors_in_inline_form in inline_formset.errors:
     795                    self.extend(errors_in_inline_form.values())
  • django/django/contrib/admin/views/main.py

     
    66from django.db.models.query import QuerySet
    77from django.utils.encoding import force_unicode, smart_str
    88from django.utils.translation import ugettext
    9 from django.utils.safestring import mark_safe
    109from django.utils.http import urlencode
    1110import operator
    1211
  • django/django/contrib/admin/widgets.py

     
    1 """
    2 Form Widget classes specific to the Django admin site.
    3 """
    4 
    5 import copy
    6 
    7 from django import forms
    8 from django.forms.widgets import RadioFieldRenderer
    9 from django.forms.util import flatatt
    10 from django.utils.datastructures import MultiValueDict
    11 from django.utils.text import capfirst, truncate_words
    12 from django.utils.translation import ugettext as _
    13 from django.utils.safestring import mark_safe
    14 from django.utils.encoding import force_unicode
    15 from django.conf import settings
    16 
    17 class FilteredSelectMultiple(forms.SelectMultiple):
    18     """
    19     A SelectMultiple with a JavaScript filter interface.
    20 
    21     Note that the resulting JavaScript assumes that the SelectFilter2.js
    22     library and its dependencies have been loaded in the HTML page.
    23     """
    24     def __init__(self, verbose_name, is_stacked, attrs=None, choices=()):
    25         self.verbose_name = verbose_name
    26         self.is_stacked = is_stacked
    27         super(FilteredSelectMultiple, self).__init__(attrs, choices)
    28 
    29     def render(self, name, value, attrs=None, choices=()):
    30         output = [super(FilteredSelectMultiple, self).render(name, value, attrs, choices)]
    31         output.append(u'<script type="text/javascript">addEvent(window, "load", function(e) {')
    32         # TODO: "id_" is hard-coded here. This should instead use the correct
    33         # API to determine the ID dynamically.
    34         output.append(u'SelectFilter.init("id_%s", "%s", %s, "%s"); });</script>\n' % \
    35             (name, self.verbose_name.replace('"', '\\"'), int(self.is_stacked), settings.ADMIN_MEDIA_PREFIX))
    36         return mark_safe(u''.join(output))
    37 
    38 class AdminDateWidget(forms.TextInput):
    39     class Media:
    40         js = (settings.ADMIN_MEDIA_PREFIX + "js/calendar.js",
    41               settings.ADMIN_MEDIA_PREFIX + "js/admin/DateTimeShortcuts.js")
    42        
    43     def __init__(self, attrs={}):
    44         super(AdminDateWidget, self).__init__(attrs={'class': 'vDateField', 'size': '10'})
    45 
    46 class AdminTimeWidget(forms.TextInput):
    47     class Media:
    48         js = (settings.ADMIN_MEDIA_PREFIX + "js/calendar.js",
    49               settings.ADMIN_MEDIA_PREFIX + "js/admin/DateTimeShortcuts.js")
    50 
    51     def __init__(self, attrs={}):
    52         super(AdminTimeWidget, self).__init__(attrs={'class': 'vTimeField', 'size': '8'})
    53    
    54 class AdminSplitDateTime(forms.SplitDateTimeWidget):
    55     """
    56     A SplitDateTime Widget that has some admin-specific styling.
    57     """
    58     def __init__(self, attrs=None):
    59         widgets = [AdminDateWidget, AdminTimeWidget]
    60         # Note that we're calling MultiWidget, not SplitDateTimeWidget, because
    61         # we want to define widgets.
    62         forms.MultiWidget.__init__(self, widgets, attrs)
    63 
    64     def format_output(self, rendered_widgets):
    65         return mark_safe(u'<p class="datetime">%s %s<br />%s %s</p>' % \
    66             (_('Date:'), rendered_widgets[0], _('Time:'), rendered_widgets[1]))
    67 
    68 class AdminRadioFieldRenderer(RadioFieldRenderer):
    69     def render(self):
    70         """Outputs a <ul> for this set of radio fields."""
    71         return mark_safe(u'<ul%s>\n%s\n</ul>' % (
    72             flatatt(self.attrs),
    73             u'\n'.join([u'<li>%s</li>' % force_unicode(w) for w in self]))
    74         )
    75 
    76 class AdminRadioSelect(forms.RadioSelect):
    77     renderer = AdminRadioFieldRenderer
    78 
    79 class AdminFileWidget(forms.FileInput):
    80     """
    81     A FileField Widget that shows its current value if it has one.
    82     """
    83     def __init__(self, attrs={}):
    84         super(AdminFileWidget, self).__init__(attrs)
    85        
    86     def render(self, name, value, attrs=None):
    87         output = []
    88         if value:
    89             output.append('%s <a target="_blank" href="%s%s">%s</a> <br />%s ' % \
    90                 (_('Currently:'), settings.MEDIA_URL, value, value, _('Change:')))
    91         output.append(super(AdminFileWidget, self).render(name, value, attrs))
    92         return mark_safe(u''.join(output))
    93 
    94 class ForeignKeyRawIdWidget(forms.TextInput):
    95     """
    96     A Widget for displaying ForeignKeys in the "raw_id" interface rather than
    97     in a <select> box.
    98     """
    99     def __init__(self, rel, attrs=None):
    100         self.rel = rel
    101         super(ForeignKeyRawIdWidget, self).__init__(attrs)
    102 
    103     def render(self, name, value, attrs=None):
    104         related_url = '../../../%s/%s/' % (self.rel.to._meta.app_label, self.rel.to._meta.object_name.lower())
    105         if self.rel.limit_choices_to:
    106             url = '?' + '&amp;'.join(['%s=%s' % (k, v) for k, v in self.rel.limit_choices_to.items()])
    107         else:
    108             url = ''
    109         if not attrs.has_key('class'):
    110           attrs['class'] = 'vForeignKeyRawIdAdminField' # The JavaScript looks for this hook.
    111         output = [super(ForeignKeyRawIdWidget, self).render(name, value, attrs)]
    112         # TODO: "id_" is hard-coded here. This should instead use the correct
    113         # API to determine the ID dynamically.
    114         output.append('<a href="%s%s" class="related-lookup" id="lookup_id_%s" onclick="return showRelatedObjectLookupPopup(this);"> ' % \
    115             (related_url, url, name))
    116         output.append('<img src="%simg/admin/selector-search.gif" width="16" height="16" alt="Lookup" /></a>' % settings.ADMIN_MEDIA_PREFIX)
    117         if value:
    118             output.append(self.label_for_value(value))
    119         return mark_safe(u''.join(output))
    120    
    121     def label_for_value(self, value):
    122         return '&nbsp;<strong>%s</strong>' % \
    123             truncate_words(self.rel.to.objects.get(pk=value), 14)
    124            
    125 class ManyToManyRawIdWidget(ForeignKeyRawIdWidget):
    126     """
    127     A Widget for displaying ManyToMany ids in the "raw_id" interface rather than
    128     in a <select multiple> box.
    129     """
    130     def __init__(self, rel, attrs=None):
    131         super(ManyToManyRawIdWidget, self).__init__(rel, attrs)
    132    
    133     def render(self, name, value, attrs=None):
    134         attrs['class'] = 'vManyToManyRawIdAdminField'
    135         if value:
    136             value = ','.join([str(v) for v in value])
    137         else:
    138             value = ''
    139         return super(ManyToManyRawIdWidget, self).render(name, value, attrs)
    140    
    141     def label_for_value(self, value):
    142         return ''
    143 
    144     def value_from_datadict(self, data, files, name):
    145         value = data.get(name, None)
    146         if value and ',' in value:
    147             return data[name].split(',')
    148         if value:
    149             return [value]
    150         return None
    151    
    152     def _has_changed(self, initial, data):
    153         if initial is None:
    154             initial = []
    155         if data is None:
    156             data = []
    157         if len(initial) != len(data):
    158             return True
    159         for pk1, pk2 in zip(initial, data):
    160             if force_unicode(pk1) != force_unicode(pk2):
    161                 return True
    162         return False
    163 
    164 class RelatedFieldWidgetWrapper(forms.Widget):
    165     """
    166     This class is a wrapper to a given widget to add the add icon for the
    167     admin interface.
    168     """
    169     def __init__(self, widget, rel, admin_site):
    170         self.is_hidden = widget.is_hidden
    171         self.needs_multipart_form = widget.needs_multipart_form
    172         self.attrs = widget.attrs
    173         self.choices = widget.choices
    174         self.widget = widget
    175         self.rel = rel
    176         # so we can check if the related object is registered with this AdminSite
    177         self.admin_site = admin_site
    178 
    179     def __deepcopy__(self, memo):
    180         obj = copy.copy(self)
    181         obj.widget = copy.deepcopy(self.widget, memo)
    182         obj.attrs = self.widget.attrs
    183         memo[id(self)] = obj
    184         return obj
    185 
    186     def render(self, name, value, *args, **kwargs):
    187         rel_to = self.rel.to
    188         related_url = '../../../%s/%s/' % (rel_to._meta.app_label, rel_to._meta.object_name.lower())
    189         self.widget.choices = self.choices
    190         output = [self.widget.render(name, value, *args, **kwargs)]
    191         if rel_to in self.admin_site._registry: # If the related object has an admin interface:
    192             # TODO: "id_" is hard-coded here. This should instead use the correct
    193             # API to determine the ID dynamically.
    194             output.append(u'<a href="%sadd/" class="add-another" id="add_id_%s" onclick="return showAddAnotherPopup(this);"> ' % \
    195                 (related_url, name))
    196             output.append(u'<img src="%simg/admin/icon_addlink.gif" width="10" height="10" alt="Add Another"/></a>' % settings.ADMIN_MEDIA_PREFIX)
    197         return mark_safe(u''.join(output))
    198 
    199     def build_attrs(self, extra_attrs=None, **kwargs):
    200         "Helper function for building an attribute dictionary."
    201         self.attrs = self.widget.build_attrs(extra_attrs=None, **kwargs)
    202         return self.attrs
    203 
    204     def value_from_datadict(self, data, files, name):
    205         return self.widget.value_from_datadict(data, files, name)
    206 
    207     def _has_changed(self, initial, data):
    208         return self.widget._has_changed(initial, data)
    209 
    210     def id_for_label(self, id_):
    211         return self.widget.id_for_label(id_)
     1"""
     2Form Widget classes specific to the Django admin site.
     3"""
     4
     5import copy
     6
     7from django import forms
     8from django.forms.widgets import RadioFieldRenderer
     9from django.forms.util import flatatt
     10from django.utils.text import truncate_words
     11from django.utils.translation import ugettext as _
     12from django.utils.safestring import mark_safe
     13from django.utils.encoding import force_unicode
     14from django.conf import settings
     15
     16class FilteredSelectMultiple(forms.SelectMultiple):
     17    """
     18    A SelectMultiple with a JavaScript filter interface.
     19
     20    Note that the resulting JavaScript assumes that the SelectFilter2.js
     21    library and its dependencies have been loaded in the HTML page.
     22    """
     23    def __init__(self, verbose_name, is_stacked, attrs=None, choices=()):
     24        self.verbose_name = verbose_name
     25        self.is_stacked = is_stacked
     26        super(FilteredSelectMultiple, self).__init__(attrs, choices)
     27
     28    def render(self, name, value, attrs=None, choices=()):
     29        output = [super(FilteredSelectMultiple, self).render(name, value, attrs, choices)]
     30        output.append(u'<script type="text/javascript">addEvent(window, "load", function(e) {')
     31        # TODO: "id_" is hard-coded here. This should instead use the correct
     32        # API to determine the ID dynamically.
     33        output.append(u'SelectFilter.init("id_%s", "%s", %s, "%s"); });</script>\n' % \
     34            (name, self.verbose_name.replace('"', '\\"'), int(self.is_stacked), settings.ADMIN_MEDIA_PREFIX))
     35        return mark_safe(u''.join(output))
     36
     37class AdminDateWidget(forms.TextInput):
     38    class Media:
     39        js = (settings.ADMIN_MEDIA_PREFIX + "js/calendar.js",
     40              settings.ADMIN_MEDIA_PREFIX + "js/admin/DateTimeShortcuts.js")
     41       
     42    def __init__(self, attrs={}):
     43        super(AdminDateWidget, self).__init__(attrs={'class': 'vDateField', 'size': '10'})
     44
     45class AdminTimeWidget(forms.TextInput):
     46    class Media:
     47        js = (settings.ADMIN_MEDIA_PREFIX + "js/calendar.js",
     48              settings.ADMIN_MEDIA_PREFIX + "js/admin/DateTimeShortcuts.js")
     49
     50    def __init__(self, attrs={}):
     51        super(AdminTimeWidget, self).__init__(attrs={'class': 'vTimeField', 'size': '8'})
     52   
     53class AdminSplitDateTime(forms.SplitDateTimeWidget):
     54    """
     55    A SplitDateTime Widget that has some admin-specific styling.
     56    """
     57    def __init__(self, attrs=None):
     58        widgets = [AdminDateWidget, AdminTimeWidget]
     59        # Note that we're calling MultiWidget, not SplitDateTimeWidget, because
     60        # we want to define widgets.
     61        forms.MultiWidget.__init__(self, widgets, attrs)
     62
     63    def format_output(self, rendered_widgets):
     64        return mark_safe(u'<p class="datetime">%s %s<br />%s %s</p>' % \
     65            (_('Date:'), rendered_widgets[0], _('Time:'), rendered_widgets[1]))
     66
     67class AdminRadioFieldRenderer(RadioFieldRenderer):
     68    def render(self):
     69        """Outputs a <ul> for this set of radio fields."""
     70        return mark_safe(u'<ul%s>\n%s\n</ul>' % (
     71            flatatt(self.attrs),
     72            u'\n'.join([u'<li>%s</li>' % force_unicode(w) for w in self]))
     73        )
     74
     75class AdminRadioSelect(forms.RadioSelect):
     76    renderer = AdminRadioFieldRenderer
     77
     78class AdminFileWidget(forms.FileInput):
     79    """
     80    A FileField Widget that shows its current value if it has one.
     81    """
     82    def __init__(self, attrs={}):
     83        super(AdminFileWidget, self).__init__(attrs)
     84       
     85    def render(self, name, value, attrs=None):
     86        output = []
     87        if value:
     88            output.append('%s <a target="_blank" href="%s%s">%s</a> <br />%s ' % \
     89                (_('Currently:'), settings.MEDIA_URL, value, value, _('Change:')))
     90        output.append(super(AdminFileWidget, self).render(name, value, attrs))
     91        return mark_safe(u''.join(output))
     92
     93class ForeignKeyRawIdWidget(forms.TextInput):
     94    """
     95    A Widget for displaying ForeignKeys in the "raw_id" interface rather than
     96    in a <select> box.
     97    """
     98    def __init__(self, rel, attrs=None):
     99        self.rel = rel
     100        super(ForeignKeyRawIdWidget, self).__init__(attrs)
     101
     102    def render(self, name, value, attrs=None):
     103        related_url = '../../../%s/%s/' % (self.rel.to._meta.app_label, self.rel.to._meta.object_name.lower())
     104        if self.rel.limit_choices_to:
     105            url = '?' + '&amp;'.join(['%s=%s' % (k, v) for k, v in self.rel.limit_choices_to.items()])
     106        else:
     107            url = ''
     108        if not attrs.has_key('class'):
     109          attrs['class'] = 'vForeignKeyRawIdAdminField' # The JavaScript looks for this hook.
     110        output = [super(ForeignKeyRawIdWidget, self).render(name, value, attrs)]
     111        # TODO: "id_" is hard-coded here. This should instead use the correct
     112        # API to determine the ID dynamically.
     113        output.append('<a href="%s%s" class="related-lookup" id="lookup_id_%s" onclick="return showRelatedObjectLookupPopup(this);"> ' % \
     114            (related_url, url, name))
     115        output.append('<img src="%simg/admin/selector-search.gif" width="16" height="16" alt="Lookup" /></a>' % settings.ADMIN_MEDIA_PREFIX)
     116        if value:
     117            output.append(self.label_for_value(value))
     118        return mark_safe(u''.join(output))
     119   
     120    def label_for_value(self, value):
     121        return '&nbsp;<strong>%s</strong>' % \
     122            truncate_words(self.rel.to.objects.get(pk=value), 14)
     123           
     124class ManyToManyRawIdWidget(ForeignKeyRawIdWidget):
     125    """
     126    A Widget for displaying ManyToMany ids in the "raw_id" interface rather than
     127    in a <select multiple> box.
     128    """
     129    def __init__(self, rel, attrs=None):
     130        super(ManyToManyRawIdWidget, self).__init__(rel, attrs)
     131   
     132    def render(self, name, value, attrs=None):
     133        attrs['class'] = 'vManyToManyRawIdAdminField'
     134        if value:
     135            value = ','.join([str(v) for v in value])
     136        else:
     137            value = ''
     138        return super(ManyToManyRawIdWidget, self).render(name, value, attrs)
     139   
     140    def label_for_value(self, value):
     141        return ''
     142
     143    def value_from_datadict(self, data, files, name):
     144        value = data.get(name, None)
     145        if value and ',' in value:
     146            return data[name].split(',')
     147        if value:
     148            return [value]
     149        return None
     150   
     151    def _has_changed(self, initial, data):
     152        if initial is None:
     153            initial = []
     154        if data is None:
     155            data = []
     156        if len(initial) != len(data):
     157            return True
     158        for pk1, pk2 in zip(initial, data):
     159            if force_unicode(pk1) != force_unicode(pk2):
     160                return True
     161        return False
     162
     163class RelatedFieldWidgetWrapper(forms.Widget):
     164    """
     165    This class is a wrapper to a given widget to add the add icon for the
     166    admin interface.
     167    """
     168    def __init__(self, widget, rel, admin_site):
     169        self.is_hidden = widget.is_hidden
     170        self.needs_multipart_form = widget.needs_multipart_form
     171        self.attrs = widget.attrs
     172        self.choices = widget.choices
     173        self.widget = widget
     174        self.rel = rel
     175        # so we can check if the related object is registered with this AdminSite
     176        self.admin_site = admin_site
     177
     178    def __deepcopy__(self, memo):
     179        obj = copy.copy(self)
     180        obj.widget = copy.deepcopy(self.widget, memo)
     181        obj.attrs = self.widget.attrs
     182        memo[id(self)] = obj
     183        return obj
     184
     185    def render(self, name, value, *args, **kwargs):
     186        rel_to = self.rel.to
     187        related_url = '../../../%s/%s/' % (rel_to._meta.app_label, rel_to._meta.object_name.lower())
     188        self.widget.choices = self.choices
     189        output = [self.widget.render(name, value, *args, **kwargs)]
     190        if rel_to in self.admin_site._registry: # If the related object has an admin interface:
     191            # TODO: "id_" is hard-coded here. This should instead use the correct
     192            # API to determine the ID dynamically.
     193            output.append(u'<a href="%sadd/" class="add-another" id="add_id_%s" onclick="return showAddAnotherPopup(this);"> ' % \
     194                (related_url, name))
     195            output.append(u'<img src="%simg/admin/icon_addlink.gif" width="10" height="10" alt="Add Another"/></a>' % settings.ADMIN_MEDIA_PREFIX)
     196        return mark_safe(u''.join(output))
     197
     198    def build_attrs(self, extra_attrs=None, **kwargs):
     199        "Helper function for building an attribute dictionary."
     200        self.attrs = self.widget.build_attrs(extra_attrs=None, **kwargs)
     201        return self.attrs
     202
     203    def value_from_datadict(self, data, files, name):
     204        return self.widget.value_from_datadict(data, files, name)
     205
     206    def _has_changed(self, initial, data):
     207        return self.widget._has_changed(initial, data)
     208
     209    def id_for_label(self, id_):
     210        return self.widget.id_for_label(id_)
  • django/django/contrib/databrowse/plugins/calendars.py

     
    44from django.contrib.databrowse.sites import DatabrowsePlugin
    55from django.shortcuts import render_to_response
    66from django.utils.text import capfirst
    7 from django.utils.translation import get_date_formats
    87from django.utils.encoding import force_unicode
    98from django.utils.safestring import mark_safe
    109from django.views.generic import date_based
  • django/django/contrib/databrowse/plugins/fieldchoices.py

     
    66from django.utils.text import capfirst
    77from django.utils.encoding import smart_str, force_unicode
    88from django.utils.safestring import mark_safe
    9 from django.views.generic import date_based
    109import urllib
    1110
    1211class FieldChoicePlugin(DatabrowsePlugin):
  • django/django/contrib/databrowse/views.py

     
    1 from django.db.models import FieldDoesNotExist, DateTimeField
    21from django.http import Http404
    32from django.shortcuts import render_to_response
    4 from django.contrib.databrowse.datastructures import EasyModel, EasyChoice
    53
    64###########
    75# CHOICES #
  • django/django/contrib/databrowse/sites.py

     
    11from django import http
    22from django.db import models
    3 from django.contrib.databrowse.datastructures import EasyModel, EasyChoice
     3from django.contrib.databrowse.datastructures import EasyModel
    44from django.shortcuts import render_to_response
    55from django.utils.safestring import mark_safe
    66
  • django/django/contrib/auth/admin.py

     
    1 from django.contrib.auth.models import User, Group
    2 from django.core.exceptions import PermissionDenied
    3 from django import oldforms, template
    4 from django.shortcuts import render_to_response
    5 from django.http import HttpResponseRedirect
    6 from django.utils.translation import ugettext, ugettext_lazy as _
    7 from django.contrib import admin
    8 
    9 class GroupAdmin(admin.ModelAdmin):
    10     search_fields = ('name',)
    11     ordering = ('name',)
    12     filter_horizontal = ('permissions',)
    13 
    14 class UserAdmin(admin.ModelAdmin):
    15     fieldsets = (
    16         (None, {'fields': ('username', 'password')}),
    17         (_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
    18         (_('Permissions'), {'fields': ('is_staff', 'is_active', 'is_superuser', 'user_permissions')}),
    19         (_('Important dates'), {'fields': ('last_login', 'date_joined')}),
    20         (_('Groups'), {'fields': ('groups',)}),
    21     )
    22     list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff')
    23     list_filter = ('is_staff', 'is_superuser')
    24     search_fields = ('username', 'first_name', 'last_name', 'email')
    25     ordering = ('username',)
    26     filter_horizontal = ('user_permissions',)
    27 
    28     def add_view(self, request):
    29         # avoid a circular import. see #6718.
    30         from django.contrib.auth.forms import UserCreationForm
    31         if not self.has_change_permission(request):
    32             raise PermissionDenied
    33         if request.method == 'POST':
    34             form = UserCreationForm(request.POST)
    35             if form.is_valid():
    36                 new_user = form.save()
    37                 msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': 'user', 'obj': new_user}
    38                 if "_addanother" in request.POST:
    39                     request.user.message_set.create(message=msg)
    40                     return HttpResponseRedirect(request.path)
    41                 else:
    42                     request.user.message_set.create(message=msg + ' ' + ugettext("You may edit it again below."))
    43                     return HttpResponseRedirect('../%s/' % new_user.id)
    44         else:
    45             form = UserCreationForm()
    46         return render_to_response('admin/auth/user/add_form.html', {
    47             'title': _('Add user'),
    48             'form': form,
    49             'is_popup': '_popup' in request.REQUEST,
    50             'add': True,
    51             'change': False,
    52             'has_add_permission': True,
    53             'has_delete_permission': False,
    54             'has_change_permission': True,
    55             'has_file_field': False,
    56             'has_absolute_url': False,
    57             'auto_populated_fields': (),
    58             'opts': User._meta,
    59             'save_as': False,
    60             'username_help_text': User._meta.get_field('username').help_text,
    61             'root_path': self.admin_site.root_path,
    62         }, context_instance=template.RequestContext(request))
    63 
    64 admin.site.register(Group, GroupAdmin)
    65 admin.site.register(User, UserAdmin)
    66 
     1from django.contrib.auth.models import User, Group
     2from django.core.exceptions import PermissionDenied
     3from django import template
     4from django.shortcuts import render_to_response
     5from django.http import HttpResponseRedirect
     6from django.utils.translation import ugettext, ugettext_lazy as _
     7from django.contrib import admin
     8
     9class GroupAdmin(admin.ModelAdmin):
     10    search_fields = ('name',)
     11    ordering = ('name',)
     12    filter_horizontal = ('permissions',)
     13
     14class UserAdmin(admin.ModelAdmin):
     15    fieldsets = (
     16        (None, {'fields': ('username', 'password')}),
     17        (_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
     18        (_('Permissions'), {'fields': ('is_staff', 'is_active', 'is_superuser', 'user_permissions')}),
     19        (_('Important dates'), {'fields': ('last_login', 'date_joined')}),
     20        (_('Groups'), {'fields': ('groups',)}),
     21    )
     22    list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff')
     23    list_filter = ('is_staff', 'is_superuser')
     24    search_fields = ('username', 'first_name', 'last_name', 'email')
     25    ordering = ('username',)
     26    filter_horizontal = ('user_permissions',)
     27
     28    def add_view(self, request):
     29        # avoid a circular import. see #6718.
     30        from django.contrib.auth.forms import UserCreationForm
     31        if not self.has_change_permission(request):
     32            raise PermissionDenied
     33        if request.method == 'POST':
     34            form = UserCreationForm(request.POST)
     35            if form.is_valid():
     36                new_user = form.save()
     37                msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': 'user', 'obj': new_user}
     38                if "_addanother" in request.POST:
     39                    request.user.message_set.create(message=msg)
     40                    return HttpResponseRedirect(request.path)
     41                else:
     42                    request.user.message_set.create(message=msg + ' ' + ugettext("You may edit it again below."))
     43                    return HttpResponseRedirect('../%s/' % new_user.id)
     44        else:
     45            form = UserCreationForm()
     46        return render_to_response('admin/auth/user/add_form.html', {
     47            'title': _('Add user'),
     48            'form': form,
     49            'is_popup': '_popup' in request.REQUEST,
     50            'add': True,
     51            'change': False,
     52            'has_add_permission': True,
     53            'has_delete_permission': False,
     54            'has_change_permission': True,
     55            'has_file_field': False,
     56            'has_absolute_url': False,
     57            'auto_populated_fields': (),
     58            'opts': User._meta,
     59            'save_as': False,
     60            'username_help_text': User._meta.get_field('username').help_text,
     61            'root_path': self.admin_site.root_path,
     62        }, context_instance=template.RequestContext(request))
     63
     64admin.site.register(Group, GroupAdmin)
     65admin.site.register(User, UserAdmin)
     66
  • django/django/contrib/auth/management/commands/createsuperuser.py

     
    1 """
    2 Management utility to create superusers.
    3 """
    4 
    5 import getpass
    6 import os
    7 import re
    8 import sys
    9 from optparse import make_option
    10 from django.contrib.auth.models import User, UNUSABLE_PASSWORD
    11 from django.core import validators
    12 from django.core.management.base import BaseCommand, CommandError
    13 
    14 RE_VALID_USERNAME = re.compile('\w+$')
    15 
    16 class Command(BaseCommand):
    17     option_list = BaseCommand.option_list + (
    18         make_option('--username', dest='username', default=None,
    19             help='Specifies the username for the superuser.'),
    20         make_option('--email', dest='email', default=None,
    21             help='Specifies the email address for the superuser.'),
    22         make_option('--noinput', action='store_false', dest='interactive', default=True,
    23             help='Tells Django to NOT prompt the user for input of any kind. '    \
    24                  'You must use --username and --email with --noinput, and '      \
    25                  'superusers created with --noinput will not be able to log in '  \
    26                  'until they\'re given a valid password.'),
    27     )
    28     help = 'Used to create a superuser.'
    29 
    30     def handle(self, *args, **options):
    31         username = options.get('username', None)
    32         email = options.get('email', None)
    33         interactive = options.get('interactive')
    34        
    35         # Do quick and dirty validation if --noinput
    36         if not interactive:
    37             if not username or not email:
    38                 raise CommandError("You must use --username and --email with --noinput.")
    39             if not RE_VALID_USERNAME.match(username):
    40                 raise CommandError("Invalid username. Use only letters, digits, and underscores")
    41             try:
    42                 validators.isValidEmail(email, None)
    43             except validators.ValidationError:
    44                 raise CommandError("Invalid email address.")
    45 
    46         password = ''
    47 
    48         # Try to determine the current system user's username to use as a default.
    49         try:
    50             import pwd
    51         except ImportError:
    52             default_username = ''
    53         else:
    54             default_username = pwd.getpwuid(os.getuid())[0].replace(' ', '').lower()
    55 
    56         # Determine whether the default username is taken, so we don't display
    57         # it as an option.
    58         if default_username:
    59             try:
    60                 User.objects.get(username=default_username)
    61             except User.DoesNotExist:
    62                 pass
    63             else:
    64                 default_username = ''
    65 
    66         # Prompt for username/email/password. Enclose this whole thing in a
    67         # try/except to trap for a keyboard interrupt and exit gracefully.
    68         if interactive:
    69             try:
    70            
    71                 # Get a username
    72                 while 1:
    73                     if not username:
    74                         input_msg = 'Username'
    75                         if default_username:
    76                             input_msg += ' (Leave blank to use %r)' % default_username
    77                         username = raw_input(input_msg + ': ')
    78                     if default_username and username == '':
    79                         username = default_username
    80                     if not RE_VALID_USERNAME.match(username):
    81                         sys.stderr.write("Error: That username is invalid. Use only letters, digits and underscores.\n")
    82                         username = None
    83                         continue
    84                     try:
    85                         User.objects.get(username=username)
    86                     except User.DoesNotExist:
    87                         break
    88                     else:
    89                         sys.stderr.write("Error: That username is already taken.\n")
    90                         username = None
    91            
    92                 # Get an email
    93                 while 1:
    94                     if not email:
    95                         email = raw_input('E-mail address: ')
    96                     try:
    97                         validators.isValidEmail(email, None)
    98                     except validators.ValidationError:
    99                         sys.stderr.write("Error: That e-mail address is invalid.\n")
    100                         email = None
    101                     else:
    102                         break
    103            
    104                 # Get a password
    105                 while 1:
    106                     if not password:
    107                         password = getpass.getpass()
    108                         password2 = getpass.getpass('Password (again): ')
    109                         if password != password2:
    110                             sys.stderr.write("Error: Your passwords didn't match.\n")
    111                             password = None
    112                             continue
    113                     if password.strip() == '':
    114                         sys.stderr.write("Error: Blank passwords aren't allowed.\n")
    115                         password = None
    116                         continue
    117                     break
    118             except KeyboardInterrupt:
    119                 sys.stderr.write("\nOperation cancelled.\n")
    120                 sys.exit(1)
    121        
    122         User.objects.create_superuser(username, email, password)
    123         print "Superuser created successfully."
     1"""
     2Management utility to create superusers.
     3"""
     4
     5import getpass
     6import os
     7import re
     8import sys
     9from optparse import make_option
     10from django.contrib.auth.models import User
     11from django.core import validators
     12from django.core.management.base import BaseCommand, CommandError
     13
     14RE_VALID_USERNAME = re.compile('\w+$')
     15
     16class Command(BaseCommand):
     17    option_list = BaseCommand.option_list + (
     18        make_option('--username', dest='username', default=None,
     19            help='Specifies the username for the superuser.'),
     20        make_option('--email', dest='email', default=None,
     21            help='Specifies the email address for the superuser.'),
     22        make_option('--noinput', action='store_false', dest='interactive', default=True,
     23            help='Tells Django to NOT prompt the user for input of any kind. '    \
     24                 'You must use --username and --email with --noinput, and '      \
     25                 'superusers created with --noinput will not be able to log in '  \
     26                 'until they\'re given a valid password.'),
     27    )
     28    help = 'Used to create a superuser.'
     29
     30    def handle(self, *args, **options):
     31        username = options.get('username', None)
     32        email = options.get('email', None)
     33        interactive = options.get('interactive')
     34       
     35        # Do quick and dirty validation if --noinput
     36        if not interactive:
     37            if not username or not email:
     38                raise CommandError("You must use --username and --email with --noinput.")
     39            if not RE_VALID_USERNAME.match(username):
     40                raise CommandError("Invalid username. Use only letters, digits, and underscores")
     41            try:
     42                validators.isValidEmail(email, None)
     43            except validators.ValidationError:
     44                raise CommandError("Invalid email address.")
     45
     46        password = ''
     47
     48        # Try to determine the current system user's username to use as a default.
     49        try:
     50            import pwd
     51        except ImportError:
     52            default_username = ''
     53        else:
     54            default_username = pwd.getpwuid(os.getuid())[0].replace(' ', '').lower()
     55
     56        # Determine whether the default username is taken, so we don't display
     57        # it as an option.
     58        if default_username:
     59            try:
     60                User.objects.get(username=default_username)
     61            except User.DoesNotExist:
     62                pass
     63            else:
     64                default_username = ''
     65
     66        # Prompt for username/email/password. Enclose this whole thing in a
     67        # try/except to trap for a keyboard interrupt and exit gracefully.
     68        if interactive:
     69            try:
     70           
     71                # Get a username
     72                while 1:
     73                    if not username:
     74                        input_msg = 'Username'
     75                        if default_username:
     76                            input_msg += ' (Leave blank to use %r)' % default_username
     77                        username = raw_input(input_msg + ': ')
     78                    if default_username and username == '':
     79                        username = default_username
     80                    if not RE_VALID_USERNAME.match(username):
     81                        sys.stderr.write("Error: That username is invalid. Use only letters, digits and underscores.\n")
     82                        username = None
     83                        continue
     84                    try:
     85                        User.objects.get(username=username)
     86                    except User.DoesNotExist:
     87                        break
     88                    else:
     89                        sys.stderr.write("Error: That username is already taken.\n")
     90                        username = None
     91           
     92                # Get an email
     93                while 1:
     94                    if not email:
     95                        email = raw_input('E-mail address: ')
     96                    try:
     97                        validators.isValidEmail(email, None)
     98                    except validators.ValidationError:
     99                        sys.stderr.write("Error: That e-mail address is invalid.\n")
     100                        email = None
     101                    else:
     102                        break
     103           
     104                # Get a password
     105                while 1:
     106                    if not password:
     107                        password = getpass.getpass()
     108                        password2 = getpass.getpass('Password (again): ')
     109                        if password != password2:
     110                            sys.stderr.write("Error: Your passwords didn't match.\n")
     111                            password = None
     112                            continue
     113                    if password.strip() == '':
     114                        sys.stderr.write("Error: Blank passwords aren't allowed.\n")
     115                        password = None
     116                        continue
     117                    break
     118            except KeyboardInterrupt:
     119                sys.stderr.write("\nOperation cancelled.\n")
     120                sys.exit(1)
     121       
     122        User.objects.create_superuser(username, email, password)
     123        print "Superuser created successfully."
  • django/django/contrib/auth/decorators.py

     
    11try:
    22    from functools import wraps, update_wrapper
    33except ImportError:
    4     from django.utils.functional import wraps, update_wrapper  # Python 2.3, 2.4 fallback.
     4    from django.utils.functional import update_wrapper  # Python 2.3, 2.4 fallback.
    55
    66from django.contrib.auth import REDIRECT_FIELD_NAME
    77from django.http import HttpResponseRedirect
  • django/django/contrib/auth/forms.py

     
    22from django.contrib.auth import authenticate
    33from django.contrib.sites.models import Site
    44from django.template import Context, loader
    5 from django.core import validators
    65from django import forms
    76from django.utils.translation import ugettext_lazy as _
    87
  • django/django/contrib/admindocs/views.py

     
    55from django.db import models
    66from django.shortcuts import render_to_response
    77from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
    8 from django.http import Http404, get_host
     8from django.http import Http404
    99from django.core import urlresolvers
    1010from django.contrib.admindocs import utils
    1111from django.contrib.sites.models import Site
  • django/django/contrib/sessions/backends/cache.py

     
    1 from django.conf import settings
    21from django.contrib.sessions.backends.base import SessionBase
    32from django.core.cache import cache
    43
  • django/django/contrib/sessions/backends/db.py

     
    11import datetime
    22
    3 from django.conf import settings
    43from django.contrib.sessions.models import Session
    54from django.contrib.sessions.backends.base import SessionBase
    65from django.core.exceptions import SuspiciousOperation
  • django/django/utils/dateformat.py

     
    1313
    1414from django.utils.dates import MONTHS, MONTHS_3, MONTHS_AP, WEEKDAYS, WEEKDAYS_ABBR
    1515from django.utils.tzinfo import LocalTimezone
    16 from django.utils.translation import string_concat, ugettext as _
     16from django.utils.translation import ugettext as _
    1717from django.utils.encoding import force_unicode
    1818from calendar import isleap, monthrange
    1919import re, time
  • django/django/utils/encoding.py

     
    33import datetime
    44
    55from django.utils.functional import Promise
    6 from django.utils.safestring import SafeData, mark_safe
    76
    87class DjangoUnicodeDecodeError(UnicodeDecodeError):
    98    def __init__(self, obj, *args):
Back to Top