telemeta.admin module
# -*- coding: utf-8 -*- from telemeta.models import * from django.contrib import admin from django.contrib.auth.models import User from django.contrib.auth.admin import UserAdmin admin.site.unregister(User) class MediaFondsAdmin(admin.ModelAdmin): search_fields = ['title', 'code'] ordering = ['code'] filter_horizontal = ['children'] class MediaCorpusAdmin(admin.ModelAdmin): search_fields = ['title', 'code'] ordering = ['code'] filter_horizontal = ['children'] class MediaCollectionRelatedInline(admin.StackedInline): model = MediaCollectionRelated class MediaCollectionIdentifierInline(admin.StackedInline): model = MediaCollectionIdentifier max_num = 1 class MediaCollectionAdmin(admin.ModelAdmin): search_fields = ['title', 'code'] ordering = ['code'] inlines = [MediaCollectionIdentifierInline, MediaCollectionRelatedInline] class MediaItemRelatedInline(admin.StackedInline): model = MediaItemRelated class MediaItemMarkerInline(admin.StackedInline): model = MediaItemMarker class MediaItemTranscodedInline(admin.StackedInline): model = MediaItemTranscoded class MediaItemIdentifierInline(admin.StackedInline): model = MediaItemIdentifier max_num = 1 class MediaItemAdmin(admin.ModelAdmin): search_fields = ['title', 'code'] ordering = ['code'] exclude = ('copied_from_item', ) inlines = [MediaItemIdentifierInline, MediaItemRelatedInline, MediaItemTranscodedInline, MediaItemMarkerInline] class MediaPartAdmin(admin.ModelAdmin): search_fields = ['title', 'item__code'] ordering = ['title'] class InstrumentAdmin(admin.ModelAdmin): search_fields = ['name'] ordering = ['name'] class InstrumentAliasAdmin(admin.ModelAdmin): search_fields = ['name'] ordering = ['name'] class InstrumentRelationAdmin(admin.ModelAdmin): search_fields = ['instrument__name', 'parent_instrument__name'] ordering = ['parent_instrument__name'] class InstrumentAliasRelationAdmin(admin.ModelAdmin): search_fields = ['alias__name', 'instrument__name'] ordering = ['alias__name'] class LocationAdmin(admin.ModelAdmin): search_fields = ['name'] ordering = ['name'] class LocationAliasAdmin(admin.ModelAdmin): search_fields = ['location__name', 'alias'] ordering = ['alias'] class LocationRelationAdmin(admin.ModelAdmin): search_fields = ['location__name', 'ancestor_location__name'] ordering = ['ancestor_location__name'] class LanguageAdmin(admin.ModelAdmin): search_fields = ['name', 'identifier'] ordering = ['name'] class RevisionAdmin(admin.ModelAdmin): search_fields = ['element_id', 'user'] ordering = ['-time'] class FormatAdmin(admin.ModelAdmin): search_fields = ['original_code', 'tape_reference'] class UserProfileInline(admin.StackedInline): model = UserProfile class UserProfileAdmin(UserAdmin): inlines = [UserProfileInline] class PlaylistAdmin(admin.ModelAdmin): search_fields = ['title', 'public_id'] class EnumerationPropertyAdmin(admin.ModelAdmin): list_display = ['enumeration_name', 'is_admin', 'is_hidden'] admin.site.register(MediaFonds, MediaFondsAdmin) admin.site.register(MediaCorpus, MediaCorpusAdmin) admin.site.register(MediaCollection, MediaCollectionAdmin) admin.site.register(MediaItem, MediaItemAdmin) admin.site.register(MediaPart, MediaPartAdmin) admin.site.register(Instrument, InstrumentAdmin) admin.site.register(InstrumentAlias, InstrumentAliasAdmin) admin.site.register(InstrumentRelation, InstrumentRelationAdmin) admin.site.register(InstrumentAliasRelation, InstrumentAliasRelationAdmin) admin.site.register(Location, LocationAdmin) admin.site.register(LocationType) admin.site.register(LocationAlias, LocationAliasAdmin) admin.site.register(LocationRelation, LocationRelationAdmin) admin.site.register(Language, LanguageAdmin) admin.site.register(Revision, RevisionAdmin) admin.site.register(Format, FormatAdmin) admin.site.register(User, UserProfileAdmin) admin.site.register(PublisherCollection) admin.site.register(Playlist, PlaylistAdmin) admin.site.register(EnumerationProperty, EnumerationPropertyAdmin)
Module variables
var ITEM_PUBLIC_ACCESS_CHOICES
var ITEM_TRANSODING_STATUS
var PUBLIC_ACCESS_CHOICES
var SCOPE_CHOICES
var TYPE_CHOICES
var app_name
var code_linesep
var collection_code_regex
var collection_published_code_regex
var collection_unpublished_code_regex
var default_decoding
var default_encoding
var engine
var eol
var ext
var item_code_regex
var item_published_code_regex
var item_unpublished_code_regex
var mime_type
var private_extra_types
var public_extra_types
var resource_code_regex
var strict_code
Classes
class EnumerationPropertyAdmin
class EnumerationPropertyAdmin(admin.ModelAdmin): list_display = ['enumeration_name', 'is_admin', 'is_hidden']
Ancestors (in MRO)
- EnumerationPropertyAdmin
- django.contrib.admin.options.ModelAdmin
- django.contrib.admin.options.BaseModelAdmin
- __builtin__.object
Class variables
var action_form
var actions
var actions_on_bottom
var actions_on_top
var actions_selection_counter
var add_form_template
var change_form_template
var change_list_template
var date_hierarchy
var delete_confirmation_template
var delete_selected_confirmation_template
var exclude
var fields
var fieldsets
var filter_horizontal
var filter_vertical
var form
var formfield_overrides
var inlines
var list_display
var list_display_links
var list_editable
var list_filter
var list_max_show_all
var list_per_page
var object_history_template
var ordering
var paginator
var prepopulated_fields
var preserve_filters
var radio_fields
var raw_id_fields
var readonly_fields
var save_as
var save_on_top
var search_fields
var validator_class
Instance variables
var declared_fieldsets
var media
var urls
Methods
def __init__(
self, model, admin_site)
def __init__(self, model, admin_site): self.model = model self.opts = model._meta self.admin_site = admin_site super(ModelAdmin, self).__init__()
def action_checkbox(
self, obj)
A list_display column containing a checkbox widget.
def action_checkbox(self, obj): """ A list_display column containing a checkbox widget. """ return helpers.checkbox.render(helpers.ACTION_CHECKBOX_NAME, force_text(obj.pk))
def add_view(
self, *args, **kwargs)
The 'add' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def change_view(
self, *args, **kwargs)
The 'change' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def changelist_view(
self, *args, **kwargs)
The 'change list' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def construct_change_message(
self, request, form, formsets)
Construct a change message from a changed object.
def construct_change_message(self, request, form, formsets): """ Construct a change message from a changed object. """ change_message = [] if form.changed_data: change_message.append(_('Changed %s.') % get_text_list(form.changed_data, _('and'))) if formsets: for formset in formsets: for added_object in formset.new_objects: change_message.append(_('Added %(name)s "%(object)s".') % {'name': force_text(added_object._meta.verbose_name), 'object': force_text(added_object)}) for changed_object, changed_fields in formset.changed_objects: change_message.append(_('Changed %(list)s for %(name)s "%(object)s".') % {'list': get_text_list(changed_fields, _('and')), 'name': force_text(changed_object._meta.verbose_name), 'object': force_text(changed_object)}) for deleted_object in formset.deleted_objects: change_message.append(_('Deleted %(name)s "%(object)s".') % {'name': force_text(deleted_object._meta.verbose_name), 'object': force_text(deleted_object)}) change_message = ' '.join(change_message) return change_message or _('No fields changed.')
def delete_model(
self, request, obj)
Given a model instance delete it from the database.
def delete_model(self, request, obj): """ Given a model instance delete it from the database. """ obj.delete()
def delete_view(
self, *args, **kwargs)
The 'delete' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def formfield_for_choice_field(
self, db_field, request=None, **kwargs)
Get a form Field for a database Field that has declared choices.
def formfield_for_choice_field(self, db_field, request=None, **kwargs): """ Get a form Field for a database Field that has declared choices. """ # If the field is named as a radio_field, use a RadioSelect if db_field.name in self.radio_fields: # Avoid stomping on custom widget/choices arguments. if 'widget' not in kwargs: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) if 'choices' not in kwargs: kwargs['choices'] = db_field.get_choices( include_blank=db_field.blank, blank_choice=[('', _('None'))] ) return db_field.formfield(**kwargs)
def formfield_for_dbfield(
self, db_field, **kwargs)
Hook for specifying the form Field instance for a given database Field instance.
If kwargs are given, they're passed to the form Field's constructor.
def formfield_for_dbfield(self, db_field, **kwargs): """ Hook for specifying the form Field instance for a given database Field instance. If kwargs are given, they're passed to the form Field's constructor. """ request = kwargs.pop("request", None) # If the field specifies choices, we don't need to look for special # admin widgets - we just need to use a select widget of some kind. if db_field.choices: return self.formfield_for_choice_field(db_field, request, **kwargs) # ForeignKey or ManyToManyFields if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)): # Combine the field kwargs with any options for formfield_overrides. # Make sure the passed in **kwargs override anything in # formfield_overrides because **kwargs is more specific, and should # always win. if db_field.__class__ in self.formfield_overrides: kwargs = dict(self.formfield_overrides[db_field.__class__], **kwargs) # Get the correct formfield. if isinstance(db_field, models.ForeignKey): formfield = self.formfield_for_foreignkey(db_field, request, **kwargs) elif isinstance(db_field, models.ManyToManyField): formfield = self.formfield_for_manytomany(db_field, request, **kwargs) # For non-raw_id fields, wrap the widget with a wrapper that adds # extra HTML -- the "add other" interface -- to the end of the # rendered output. formfield can be None if it came from a # OneToOneField with parent_link=True or a M2M intermediary. if formfield and db_field.name not in self.raw_id_fields: related_modeladmin = self.admin_site._registry.get( db_field.rel.to) can_add_related = bool(related_modeladmin and related_modeladmin.has_add_permission(request)) formfield.widget = widgets.RelatedFieldWidgetWrapper( formfield.widget, db_field.rel, self.admin_site, can_add_related=can_add_related) return formfield # If we've got overrides for the formfield defined, use 'em. **kwargs # passed to formfield_for_dbfield override the defaults. for klass in db_field.__class__.mro(): if klass in self.formfield_overrides: kwargs = dict(copy.deepcopy(self.formfield_overrides[klass]), **kwargs) return db_field.formfield(**kwargs) # For any other type of field, just call its formfield() method. return db_field.formfield(**kwargs)
def formfield_for_foreignkey(
self, db_field, request=None, **kwargs)
Get a form Field for a ForeignKey.
def formfield_for_foreignkey(self, db_field, request=None, **kwargs): """ Get a form Field for a ForeignKey. """ db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel, self.admin_site, using=db) elif db_field.name in self.radio_fields: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) kwargs['empty_label'] = _('None') if db_field.blank else None if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def formfield_for_manytomany(
self, db_field, request=None, **kwargs)
Get a form Field for a ManyToManyField.
def formfield_for_manytomany(self, db_field, request=None, **kwargs): """ Get a form Field for a ManyToManyField. """ # If it uses an intermediary model that isn't auto created, don't show # a field in admin. if not db_field.rel.through._meta.auto_created: return None db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel, self.admin_site, using=db) kwargs['help_text'] = '' elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)): kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical)) if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def get_action(
self, action)
Return a given action from a parameter, which can either be a callable, or the name of a method on the ModelAdmin. Return is a tuple of (callable, name, description).
def get_action(self, action): """ Return a given action from a parameter, which can either be a callable, or the name of a method on the ModelAdmin. Return is a tuple of (callable, name, description). """ # If the action is a callable, just use it. if callable(action): func = action action = action.__name__ # Next, look for a method. Grab it off self.__class__ to get an unbound # method instead of a bound one; this ensures that the calling # conventions are the same for functions and methods. elif hasattr(self.__class__, action): func = getattr(self.__class__, action) # Finally, look for a named method on the admin site else: try: func = self.admin_site.get_action(action) except KeyError: return None if hasattr(func, 'short_description'): description = func.short_description else: description = capfirst(action.replace('_', ' ')) return func, action, description
def get_action_choices(
self, request, default_choices=[(u'', u'---------')])
Return a list of choices for use in a form object. Each choice is a tuple (name, description).
def get_action_choices(self, request, default_choices=BLANK_CHOICE_DASH): """ Return a list of choices for use in a form object. Each choice is a tuple (name, description). """ choices = [] + default_choices for func, name, description in six.itervalues(self.get_actions(request)): choice = (name, description % model_format_dict(self.opts)) choices.append(choice) return choices
def get_actions(
self, request)
Return a dictionary mapping the names of all actions for this ModelAdmin to a tuple of (callable, name, description) for each action.
def get_actions(self, request): """ Return a dictionary mapping the names of all actions for this ModelAdmin to a tuple of (callable, name, description) for each action. """ # If self.actions is explicitly set to None that means that we don't # want *any* actions enabled on this page. from django.contrib.admin.views.main import _is_changelist_popup if self.actions is None or _is_changelist_popup(request): return SortedDict() actions = [] # Gather actions from the admin site first for (name, func) in self.admin_site.actions: description = getattr(func, 'short_description', name.replace('_', ' ')) actions.append((func, name, description)) # Then gather them from the model admin and all parent classes, # starting with self and working back up. for klass in self.__class__.mro()[::-1]: class_actions = getattr(klass, 'actions', []) # Avoid trying to iterate over None if not class_actions: continue actions.extend([self.get_action(action) for action in class_actions]) # get_action might have returned None, so filter any of those out. actions = filter(None, actions) # Convert the actions into a SortedDict keyed by name. actions = SortedDict([ (name, (func, name, desc)) for func, name, desc in actions ]) return actions
def get_changelist(
self, request, **kwargs)
Returns the ChangeList class for use on the changelist page.
def get_changelist(self, request, **kwargs): """ Returns the ChangeList class for use on the changelist page. """ from django.contrib.admin.views.main import ChangeList return ChangeList
def get_changelist_form(
self, request, **kwargs)
Returns a Form class for use in the Formset on the changelist page.
def get_changelist_form(self, request, **kwargs): """ Returns a Form class for use in the Formset on the changelist page. """ defaults = { "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) if (defaults.get('fields') is None and not modelform_defines_fields(defaults.get('form'))): defaults['fields'] = forms.ALL_FIELDS return modelform_factory(self.model, **defaults)
def get_changelist_formset(
self, request, **kwargs)
Returns a FormSet class for use on the changelist page if list_editable is used.
def get_changelist_formset(self, request, **kwargs): """ Returns a FormSet class for use on the changelist page if list_editable is used. """ defaults = { "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) return modelformset_factory(self.model, self.get_changelist_form(request), extra=0, fields=self.list_editable, **defaults)
def get_field_queryset(
self, db, db_field, request)
If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case).
def get_field_queryset(self, db, db_field, request): """ If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case). """ related_admin = self.admin_site._registry.get(db_field.rel.to, None) if related_admin is not None: ordering = related_admin.get_ordering(request) if ordering is not None and ordering != (): return db_field.rel.to._default_manager.using(db).order_by(*ordering).complex_filter(db_field.rel.limit_choices_to) return None
def get_fieldsets(
self, request, obj=None)
Hook for specifying fieldsets for the add form.
def get_fieldsets(self, request, obj=None): "Hook for specifying fieldsets for the add form." if self.declared_fieldsets: return self.declared_fieldsets form = self.get_form(request, obj, fields=None) fields = list(form.base_fields) + list(self.get_readonly_fields(request, obj)) return [(None, {'fields': fields})]
def get_form(
self, request, obj=None, **kwargs)
Returns a Form class for use in the admin add view. This is used by add_view and change_view.
def get_form(self, request, obj=None, **kwargs): """ Returns a Form class for use in the admin add view. This is used by add_view and change_view. """ if 'fields' in kwargs: fields = kwargs.pop('fields') else: fields = flatten_fieldsets(self.get_fieldsets(request, obj)) if self.exclude is None: exclude = [] else: exclude = list(self.exclude) exclude.extend(self.get_readonly_fields(request, obj)) if self.exclude is None and hasattr(self.form, '_meta') and self.form._meta.exclude: # Take the custom ModelForm's Meta.exclude into account only if the # ModelAdmin doesn't define its own. exclude.extend(self.form._meta.exclude) # if exclude is an empty list we pass None to be consistent with the # default on modelform_factory exclude = exclude or None defaults = { "form": self.form, "fields": fields, "exclude": exclude, "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) if defaults['fields'] is None and not modelform_defines_fields(defaults['form']): defaults['fields'] = forms.ALL_FIELDS try: return modelform_factory(self.model, **defaults) except FieldError as e: raise FieldError('%s. Check fields/fieldsets/exclude attributes of class %s.' % (e, self.__class__.__name__))
def get_formsets(
self, request, obj=None)
def get_formsets(self, request, obj=None): for inline in self.get_inline_instances(request, obj): yield inline.get_formset(request, obj)
def get_inline_instances(
self, request, obj=None)
def get_inline_instances(self, request, obj=None): inline_instances = [] for inline_class in self.inlines: inline = inline_class(self.model, self.admin_site) if request: if not (inline.has_add_permission(request) or inline.has_change_permission(request, obj) or inline.has_delete_permission(request, obj)): continue if not inline.has_add_permission(request): inline.max_num = 0 inline_instances.append(inline) return inline_instances
def get_list_display(
self, request)
Return a sequence containing the fields to be displayed on the changelist.
def get_list_display(self, request): """ Return a sequence containing the fields to be displayed on the changelist. """ return self.list_display
def get_list_display_links(
self, request, list_display)
Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display().
def get_list_display_links(self, request, list_display): """ Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display(). """ if self.list_display_links or not list_display: return self.list_display_links else: # Use only the first item in list_display as link return list(list_display)[:1]
def get_list_filter(
self, request)
Returns a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page.
def get_list_filter(self, request): """ Returns a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page. """ return self.list_filter
def get_model_perms(
self, request)
Returns a dict of all perms for this model. This dict has the keys
add
, change
, and delete
mapping to the True/False for each
of those actions.
def get_model_perms(self, request): """ Returns a dict of all perms for this model. This dict has the keys ``add``, ``change``, and ``delete`` mapping to the True/False for each of those actions. """ return { 'add': self.has_add_permission(request), 'change': self.has_change_permission(request), 'delete': self.has_delete_permission(request), }
def get_object(
self, request, object_id)
Returns an instance matching the primary key provided. None
is
returned if no match is found (or the object_id failed validation
against the primary key field).
def get_object(self, request, object_id): """ Returns an instance matching the primary key provided. ``None`` is returned if no match is found (or the object_id failed validation against the primary key field). """ queryset = self.get_queryset(request) model = queryset.model try: object_id = model._meta.pk.to_python(object_id) return queryset.get(pk=object_id) except (model.DoesNotExist, ValidationError, ValueError): return None
def get_ordering(
self, request)
Hook for specifying field ordering.
def get_ordering(self, request): """ Hook for specifying field ordering. """ return self.ordering or () # otherwise we might try to *None, which is bad ;)
def get_paginator(
self, request, queryset, per_page, orphans=0, allow_empty_first_page=True)
def get_paginator(self, request, queryset, per_page, orphans=0, allow_empty_first_page=True): return self.paginator(queryset, per_page, orphans, allow_empty_first_page)
def get_prepopulated_fields(
self, request, obj=None)
Hook for specifying custom prepopulated fields.
def get_prepopulated_fields(self, request, obj=None): """ Hook for specifying custom prepopulated fields. """ return self.prepopulated_fields
def get_preserved_filters(
self, request)
Returns the preserved filters querystring.
def get_preserved_filters(self, request): """ Returns the preserved filters querystring. """ match = request.resolver_match if self.preserve_filters and match: opts = self.model._meta current_url = '%s:%s' % (match.app_name, match.url_name) changelist_url = 'admin:%s_%s_changelist' % (opts.app_label, opts.model_name) if current_url == changelist_url: preserved_filters = request.GET.urlencode() else: preserved_filters = request.GET.get('_changelist_filters') if preserved_filters: return urlencode({'_changelist_filters': preserved_filters}) return ''
def get_queryset(
self, request)
Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view.
def get_queryset(self, request): """ Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view. """ qs = self.model._default_manager.get_queryset() # TODO: this should be handled by some parameter to the ChangeList. ordering = self.get_ordering(request) if ordering: qs = qs.order_by(*ordering) return qs
def get_readonly_fields(
self, request, obj=None)
Hook for specifying custom readonly fields.
def get_readonly_fields(self, request, obj=None): """ Hook for specifying custom readonly fields. """ return self.readonly_fields
def get_search_results(
self, request, queryset, search_term)
Returns a tuple containing a queryset to implement the search, and a boolean indicating if the results may contain duplicates.
def get_search_results(self, request, queryset, search_term): """ Returns a tuple containing a queryset to implement the search, and a boolean indicating if the results may contain duplicates. """ # Apply keyword searches. def construct_search(field_name): if field_name.startswith('^'): return "%s__istartswith" % field_name[1:] elif field_name.startswith('='): return "%s__iexact" % field_name[1:] elif field_name.startswith('@'): return "%s__search" % field_name[1:] else: return "%s__icontains" % field_name use_distinct = False if self.search_fields and search_term: orm_lookups = [construct_search(str(search_field)) for search_field in self.search_fields] for bit in search_term.split(): or_queries = [models.Q(**{orm_lookup: bit}) for orm_lookup in orm_lookups] queryset = queryset.filter(reduce(operator.or_, or_queries)) if not use_distinct: for search_spec in orm_lookups: if lookup_needs_distinct(self.opts, search_spec): use_distinct = True break return queryset, use_distinct
def get_urls(
self)
def get_urls(self): from django.conf.urls import patterns, url def wrap(view): def wrapper(*args, **kwargs): return self.admin_site.admin_view(view)(*args, **kwargs) return update_wrapper(wrapper, view) info = self.model._meta.app_label, self.model._meta.model_name urlpatterns = patterns('', url(r'^$', wrap(self.changelist_view), name='%s_%s_changelist' % info), url(r'^add/$', wrap(self.add_view), name='%s_%s_add' % info), url(r'^(.+)/history/$', wrap(self.history_view), name='%s_%s_history' % info), url(r'^(.+)/delete/$', wrap(self.delete_view), name='%s_%s_delete' % info), url(r'^(.+)/$', wrap(self.change_view), name='%s_%s_change' % info), ) return urlpatterns
def has_add_permission(
self, request)
Returns True if the given request has permission to add an object. Can be overridden by the user in subclasses.
def has_add_permission(self, request): """ Returns True if the given request has permission to add an object. Can be overridden by the user in subclasses. """ opts = self.opts codename = get_permission_codename('add', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_change_permission(
self, request, obj=None)
Returns True if the given request has permission to change the given
Django model instance, the default implementation doesn't examine the
obj
parameter.
Can be overridden by the user in subclasses. In such case it should
return True if the given request has permission to change the obj
model instance. If obj
is None, this should return True if the given
request has permission to change any object of the given type.
def has_change_permission(self, request, obj=None): """ Returns True if the given request has permission to change the given Django model instance, the default implementation doesn't examine the `obj` parameter. Can be overridden by the user in subclasses. In such case it should return True if the given request has permission to change the `obj` model instance. If `obj` is None, this should return True if the given request has permission to change *any* object of the given type. """ opts = self.opts codename = get_permission_codename('change', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_delete_permission(
self, request, obj=None)
Returns True if the given request has permission to change the given
Django model instance, the default implementation doesn't examine the
obj
parameter.
Can be overridden by the user in subclasses. In such case it should
return True if the given request has permission to delete the obj
model instance. If obj
is None, this should return True if the given
request has permission to delete any object of the given type.
def has_delete_permission(self, request, obj=None): """ Returns True if the given request has permission to change the given Django model instance, the default implementation doesn't examine the `obj` parameter. Can be overridden by the user in subclasses. In such case it should return True if the given request has permission to delete the `obj` model instance. If `obj` is None, this should return True if the given request has permission to delete *any* object of the given type. """ opts = self.opts codename = get_permission_codename('delete', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def history_view(
self, request, object_id, extra_context=None)
The 'history' admin view for this model.
def history_view(self, request, object_id, extra_context=None): "The 'history' admin view for this model." from django.contrib.admin.models import LogEntry # First check if the user can see this history. model = self.model obj = get_object_or_404(model, pk=unquote(object_id)) if not self.has_change_permission(request, obj): raise PermissionDenied # Then get the history for this object. opts = model._meta app_label = opts.app_label action_list = LogEntry.objects.filter( object_id=unquote(object_id), content_type__id__exact=ContentType.objects.get_for_model(model).id ).select_related().order_by('action_time') context = { 'title': _('Change history: %s') % force_text(obj), 'action_list': action_list, 'module_name': capfirst(force_text(opts.verbose_name_plural)), 'object': obj, 'app_label': app_label, 'opts': opts, 'preserved_filters': self.get_preserved_filters(request), } context.update(extra_context or {}) return TemplateResponse(request, self.object_history_template or [ "admin/%s/%s/object_history.html" % (app_label, opts.model_name), "admin/%s/object_history.html" % app_label, "admin/object_history.html" ], context, current_app=self.admin_site.name)
def log_addition(
self, request, object)
Log that an object has been successfully added.
The default implementation creates an admin LogEntry object.
def log_addition(self, request, object): """ Log that an object has been successfully added. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, ADDITION LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=ADDITION )
def log_change(
self, request, object, message)
Log that an object has been successfully changed.
The default implementation creates an admin LogEntry object.
def log_change(self, request, object, message): """ Log that an object has been successfully changed. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, CHANGE LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=CHANGE, change_message=message )
def log_deletion(
self, request, object, object_repr)
Log that an object will be deleted. Note that this method is called before the deletion.
The default implementation creates an admin LogEntry object.
def log_deletion(self, request, object, object_repr): """ Log that an object will be deleted. Note that this method is called before the deletion. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, DELETION LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(self.model).pk, object_id=object.pk, object_repr=object_repr, action_flag=DELETION )
def lookup_allowed(
self, lookup, value)
def lookup_allowed(self, lookup, value): model = self.model # Check FKey lookups that are allowed, so that popups produced by # ForeignKeyRawIdWidget, on the basis of ForeignKey.limit_choices_to, # are allowed to work. for l in model._meta.related_fkey_lookups: for k, v in widgets.url_params_from_lookup_dict(l).items(): if k == lookup and v == value: return True parts = lookup.split(LOOKUP_SEP) # Last term in lookup is a query term (__exact, __startswith etc) # This term can be ignored. if len(parts) > 1 and parts[-1] in QUERY_TERMS: parts.pop() # Special case -- foo__id__exact and foo__id queries are implied # if foo has been specifically included in the lookup list; so # drop __id if it is the last part. However, first we need to find # the pk attribute name. rel_name = None for part in parts[:-1]: try: field, _, _, _ = model._meta.get_field_by_name(part) except FieldDoesNotExist: # Lookups on non-existent fields are ok, since they're ignored # later. return True if hasattr(field, 'rel'): if field.rel is None: # This property or relation doesn't exist, but it's allowed # since it's ignored in ChangeList.get_filters(). return True model = field.rel.to rel_name = field.rel.get_related_field().name elif isinstance(field, RelatedObject): model = field.model rel_name = model._meta.pk.name else: rel_name = None if rel_name and len(parts) > 1 and parts[-1] == rel_name: parts.pop() if len(parts) == 1: return True clean_lookup = LOOKUP_SEP.join(parts) return clean_lookup in self.list_filter or clean_lookup == self.date_hierarchy
def message_user(
self, request, message, level=20, extra_tags='', fail_silently=False)
Send a message to the user. The default implementation posts a message using the django.contrib.messages backend.
Exposes almost the same API as messages.add_message(), but accepts the
positional arguments in a different order to maintain backwards
compatibility. For convenience, it accepts the level
argument as
a string rather than the usual level number.
def message_user(self, request, message, level=messages.INFO, extra_tags='', fail_silently=False): """ Send a message to the user. The default implementation posts a message using the django.contrib.messages backend. Exposes almost the same API as messages.add_message(), but accepts the positional arguments in a different order to maintain backwards compatibility. For convenience, it accepts the `level` argument as a string rather than the usual level number. """ if not isinstance(level, int): # attempt to get the level if passed a string try: level = getattr(messages.constants, level.upper()) except AttributeError: levels = messages.constants.DEFAULT_TAGS.values() levels_repr = ', '.join('`%s`' % l for l in levels) raise ValueError('Bad message level string: `%s`. ' 'Possible values are: %s' % (level, levels_repr)) messages.add_message(request, level, message, extra_tags=extra_tags, fail_silently=fail_silently)
def queryset(
*args, **kwargs)
def wrapped(*args, **kwargs): warnings.warn( "`%s.%s` is deprecated, use `%s` instead." % (self.class_name, self.old_method_name, self.new_method_name), self.deprecation_warning, 2) return f(*args, **kwargs)
def render_change_form(
self, request, context, add=False, change=False, form_url='', obj=None)
def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None): opts = self.model._meta app_label = opts.app_label preserved_filters = self.get_preserved_filters(request) form_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, form_url) context.update({ 'add': add, 'change': change, 'has_add_permission': self.has_add_permission(request), 'has_change_permission': self.has_change_permission(request, obj), 'has_delete_permission': self.has_delete_permission(request, obj), 'has_file_field': True, # FIXME - this should check if form or formsets have a FileField, 'has_absolute_url': hasattr(self.model, 'get_absolute_url'), 'form_url': form_url, 'opts': opts, 'content_type_id': ContentType.objects.get_for_model(self.model).id, 'save_as': self.save_as, 'save_on_top': self.save_on_top, }) if add and self.add_form_template is not None: form_template = self.add_form_template else: form_template = self.change_form_template return TemplateResponse(request, form_template or [ "admin/%s/%s/change_form.html" % (app_label, opts.model_name), "admin/%s/change_form.html" % app_label, "admin/change_form.html" ], context, current_app=self.admin_site.name)
def response_action(
self, request, queryset)
Handle an admin action. This is called if a request is POSTed to the changelist; it returns an HttpResponse if the action was handled, and None otherwise.
def response_action(self, request, queryset): """ Handle an admin action. This is called if a request is POSTed to the changelist; it returns an HttpResponse if the action was handled, and None otherwise. """ # There can be multiple action forms on the page (at the top # and bottom of the change list, for example). Get the action # whose button was pushed. try: action_index = int(request.POST.get('index', 0)) except ValueError: action_index = 0 # Construct the action form. data = request.POST.copy() data.pop(helpers.ACTION_CHECKBOX_NAME, None) data.pop("index", None) # Use the action whose button was pushed try: data.update({'action': data.getlist('action')[action_index]}) except IndexError: # If we didn't get an action from the chosen form that's invalid # POST data, so by deleting action it'll fail the validation check # below. So no need to do anything here pass action_form = self.action_form(data, auto_id=None) action_form.fields['action'].choices = self.get_action_choices(request) # If the form's valid we can handle the action. if action_form.is_valid(): action = action_form.cleaned_data['action'] select_across = action_form.cleaned_data['select_across'] func = self.get_actions(request)[action][0] # Get the list of selected PKs. If nothing's selected, we can't # perform an action on it, so bail. Except we want to perform # the action explicitly on all objects. selected = request.POST.getlist(helpers.ACTION_CHECKBOX_NAME) if not selected and not select_across: # Reminder that something needs to be selected or nothing will happen msg = _("Items must be selected in order to perform " "actions on them. No items have been changed.") self.message_user(request, msg, messages.WARNING) return None if not select_across: # Perform the action only on the selected objects queryset = queryset.filter(pk__in=selected) response = func(self, request, queryset) # Actions may return an HttpResponse-like object, which will be # used as the response from the POST. If not, we'll be a good # little HTTP citizen and redirect back to the changelist page. if isinstance(response, HttpResponseBase): return response else: return HttpResponseRedirect(request.get_full_path()) else: msg = _("No action selected.") self.message_user(request, msg, messages.WARNING) return None
def response_add(
self, request, obj, post_url_continue=None)
Determines the HttpResponse for the add_view stage.
def response_add(self, request, obj, post_url_continue=None): """ Determines the HttpResponse for the add_view stage. """ opts = obj._meta pk_value = obj._get_pk_val() preserved_filters = self.get_preserved_filters(request) msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)} # Here, we distinguish between different save types by checking for # the presence of keys in request.POST. if IS_POPUP_VAR in request.POST: return SimpleTemplateResponse('admin/popup_response.html', { 'pk_value': escape(pk_value), 'obj': escapejs(obj) }) elif "_continue" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) if post_url_continue is None: post_url_continue = reverse('admin:%s_%s_change' % (opts.app_label, opts.model_name), args=(pk_value,), current_app=self.admin_site.name) post_url_continue = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url_continue) return HttpResponseRedirect(post_url_continue) elif "_addanother" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may add another %(name)s below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = request.path redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) else: msg = _('The %(name)s "%(obj)s" was added successfully.') % msg_dict self.message_user(request, msg, messages.SUCCESS) return self.response_post_save_add(request, obj)
def response_change(
self, request, obj)
Determines the HttpResponse for the change_view stage.
def response_change(self, request, obj): """ Determines the HttpResponse for the change_view stage. """ opts = self.model._meta pk_value = obj._get_pk_val() preserved_filters = self.get_preserved_filters(request) msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)} if "_continue" in request.POST: msg = _('The %(name)s "%(obj)s" was changed successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = request.path redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) elif "_saveasnew" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = reverse('admin:%s_%s_change' % (opts.app_label, opts.model_name), args=(pk_value,), current_app=self.admin_site.name) redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) elif "_addanother" in request.POST: msg = _('The %(name)s "%(obj)s" was changed successfully. You may add another %(name)s below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = reverse('admin:%s_%s_add' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) else: msg = _('The %(name)s "%(obj)s" was changed successfully.') % msg_dict self.message_user(request, msg, messages.SUCCESS) return self.response_post_save_change(request, obj)
def response_post_save_add(
self, request, obj)
Figure out where to redirect after the 'Save' button has been pressed when adding a new object.
def response_post_save_add(self, request, obj): """ Figure out where to redirect after the 'Save' button has been pressed when adding a new object. """ opts = self.model._meta if self.has_change_permission(request, None): post_url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url) else: post_url = reverse('admin:index', current_app=self.admin_site.name) return HttpResponseRedirect(post_url)
def response_post_save_change(
self, request, obj)
Figure out where to redirect after the 'Save' button has been pressed when editing an existing object.
def response_post_save_change(self, request, obj): """ Figure out where to redirect after the 'Save' button has been pressed when editing an existing object. """ opts = self.model._meta if self.has_change_permission(request, None): post_url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url) else: post_url = reverse('admin:index', current_app=self.admin_site.name) return HttpResponseRedirect(post_url)
def save_form(
self, request, form, change)
Given a ModelForm return an unsaved instance. change
is True if
the object is being changed, and False if it's being added.
def save_form(self, request, form, change): """ Given a ModelForm return an unsaved instance. ``change`` is True if the object is being changed, and False if it's being added. """ return form.save(commit=False)
def save_formset(
self, request, form, formset, change)
Given an inline formset save it to the database.
def save_formset(self, request, form, formset, change): """ Given an inline formset save it to the database. """ formset.save()
def save_model(
self, request, obj, form, change)
Given a model instance save it to the database.
def save_model(self, request, obj, form, change): """ Given a model instance save it to the database. """ obj.save()
Given the HttpRequest
, the parent ModelForm
instance, the
list of inline formsets and a boolean value based on whether the
parent is being added or changed, save the related objects to the
database. Note that at this point save_form() and save_model() have
already been called.
def to_field_allowed(
self, request, to_field)
Returns True if the model associated with this admin should be allowed to be referenced by the specified field.
def to_field_allowed(self, request, to_field): """ Returns True if the model associated with this admin should be allowed to be referenced by the specified field. """ opts = self.model._meta try: field = opts.get_field(to_field) except FieldDoesNotExist: return False # Always allow referencing the primary key since it's already possible # to get this information from the change view URL. if field.primary_key: return True # Make sure at least one of the models registered for this site # references this field through a FK or a M2M relationship. registered_models = set() for model, admin in self.admin_site._registry.items(): registered_models.add(model) for inline in admin.inlines: registered_models.add(inline.model) for related_object in opts.get_all_related_objects(include_hidden=True): related_model = related_object.model if (any(issubclass(model, related_model) for model in registered_models) and related_object.field.rel.get_related_field() == field): return True return False
def validate(
cls, model)
@classmethod def validate(cls, model): validator = cls.validator_class() validator.validate(cls, model)
class FormatAdmin
class FormatAdmin(admin.ModelAdmin): search_fields = ['original_code', 'tape_reference']
Ancestors (in MRO)
- FormatAdmin
- django.contrib.admin.options.ModelAdmin
- django.contrib.admin.options.BaseModelAdmin
- __builtin__.object
Class variables
var action_form
var actions
var actions_on_bottom
var actions_on_top
var actions_selection_counter
var add_form_template
var change_form_template
var change_list_template
var date_hierarchy
var delete_confirmation_template
var delete_selected_confirmation_template
var exclude
var fields
var fieldsets
var filter_horizontal
var filter_vertical
var form
var formfield_overrides
var inlines
var list_display
var list_display_links
var list_editable
var list_filter
var list_max_show_all
var list_per_page
var object_history_template
var ordering
var paginator
var prepopulated_fields
var preserve_filters
var radio_fields
var raw_id_fields
var readonly_fields
var save_as
var save_on_top
var search_fields
var validator_class
Instance variables
var declared_fieldsets
var media
var urls
Methods
def __init__(
self, model, admin_site)
def __init__(self, model, admin_site): self.model = model self.opts = model._meta self.admin_site = admin_site super(ModelAdmin, self).__init__()
def action_checkbox(
self, obj)
A list_display column containing a checkbox widget.
def action_checkbox(self, obj): """ A list_display column containing a checkbox widget. """ return helpers.checkbox.render(helpers.ACTION_CHECKBOX_NAME, force_text(obj.pk))
def add_view(
self, *args, **kwargs)
The 'add' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def change_view(
self, *args, **kwargs)
The 'change' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def changelist_view(
self, *args, **kwargs)
The 'change list' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def construct_change_message(
self, request, form, formsets)
Construct a change message from a changed object.
def construct_change_message(self, request, form, formsets): """ Construct a change message from a changed object. """ change_message = [] if form.changed_data: change_message.append(_('Changed %s.') % get_text_list(form.changed_data, _('and'))) if formsets: for formset in formsets: for added_object in formset.new_objects: change_message.append(_('Added %(name)s "%(object)s".') % {'name': force_text(added_object._meta.verbose_name), 'object': force_text(added_object)}) for changed_object, changed_fields in formset.changed_objects: change_message.append(_('Changed %(list)s for %(name)s "%(object)s".') % {'list': get_text_list(changed_fields, _('and')), 'name': force_text(changed_object._meta.verbose_name), 'object': force_text(changed_object)}) for deleted_object in formset.deleted_objects: change_message.append(_('Deleted %(name)s "%(object)s".') % {'name': force_text(deleted_object._meta.verbose_name), 'object': force_text(deleted_object)}) change_message = ' '.join(change_message) return change_message or _('No fields changed.')
def delete_model(
self, request, obj)
Given a model instance delete it from the database.
def delete_model(self, request, obj): """ Given a model instance delete it from the database. """ obj.delete()
def delete_view(
self, *args, **kwargs)
The 'delete' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def formfield_for_choice_field(
self, db_field, request=None, **kwargs)
Get a form Field for a database Field that has declared choices.
def formfield_for_choice_field(self, db_field, request=None, **kwargs): """ Get a form Field for a database Field that has declared choices. """ # If the field is named as a radio_field, use a RadioSelect if db_field.name in self.radio_fields: # Avoid stomping on custom widget/choices arguments. if 'widget' not in kwargs: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) if 'choices' not in kwargs: kwargs['choices'] = db_field.get_choices( include_blank=db_field.blank, blank_choice=[('', _('None'))] ) return db_field.formfield(**kwargs)
def formfield_for_dbfield(
self, db_field, **kwargs)
Hook for specifying the form Field instance for a given database Field instance.
If kwargs are given, they're passed to the form Field's constructor.
def formfield_for_dbfield(self, db_field, **kwargs): """ Hook for specifying the form Field instance for a given database Field instance. If kwargs are given, they're passed to the form Field's constructor. """ request = kwargs.pop("request", None) # If the field specifies choices, we don't need to look for special # admin widgets - we just need to use a select widget of some kind. if db_field.choices: return self.formfield_for_choice_field(db_field, request, **kwargs) # ForeignKey or ManyToManyFields if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)): # Combine the field kwargs with any options for formfield_overrides. # Make sure the passed in **kwargs override anything in # formfield_overrides because **kwargs is more specific, and should # always win. if db_field.__class__ in self.formfield_overrides: kwargs = dict(self.formfield_overrides[db_field.__class__], **kwargs) # Get the correct formfield. if isinstance(db_field, models.ForeignKey): formfield = self.formfield_for_foreignkey(db_field, request, **kwargs) elif isinstance(db_field, models.ManyToManyField): formfield = self.formfield_for_manytomany(db_field, request, **kwargs) # For non-raw_id fields, wrap the widget with a wrapper that adds # extra HTML -- the "add other" interface -- to the end of the # rendered output. formfield can be None if it came from a # OneToOneField with parent_link=True or a M2M intermediary. if formfield and db_field.name not in self.raw_id_fields: related_modeladmin = self.admin_site._registry.get( db_field.rel.to) can_add_related = bool(related_modeladmin and related_modeladmin.has_add_permission(request)) formfield.widget = widgets.RelatedFieldWidgetWrapper( formfield.widget, db_field.rel, self.admin_site, can_add_related=can_add_related) return formfield # If we've got overrides for the formfield defined, use 'em. **kwargs # passed to formfield_for_dbfield override the defaults. for klass in db_field.__class__.mro(): if klass in self.formfield_overrides: kwargs = dict(copy.deepcopy(self.formfield_overrides[klass]), **kwargs) return db_field.formfield(**kwargs) # For any other type of field, just call its formfield() method. return db_field.formfield(**kwargs)
def formfield_for_foreignkey(
self, db_field, request=None, **kwargs)
Get a form Field for a ForeignKey.
def formfield_for_foreignkey(self, db_field, request=None, **kwargs): """ Get a form Field for a ForeignKey. """ db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel, self.admin_site, using=db) elif db_field.name in self.radio_fields: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) kwargs['empty_label'] = _('None') if db_field.blank else None if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def formfield_for_manytomany(
self, db_field, request=None, **kwargs)
Get a form Field for a ManyToManyField.
def formfield_for_manytomany(self, db_field, request=None, **kwargs): """ Get a form Field for a ManyToManyField. """ # If it uses an intermediary model that isn't auto created, don't show # a field in admin. if not db_field.rel.through._meta.auto_created: return None db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel, self.admin_site, using=db) kwargs['help_text'] = '' elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)): kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical)) if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def get_action(
self, action)
Return a given action from a parameter, which can either be a callable, or the name of a method on the ModelAdmin. Return is a tuple of (callable, name, description).
def get_action(self, action): """ Return a given action from a parameter, which can either be a callable, or the name of a method on the ModelAdmin. Return is a tuple of (callable, name, description). """ # If the action is a callable, just use it. if callable(action): func = action action = action.__name__ # Next, look for a method. Grab it off self.__class__ to get an unbound # method instead of a bound one; this ensures that the calling # conventions are the same for functions and methods. elif hasattr(self.__class__, action): func = getattr(self.__class__, action) # Finally, look for a named method on the admin site else: try: func = self.admin_site.get_action(action) except KeyError: return None if hasattr(func, 'short_description'): description = func.short_description else: description = capfirst(action.replace('_', ' ')) return func, action, description
def get_action_choices(
self, request, default_choices=[(u'', u'---------')])
Return a list of choices for use in a form object. Each choice is a tuple (name, description).
def get_action_choices(self, request, default_choices=BLANK_CHOICE_DASH): """ Return a list of choices for use in a form object. Each choice is a tuple (name, description). """ choices = [] + default_choices for func, name, description in six.itervalues(self.get_actions(request)): choice = (name, description % model_format_dict(self.opts)) choices.append(choice) return choices
def get_actions(
self, request)
Return a dictionary mapping the names of all actions for this ModelAdmin to a tuple of (callable, name, description) for each action.
def get_actions(self, request): """ Return a dictionary mapping the names of all actions for this ModelAdmin to a tuple of (callable, name, description) for each action. """ # If self.actions is explicitly set to None that means that we don't # want *any* actions enabled on this page. from django.contrib.admin.views.main import _is_changelist_popup if self.actions is None or _is_changelist_popup(request): return SortedDict() actions = [] # Gather actions from the admin site first for (name, func) in self.admin_site.actions: description = getattr(func, 'short_description', name.replace('_', ' ')) actions.append((func, name, description)) # Then gather them from the model admin and all parent classes, # starting with self and working back up. for klass in self.__class__.mro()[::-1]: class_actions = getattr(klass, 'actions', []) # Avoid trying to iterate over None if not class_actions: continue actions.extend([self.get_action(action) for action in class_actions]) # get_action might have returned None, so filter any of those out. actions = filter(None, actions) # Convert the actions into a SortedDict keyed by name. actions = SortedDict([ (name, (func, name, desc)) for func, name, desc in actions ]) return actions
def get_changelist(
self, request, **kwargs)
Returns the ChangeList class for use on the changelist page.
def get_changelist(self, request, **kwargs): """ Returns the ChangeList class for use on the changelist page. """ from django.contrib.admin.views.main import ChangeList return ChangeList
def get_changelist_form(
self, request, **kwargs)
Returns a Form class for use in the Formset on the changelist page.
def get_changelist_form(self, request, **kwargs): """ Returns a Form class for use in the Formset on the changelist page. """ defaults = { "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) if (defaults.get('fields') is None and not modelform_defines_fields(defaults.get('form'))): defaults['fields'] = forms.ALL_FIELDS return modelform_factory(self.model, **defaults)
def get_changelist_formset(
self, request, **kwargs)
Returns a FormSet class for use on the changelist page if list_editable is used.
def get_changelist_formset(self, request, **kwargs): """ Returns a FormSet class for use on the changelist page if list_editable is used. """ defaults = { "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) return modelformset_factory(self.model, self.get_changelist_form(request), extra=0, fields=self.list_editable, **defaults)
def get_field_queryset(
self, db, db_field, request)
If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case).
def get_field_queryset(self, db, db_field, request): """ If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case). """ related_admin = self.admin_site._registry.get(db_field.rel.to, None) if related_admin is not None: ordering = related_admin.get_ordering(request) if ordering is not None and ordering != (): return db_field.rel.to._default_manager.using(db).order_by(*ordering).complex_filter(db_field.rel.limit_choices_to) return None
def get_fieldsets(
self, request, obj=None)
Hook for specifying fieldsets for the add form.
def get_fieldsets(self, request, obj=None): "Hook for specifying fieldsets for the add form." if self.declared_fieldsets: return self.declared_fieldsets form = self.get_form(request, obj, fields=None) fields = list(form.base_fields) + list(self.get_readonly_fields(request, obj)) return [(None, {'fields': fields})]
def get_form(
self, request, obj=None, **kwargs)
Returns a Form class for use in the admin add view. This is used by add_view and change_view.
def get_form(self, request, obj=None, **kwargs): """ Returns a Form class for use in the admin add view. This is used by add_view and change_view. """ if 'fields' in kwargs: fields = kwargs.pop('fields') else: fields = flatten_fieldsets(self.get_fieldsets(request, obj)) if self.exclude is None: exclude = [] else: exclude = list(self.exclude) exclude.extend(self.get_readonly_fields(request, obj)) if self.exclude is None and hasattr(self.form, '_meta') and self.form._meta.exclude: # Take the custom ModelForm's Meta.exclude into account only if the # ModelAdmin doesn't define its own. exclude.extend(self.form._meta.exclude) # if exclude is an empty list we pass None to be consistent with the # default on modelform_factory exclude = exclude or None defaults = { "form": self.form, "fields": fields, "exclude": exclude, "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) if defaults['fields'] is None and not modelform_defines_fields(defaults['form']): defaults['fields'] = forms.ALL_FIELDS try: return modelform_factory(self.model, **defaults) except FieldError as e: raise FieldError('%s. Check fields/fieldsets/exclude attributes of class %s.' % (e, self.__class__.__name__))
def get_formsets(
self, request, obj=None)
def get_formsets(self, request, obj=None): for inline in self.get_inline_instances(request, obj): yield inline.get_formset(request, obj)
def get_inline_instances(
self, request, obj=None)
def get_inline_instances(self, request, obj=None): inline_instances = [] for inline_class in self.inlines: inline = inline_class(self.model, self.admin_site) if request: if not (inline.has_add_permission(request) or inline.has_change_permission(request, obj) or inline.has_delete_permission(request, obj)): continue if not inline.has_add_permission(request): inline.max_num = 0 inline_instances.append(inline) return inline_instances
def get_list_display(
self, request)
Return a sequence containing the fields to be displayed on the changelist.
def get_list_display(self, request): """ Return a sequence containing the fields to be displayed on the changelist. """ return self.list_display
def get_list_display_links(
self, request, list_display)
Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display().
def get_list_display_links(self, request, list_display): """ Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display(). """ if self.list_display_links or not list_display: return self.list_display_links else: # Use only the first item in list_display as link return list(list_display)[:1]
def get_list_filter(
self, request)
Returns a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page.
def get_list_filter(self, request): """ Returns a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page. """ return self.list_filter
def get_model_perms(
self, request)
Returns a dict of all perms for this model. This dict has the keys
add
, change
, and delete
mapping to the True/False for each
of those actions.
def get_model_perms(self, request): """ Returns a dict of all perms for this model. This dict has the keys ``add``, ``change``, and ``delete`` mapping to the True/False for each of those actions. """ return { 'add': self.has_add_permission(request), 'change': self.has_change_permission(request), 'delete': self.has_delete_permission(request), }
def get_object(
self, request, object_id)
Returns an instance matching the primary key provided. None
is
returned if no match is found (or the object_id failed validation
against the primary key field).
def get_object(self, request, object_id): """ Returns an instance matching the primary key provided. ``None`` is returned if no match is found (or the object_id failed validation against the primary key field). """ queryset = self.get_queryset(request) model = queryset.model try: object_id = model._meta.pk.to_python(object_id) return queryset.get(pk=object_id) except (model.DoesNotExist, ValidationError, ValueError): return None
def get_ordering(
self, request)
Hook for specifying field ordering.
def get_ordering(self, request): """ Hook for specifying field ordering. """ return self.ordering or () # otherwise we might try to *None, which is bad ;)
def get_paginator(
self, request, queryset, per_page, orphans=0, allow_empty_first_page=True)
def get_paginator(self, request, queryset, per_page, orphans=0, allow_empty_first_page=True): return self.paginator(queryset, per_page, orphans, allow_empty_first_page)
def get_prepopulated_fields(
self, request, obj=None)
Hook for specifying custom prepopulated fields.
def get_prepopulated_fields(self, request, obj=None): """ Hook for specifying custom prepopulated fields. """ return self.prepopulated_fields
def get_preserved_filters(
self, request)
Returns the preserved filters querystring.
def get_preserved_filters(self, request): """ Returns the preserved filters querystring. """ match = request.resolver_match if self.preserve_filters and match: opts = self.model._meta current_url = '%s:%s' % (match.app_name, match.url_name) changelist_url = 'admin:%s_%s_changelist' % (opts.app_label, opts.model_name) if current_url == changelist_url: preserved_filters = request.GET.urlencode() else: preserved_filters = request.GET.get('_changelist_filters') if preserved_filters: return urlencode({'_changelist_filters': preserved_filters}) return ''
def get_queryset(
self, request)
Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view.
def get_queryset(self, request): """ Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view. """ qs = self.model._default_manager.get_queryset() # TODO: this should be handled by some parameter to the ChangeList. ordering = self.get_ordering(request) if ordering: qs = qs.order_by(*ordering) return qs
def get_readonly_fields(
self, request, obj=None)
Hook for specifying custom readonly fields.
def get_readonly_fields(self, request, obj=None): """ Hook for specifying custom readonly fields. """ return self.readonly_fields
def get_search_results(
self, request, queryset, search_term)
Returns a tuple containing a queryset to implement the search, and a boolean indicating if the results may contain duplicates.
def get_search_results(self, request, queryset, search_term): """ Returns a tuple containing a queryset to implement the search, and a boolean indicating if the results may contain duplicates. """ # Apply keyword searches. def construct_search(field_name): if field_name.startswith('^'): return "%s__istartswith" % field_name[1:] elif field_name.startswith('='): return "%s__iexact" % field_name[1:] elif field_name.startswith('@'): return "%s__search" % field_name[1:] else: return "%s__icontains" % field_name use_distinct = False if self.search_fields and search_term: orm_lookups = [construct_search(str(search_field)) for search_field in self.search_fields] for bit in search_term.split(): or_queries = [models.Q(**{orm_lookup: bit}) for orm_lookup in orm_lookups] queryset = queryset.filter(reduce(operator.or_, or_queries)) if not use_distinct: for search_spec in orm_lookups: if lookup_needs_distinct(self.opts, search_spec): use_distinct = True break return queryset, use_distinct
def get_urls(
self)
def get_urls(self): from django.conf.urls import patterns, url def wrap(view): def wrapper(*args, **kwargs): return self.admin_site.admin_view(view)(*args, **kwargs) return update_wrapper(wrapper, view) info = self.model._meta.app_label, self.model._meta.model_name urlpatterns = patterns('', url(r'^$', wrap(self.changelist_view), name='%s_%s_changelist' % info), url(r'^add/$', wrap(self.add_view), name='%s_%s_add' % info), url(r'^(.+)/history/$', wrap(self.history_view), name='%s_%s_history' % info), url(r'^(.+)/delete/$', wrap(self.delete_view), name='%s_%s_delete' % info), url(r'^(.+)/$', wrap(self.change_view), name='%s_%s_change' % info), ) return urlpatterns
def has_add_permission(
self, request)
Returns True if the given request has permission to add an object. Can be overridden by the user in subclasses.
def has_add_permission(self, request): """ Returns True if the given request has permission to add an object. Can be overridden by the user in subclasses. """ opts = self.opts codename = get_permission_codename('add', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_change_permission(
self, request, obj=None)
Returns True if the given request has permission to change the given
Django model instance, the default implementation doesn't examine the
obj
parameter.
Can be overridden by the user in subclasses. In such case it should
return True if the given request has permission to change the obj
model instance. If obj
is None, this should return True if the given
request has permission to change any object of the given type.
def has_change_permission(self, request, obj=None): """ Returns True if the given request has permission to change the given Django model instance, the default implementation doesn't examine the `obj` parameter. Can be overridden by the user in subclasses. In such case it should return True if the given request has permission to change the `obj` model instance. If `obj` is None, this should return True if the given request has permission to change *any* object of the given type. """ opts = self.opts codename = get_permission_codename('change', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_delete_permission(
self, request, obj=None)
Returns True if the given request has permission to change the given
Django model instance, the default implementation doesn't examine the
obj
parameter.
Can be overridden by the user in subclasses. In such case it should
return True if the given request has permission to delete the obj
model instance. If obj
is None, this should return True if the given
request has permission to delete any object of the given type.
def has_delete_permission(self, request, obj=None): """ Returns True if the given request has permission to change the given Django model instance, the default implementation doesn't examine the `obj` parameter. Can be overridden by the user in subclasses. In such case it should return True if the given request has permission to delete the `obj` model instance. If `obj` is None, this should return True if the given request has permission to delete *any* object of the given type. """ opts = self.opts codename = get_permission_codename('delete', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def history_view(
self, request, object_id, extra_context=None)
The 'history' admin view for this model.
def history_view(self, request, object_id, extra_context=None): "The 'history' admin view for this model." from django.contrib.admin.models import LogEntry # First check if the user can see this history. model = self.model obj = get_object_or_404(model, pk=unquote(object_id)) if not self.has_change_permission(request, obj): raise PermissionDenied # Then get the history for this object. opts = model._meta app_label = opts.app_label action_list = LogEntry.objects.filter( object_id=unquote(object_id), content_type__id__exact=ContentType.objects.get_for_model(model).id ).select_related().order_by('action_time') context = { 'title': _('Change history: %s') % force_text(obj), 'action_list': action_list, 'module_name': capfirst(force_text(opts.verbose_name_plural)), 'object': obj, 'app_label': app_label, 'opts': opts, 'preserved_filters': self.get_preserved_filters(request), } context.update(extra_context or {}) return TemplateResponse(request, self.object_history_template or [ "admin/%s/%s/object_history.html" % (app_label, opts.model_name), "admin/%s/object_history.html" % app_label, "admin/object_history.html" ], context, current_app=self.admin_site.name)
def log_addition(
self, request, object)
Log that an object has been successfully added.
The default implementation creates an admin LogEntry object.
def log_addition(self, request, object): """ Log that an object has been successfully added. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, ADDITION LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=ADDITION )
def log_change(
self, request, object, message)
Log that an object has been successfully changed.
The default implementation creates an admin LogEntry object.
def log_change(self, request, object, message): """ Log that an object has been successfully changed. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, CHANGE LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=CHANGE, change_message=message )
def log_deletion(
self, request, object, object_repr)
Log that an object will be deleted. Note that this method is called before the deletion.
The default implementation creates an admin LogEntry object.
def log_deletion(self, request, object, object_repr): """ Log that an object will be deleted. Note that this method is called before the deletion. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, DELETION LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(self.model).pk, object_id=object.pk, object_repr=object_repr, action_flag=DELETION )
def lookup_allowed(
self, lookup, value)
def lookup_allowed(self, lookup, value): model = self.model # Check FKey lookups that are allowed, so that popups produced by # ForeignKeyRawIdWidget, on the basis of ForeignKey.limit_choices_to, # are allowed to work. for l in model._meta.related_fkey_lookups: for k, v in widgets.url_params_from_lookup_dict(l).items(): if k == lookup and v == value: return True parts = lookup.split(LOOKUP_SEP) # Last term in lookup is a query term (__exact, __startswith etc) # This term can be ignored. if len(parts) > 1 and parts[-1] in QUERY_TERMS: parts.pop() # Special case -- foo__id__exact and foo__id queries are implied # if foo has been specifically included in the lookup list; so # drop __id if it is the last part. However, first we need to find # the pk attribute name. rel_name = None for part in parts[:-1]: try: field, _, _, _ = model._meta.get_field_by_name(part) except FieldDoesNotExist: # Lookups on non-existent fields are ok, since they're ignored # later. return True if hasattr(field, 'rel'): if field.rel is None: # This property or relation doesn't exist, but it's allowed # since it's ignored in ChangeList.get_filters(). return True model = field.rel.to rel_name = field.rel.get_related_field().name elif isinstance(field, RelatedObject): model = field.model rel_name = model._meta.pk.name else: rel_name = None if rel_name and len(parts) > 1 and parts[-1] == rel_name: parts.pop() if len(parts) == 1: return True clean_lookup = LOOKUP_SEP.join(parts) return clean_lookup in self.list_filter or clean_lookup == self.date_hierarchy
def message_user(
self, request, message, level=20, extra_tags='', fail_silently=False)
Send a message to the user. The default implementation posts a message using the django.contrib.messages backend.
Exposes almost the same API as messages.add_message(), but accepts the
positional arguments in a different order to maintain backwards
compatibility. For convenience, it accepts the level
argument as
a string rather than the usual level number.
def message_user(self, request, message, level=messages.INFO, extra_tags='', fail_silently=False): """ Send a message to the user. The default implementation posts a message using the django.contrib.messages backend. Exposes almost the same API as messages.add_message(), but accepts the positional arguments in a different order to maintain backwards compatibility. For convenience, it accepts the `level` argument as a string rather than the usual level number. """ if not isinstance(level, int): # attempt to get the level if passed a string try: level = getattr(messages.constants, level.upper()) except AttributeError: levels = messages.constants.DEFAULT_TAGS.values() levels_repr = ', '.join('`%s`' % l for l in levels) raise ValueError('Bad message level string: `%s`. ' 'Possible values are: %s' % (level, levels_repr)) messages.add_message(request, level, message, extra_tags=extra_tags, fail_silently=fail_silently)
def queryset(
*args, **kwargs)
def wrapped(*args, **kwargs): warnings.warn( "`%s.%s` is deprecated, use `%s` instead." % (self.class_name, self.old_method_name, self.new_method_name), self.deprecation_warning, 2) return f(*args, **kwargs)
def render_change_form(
self, request, context, add=False, change=False, form_url='', obj=None)
def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None): opts = self.model._meta app_label = opts.app_label preserved_filters = self.get_preserved_filters(request) form_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, form_url) context.update({ 'add': add, 'change': change, 'has_add_permission': self.has_add_permission(request), 'has_change_permission': self.has_change_permission(request, obj), 'has_delete_permission': self.has_delete_permission(request, obj), 'has_file_field': True, # FIXME - this should check if form or formsets have a FileField, 'has_absolute_url': hasattr(self.model, 'get_absolute_url'), 'form_url': form_url, 'opts': opts, 'content_type_id': ContentType.objects.get_for_model(self.model).id, 'save_as': self.save_as, 'save_on_top': self.save_on_top, }) if add and self.add_form_template is not None: form_template = self.add_form_template else: form_template = self.change_form_template return TemplateResponse(request, form_template or [ "admin/%s/%s/change_form.html" % (app_label, opts.model_name), "admin/%s/change_form.html" % app_label, "admin/change_form.html" ], context, current_app=self.admin_site.name)
def response_action(
self, request, queryset)
Handle an admin action. This is called if a request is POSTed to the changelist; it returns an HttpResponse if the action was handled, and None otherwise.
def response_action(self, request, queryset): """ Handle an admin action. This is called if a request is POSTed to the changelist; it returns an HttpResponse if the action was handled, and None otherwise. """ # There can be multiple action forms on the page (at the top # and bottom of the change list, for example). Get the action # whose button was pushed. try: action_index = int(request.POST.get('index', 0)) except ValueError: action_index = 0 # Construct the action form. data = request.POST.copy() data.pop(helpers.ACTION_CHECKBOX_NAME, None) data.pop("index", None) # Use the action whose button was pushed try: data.update({'action': data.getlist('action')[action_index]}) except IndexError: # If we didn't get an action from the chosen form that's invalid # POST data, so by deleting action it'll fail the validation check # below. So no need to do anything here pass action_form = self.action_form(data, auto_id=None) action_form.fields['action'].choices = self.get_action_choices(request) # If the form's valid we can handle the action. if action_form.is_valid(): action = action_form.cleaned_data['action'] select_across = action_form.cleaned_data['select_across'] func = self.get_actions(request)[action][0] # Get the list of selected PKs. If nothing's selected, we can't # perform an action on it, so bail. Except we want to perform # the action explicitly on all objects. selected = request.POST.getlist(helpers.ACTION_CHECKBOX_NAME) if not selected and not select_across: # Reminder that something needs to be selected or nothing will happen msg = _("Items must be selected in order to perform " "actions on them. No items have been changed.") self.message_user(request, msg, messages.WARNING) return None if not select_across: # Perform the action only on the selected objects queryset = queryset.filter(pk__in=selected) response = func(self, request, queryset) # Actions may return an HttpResponse-like object, which will be # used as the response from the POST. If not, we'll be a good # little HTTP citizen and redirect back to the changelist page. if isinstance(response, HttpResponseBase): return response else: return HttpResponseRedirect(request.get_full_path()) else: msg = _("No action selected.") self.message_user(request, msg, messages.WARNING) return None
def response_add(
self, request, obj, post_url_continue=None)
Determines the HttpResponse for the add_view stage.
def response_add(self, request, obj, post_url_continue=None): """ Determines the HttpResponse for the add_view stage. """ opts = obj._meta pk_value = obj._get_pk_val() preserved_filters = self.get_preserved_filters(request) msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)} # Here, we distinguish between different save types by checking for # the presence of keys in request.POST. if IS_POPUP_VAR in request.POST: return SimpleTemplateResponse('admin/popup_response.html', { 'pk_value': escape(pk_value), 'obj': escapejs(obj) }) elif "_continue" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) if post_url_continue is None: post_url_continue = reverse('admin:%s_%s_change' % (opts.app_label, opts.model_name), args=(pk_value,), current_app=self.admin_site.name) post_url_continue = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url_continue) return HttpResponseRedirect(post_url_continue) elif "_addanother" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may add another %(name)s below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = request.path redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) else: msg = _('The %(name)s "%(obj)s" was added successfully.') % msg_dict self.message_user(request, msg, messages.SUCCESS) return self.response_post_save_add(request, obj)
def response_change(
self, request, obj)
Determines the HttpResponse for the change_view stage.
def response_change(self, request, obj): """ Determines the HttpResponse for the change_view stage. """ opts = self.model._meta pk_value = obj._get_pk_val() preserved_filters = self.get_preserved_filters(request) msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)} if "_continue" in request.POST: msg = _('The %(name)s "%(obj)s" was changed successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = request.path redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) elif "_saveasnew" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = reverse('admin:%s_%s_change' % (opts.app_label, opts.model_name), args=(pk_value,), current_app=self.admin_site.name) redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) elif "_addanother" in request.POST: msg = _('The %(name)s "%(obj)s" was changed successfully. You may add another %(name)s below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = reverse('admin:%s_%s_add' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) else: msg = _('The %(name)s "%(obj)s" was changed successfully.') % msg_dict self.message_user(request, msg, messages.SUCCESS) return self.response_post_save_change(request, obj)
def response_post_save_add(
self, request, obj)
Figure out where to redirect after the 'Save' button has been pressed when adding a new object.
def response_post_save_add(self, request, obj): """ Figure out where to redirect after the 'Save' button has been pressed when adding a new object. """ opts = self.model._meta if self.has_change_permission(request, None): post_url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url) else: post_url = reverse('admin:index', current_app=self.admin_site.name) return HttpResponseRedirect(post_url)
def response_post_save_change(
self, request, obj)
Figure out where to redirect after the 'Save' button has been pressed when editing an existing object.
def response_post_save_change(self, request, obj): """ Figure out where to redirect after the 'Save' button has been pressed when editing an existing object. """ opts = self.model._meta if self.has_change_permission(request, None): post_url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url) else: post_url = reverse('admin:index', current_app=self.admin_site.name) return HttpResponseRedirect(post_url)
def save_form(
self, request, form, change)
Given a ModelForm return an unsaved instance. change
is True if
the object is being changed, and False if it's being added.
def save_form(self, request, form, change): """ Given a ModelForm return an unsaved instance. ``change`` is True if the object is being changed, and False if it's being added. """ return form.save(commit=False)
def save_formset(
self, request, form, formset, change)
Given an inline formset save it to the database.
def save_formset(self, request, form, formset, change): """ Given an inline formset save it to the database. """ formset.save()
def save_model(
self, request, obj, form, change)
Given a model instance save it to the database.
def save_model(self, request, obj, form, change): """ Given a model instance save it to the database. """ obj.save()
Given the HttpRequest
, the parent ModelForm
instance, the
list of inline formsets and a boolean value based on whether the
parent is being added or changed, save the related objects to the
database. Note that at this point save_form() and save_model() have
already been called.
def to_field_allowed(
self, request, to_field)
Returns True if the model associated with this admin should be allowed to be referenced by the specified field.
def to_field_allowed(self, request, to_field): """ Returns True if the model associated with this admin should be allowed to be referenced by the specified field. """ opts = self.model._meta try: field = opts.get_field(to_field) except FieldDoesNotExist: return False # Always allow referencing the primary key since it's already possible # to get this information from the change view URL. if field.primary_key: return True # Make sure at least one of the models registered for this site # references this field through a FK or a M2M relationship. registered_models = set() for model, admin in self.admin_site._registry.items(): registered_models.add(model) for inline in admin.inlines: registered_models.add(inline.model) for related_object in opts.get_all_related_objects(include_hidden=True): related_model = related_object.model if (any(issubclass(model, related_model) for model in registered_models) and related_object.field.rel.get_related_field() == field): return True return False
def validate(
cls, model)
@classmethod def validate(cls, model): validator = cls.validator_class() validator.validate(cls, model)
class InstrumentAdmin
class InstrumentAdmin(admin.ModelAdmin): search_fields = ['name'] ordering = ['name']
Ancestors (in MRO)
- InstrumentAdmin
- django.contrib.admin.options.ModelAdmin
- django.contrib.admin.options.BaseModelAdmin
- __builtin__.object
Class variables
var action_form
var actions
var actions_on_bottom
var actions_on_top
var actions_selection_counter
var add_form_template
var change_form_template
var change_list_template
var date_hierarchy
var delete_confirmation_template
var delete_selected_confirmation_template
var exclude
var fields
var fieldsets
var filter_horizontal
var filter_vertical
var form
var formfield_overrides
var inlines
var list_display
var list_display_links
var list_editable
var list_filter
var list_max_show_all
var list_per_page
var object_history_template
var ordering
var paginator
var prepopulated_fields
var preserve_filters
var radio_fields
var raw_id_fields
var readonly_fields
var save_as
var save_on_top
var search_fields
var validator_class
Instance variables
var declared_fieldsets
var media
var urls
Methods
def __init__(
self, model, admin_site)
def __init__(self, model, admin_site): self.model = model self.opts = model._meta self.admin_site = admin_site super(ModelAdmin, self).__init__()
def action_checkbox(
self, obj)
A list_display column containing a checkbox widget.
def action_checkbox(self, obj): """ A list_display column containing a checkbox widget. """ return helpers.checkbox.render(helpers.ACTION_CHECKBOX_NAME, force_text(obj.pk))
def add_view(
self, *args, **kwargs)
The 'add' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def change_view(
self, *args, **kwargs)
The 'change' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def changelist_view(
self, *args, **kwargs)
The 'change list' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def construct_change_message(
self, request, form, formsets)
Construct a change message from a changed object.
def construct_change_message(self, request, form, formsets): """ Construct a change message from a changed object. """ change_message = [] if form.changed_data: change_message.append(_('Changed %s.') % get_text_list(form.changed_data, _('and'))) if formsets: for formset in formsets: for added_object in formset.new_objects: change_message.append(_('Added %(name)s "%(object)s".') % {'name': force_text(added_object._meta.verbose_name), 'object': force_text(added_object)}) for changed_object, changed_fields in formset.changed_objects: change_message.append(_('Changed %(list)s for %(name)s "%(object)s".') % {'list': get_text_list(changed_fields, _('and')), 'name': force_text(changed_object._meta.verbose_name), 'object': force_text(changed_object)}) for deleted_object in formset.deleted_objects: change_message.append(_('Deleted %(name)s "%(object)s".') % {'name': force_text(deleted_object._meta.verbose_name), 'object': force_text(deleted_object)}) change_message = ' '.join(change_message) return change_message or _('No fields changed.')
def delete_model(
self, request, obj)
Given a model instance delete it from the database.
def delete_model(self, request, obj): """ Given a model instance delete it from the database. """ obj.delete()
def delete_view(
self, *args, **kwargs)
The 'delete' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def formfield_for_choice_field(
self, db_field, request=None, **kwargs)
Get a form Field for a database Field that has declared choices.
def formfield_for_choice_field(self, db_field, request=None, **kwargs): """ Get a form Field for a database Field that has declared choices. """ # If the field is named as a radio_field, use a RadioSelect if db_field.name in self.radio_fields: # Avoid stomping on custom widget/choices arguments. if 'widget' not in kwargs: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) if 'choices' not in kwargs: kwargs['choices'] = db_field.get_choices( include_blank=db_field.blank, blank_choice=[('', _('None'))] ) return db_field.formfield(**kwargs)
def formfield_for_dbfield(
self, db_field, **kwargs)
Hook for specifying the form Field instance for a given database Field instance.
If kwargs are given, they're passed to the form Field's constructor.
def formfield_for_dbfield(self, db_field, **kwargs): """ Hook for specifying the form Field instance for a given database Field instance. If kwargs are given, they're passed to the form Field's constructor. """ request = kwargs.pop("request", None) # If the field specifies choices, we don't need to look for special # admin widgets - we just need to use a select widget of some kind. if db_field.choices: return self.formfield_for_choice_field(db_field, request, **kwargs) # ForeignKey or ManyToManyFields if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)): # Combine the field kwargs with any options for formfield_overrides. # Make sure the passed in **kwargs override anything in # formfield_overrides because **kwargs is more specific, and should # always win. if db_field.__class__ in self.formfield_overrides: kwargs = dict(self.formfield_overrides[db_field.__class__], **kwargs) # Get the correct formfield. if isinstance(db_field, models.ForeignKey): formfield = self.formfield_for_foreignkey(db_field, request, **kwargs) elif isinstance(db_field, models.ManyToManyField): formfield = self.formfield_for_manytomany(db_field, request, **kwargs) # For non-raw_id fields, wrap the widget with a wrapper that adds # extra HTML -- the "add other" interface -- to the end of the # rendered output. formfield can be None if it came from a # OneToOneField with parent_link=True or a M2M intermediary. if formfield and db_field.name not in self.raw_id_fields: related_modeladmin = self.admin_site._registry.get( db_field.rel.to) can_add_related = bool(related_modeladmin and related_modeladmin.has_add_permission(request)) formfield.widget = widgets.RelatedFieldWidgetWrapper( formfield.widget, db_field.rel, self.admin_site, can_add_related=can_add_related) return formfield # If we've got overrides for the formfield defined, use 'em. **kwargs # passed to formfield_for_dbfield override the defaults. for klass in db_field.__class__.mro(): if klass in self.formfield_overrides: kwargs = dict(copy.deepcopy(self.formfield_overrides[klass]), **kwargs) return db_field.formfield(**kwargs) # For any other type of field, just call its formfield() method. return db_field.formfield(**kwargs)
def formfield_for_foreignkey(
self, db_field, request=None, **kwargs)
Get a form Field for a ForeignKey.
def formfield_for_foreignkey(self, db_field, request=None, **kwargs): """ Get a form Field for a ForeignKey. """ db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel, self.admin_site, using=db) elif db_field.name in self.radio_fields: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) kwargs['empty_label'] = _('None') if db_field.blank else None if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def formfield_for_manytomany(
self, db_field, request=None, **kwargs)
Get a form Field for a ManyToManyField.
def formfield_for_manytomany(self, db_field, request=None, **kwargs): """ Get a form Field for a ManyToManyField. """ # If it uses an intermediary model that isn't auto created, don't show # a field in admin. if not db_field.rel.through._meta.auto_created: return None db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel, self.admin_site, using=db) kwargs['help_text'] = '' elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)): kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical)) if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def get_action(
self, action)
Return a given action from a parameter, which can either be a callable, or the name of a method on the ModelAdmin. Return is a tuple of (callable, name, description).
def get_action(self, action): """ Return a given action from a parameter, which can either be a callable, or the name of a method on the ModelAdmin. Return is a tuple of (callable, name, description). """ # If the action is a callable, just use it. if callable(action): func = action action = action.__name__ # Next, look for a method. Grab it off self.__class__ to get an unbound # method instead of a bound one; this ensures that the calling # conventions are the same for functions and methods. elif hasattr(self.__class__, action): func = getattr(self.__class__, action) # Finally, look for a named method on the admin site else: try: func = self.admin_site.get_action(action) except KeyError: return None if hasattr(func, 'short_description'): description = func.short_description else: description = capfirst(action.replace('_', ' ')) return func, action, description
def get_action_choices(
self, request, default_choices=[(u'', u'---------')])
Return a list of choices for use in a form object. Each choice is a tuple (name, description).
def get_action_choices(self, request, default_choices=BLANK_CHOICE_DASH): """ Return a list of choices for use in a form object. Each choice is a tuple (name, description). """ choices = [] + default_choices for func, name, description in six.itervalues(self.get_actions(request)): choice = (name, description % model_format_dict(self.opts)) choices.append(choice) return choices
def get_actions(
self, request)
Return a dictionary mapping the names of all actions for this ModelAdmin to a tuple of (callable, name, description) for each action.
def get_actions(self, request): """ Return a dictionary mapping the names of all actions for this ModelAdmin to a tuple of (callable, name, description) for each action. """ # If self.actions is explicitly set to None that means that we don't # want *any* actions enabled on this page. from django.contrib.admin.views.main import _is_changelist_popup if self.actions is None or _is_changelist_popup(request): return SortedDict() actions = [] # Gather actions from the admin site first for (name, func) in self.admin_site.actions: description = getattr(func, 'short_description', name.replace('_', ' ')) actions.append((func, name, description)) # Then gather them from the model admin and all parent classes, # starting with self and working back up. for klass in self.__class__.mro()[::-1]: class_actions = getattr(klass, 'actions', []) # Avoid trying to iterate over None if not class_actions: continue actions.extend([self.get_action(action) for action in class_actions]) # get_action might have returned None, so filter any of those out. actions = filter(None, actions) # Convert the actions into a SortedDict keyed by name. actions = SortedDict([ (name, (func, name, desc)) for func, name, desc in actions ]) return actions
def get_changelist(
self, request, **kwargs)
Returns the ChangeList class for use on the changelist page.
def get_changelist(self, request, **kwargs): """ Returns the ChangeList class for use on the changelist page. """ from django.contrib.admin.views.main import ChangeList return ChangeList
def get_changelist_form(
self, request, **kwargs)
Returns a Form class for use in the Formset on the changelist page.
def get_changelist_form(self, request, **kwargs): """ Returns a Form class for use in the Formset on the changelist page. """ defaults = { "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) if (defaults.get('fields') is None and not modelform_defines_fields(defaults.get('form'))): defaults['fields'] = forms.ALL_FIELDS return modelform_factory(self.model, **defaults)
def get_changelist_formset(
self, request, **kwargs)
Returns a FormSet class for use on the changelist page if list_editable is used.
def get_changelist_formset(self, request, **kwargs): """ Returns a FormSet class for use on the changelist page if list_editable is used. """ defaults = { "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) return modelformset_factory(self.model, self.get_changelist_form(request), extra=0, fields=self.list_editable, **defaults)
def get_field_queryset(
self, db, db_field, request)
If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case).
def get_field_queryset(self, db, db_field, request): """ If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case). """ related_admin = self.admin_site._registry.get(db_field.rel.to, None) if related_admin is not None: ordering = related_admin.get_ordering(request) if ordering is not None and ordering != (): return db_field.rel.to._default_manager.using(db).order_by(*ordering).complex_filter(db_field.rel.limit_choices_to) return None
def get_fieldsets(
self, request, obj=None)
Hook for specifying fieldsets for the add form.
def get_fieldsets(self, request, obj=None): "Hook for specifying fieldsets for the add form." if self.declared_fieldsets: return self.declared_fieldsets form = self.get_form(request, obj, fields=None) fields = list(form.base_fields) + list(self.get_readonly_fields(request, obj)) return [(None, {'fields': fields})]
def get_form(
self, request, obj=None, **kwargs)
Returns a Form class for use in the admin add view. This is used by add_view and change_view.
def get_form(self, request, obj=None, **kwargs): """ Returns a Form class for use in the admin add view. This is used by add_view and change_view. """ if 'fields' in kwargs: fields = kwargs.pop('fields') else: fields = flatten_fieldsets(self.get_fieldsets(request, obj)) if self.exclude is None: exclude = [] else: exclude = list(self.exclude) exclude.extend(self.get_readonly_fields(request, obj)) if self.exclude is None and hasattr(self.form, '_meta') and self.form._meta.exclude: # Take the custom ModelForm's Meta.exclude into account only if the # ModelAdmin doesn't define its own. exclude.extend(self.form._meta.exclude) # if exclude is an empty list we pass None to be consistent with the # default on modelform_factory exclude = exclude or None defaults = { "form": self.form, "fields": fields, "exclude": exclude, "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) if defaults['fields'] is None and not modelform_defines_fields(defaults['form']): defaults['fields'] = forms.ALL_FIELDS try: return modelform_factory(self.model, **defaults) except FieldError as e: raise FieldError('%s. Check fields/fieldsets/exclude attributes of class %s.' % (e, self.__class__.__name__))
def get_formsets(
self, request, obj=None)
def get_formsets(self, request, obj=None): for inline in self.get_inline_instances(request, obj): yield inline.get_formset(request, obj)
def get_inline_instances(
self, request, obj=None)
def get_inline_instances(self, request, obj=None): inline_instances = [] for inline_class in self.inlines: inline = inline_class(self.model, self.admin_site) if request: if not (inline.has_add_permission(request) or inline.has_change_permission(request, obj) or inline.has_delete_permission(request, obj)): continue if not inline.has_add_permission(request): inline.max_num = 0 inline_instances.append(inline) return inline_instances
def get_list_display(
self, request)
Return a sequence containing the fields to be displayed on the changelist.
def get_list_display(self, request): """ Return a sequence containing the fields to be displayed on the changelist. """ return self.list_display
def get_list_display_links(
self, request, list_display)
Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display().
def get_list_display_links(self, request, list_display): """ Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display(). """ if self.list_display_links or not list_display: return self.list_display_links else: # Use only the first item in list_display as link return list(list_display)[:1]
def get_list_filter(
self, request)
Returns a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page.
def get_list_filter(self, request): """ Returns a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page. """ return self.list_filter
def get_model_perms(
self, request)
Returns a dict of all perms for this model. This dict has the keys
add
, change
, and delete
mapping to the True/False for each
of those actions.
def get_model_perms(self, request): """ Returns a dict of all perms for this model. This dict has the keys ``add``, ``change``, and ``delete`` mapping to the True/False for each of those actions. """ return { 'add': self.has_add_permission(request), 'change': self.has_change_permission(request), 'delete': self.has_delete_permission(request), }
def get_object(
self, request, object_id)
Returns an instance matching the primary key provided. None
is
returned if no match is found (or the object_id failed validation
against the primary key field).
def get_object(self, request, object_id): """ Returns an instance matching the primary key provided. ``None`` is returned if no match is found (or the object_id failed validation against the primary key field). """ queryset = self.get_queryset(request) model = queryset.model try: object_id = model._meta.pk.to_python(object_id) return queryset.get(pk=object_id) except (model.DoesNotExist, ValidationError, ValueError): return None
def get_ordering(
self, request)
Hook for specifying field ordering.
def get_ordering(self, request): """ Hook for specifying field ordering. """ return self.ordering or () # otherwise we might try to *None, which is bad ;)
def get_paginator(
self, request, queryset, per_page, orphans=0, allow_empty_first_page=True)
def get_paginator(self, request, queryset, per_page, orphans=0, allow_empty_first_page=True): return self.paginator(queryset, per_page, orphans, allow_empty_first_page)
def get_prepopulated_fields(
self, request, obj=None)
Hook for specifying custom prepopulated fields.
def get_prepopulated_fields(self, request, obj=None): """ Hook for specifying custom prepopulated fields. """ return self.prepopulated_fields
def get_preserved_filters(
self, request)
Returns the preserved filters querystring.
def get_preserved_filters(self, request): """ Returns the preserved filters querystring. """ match = request.resolver_match if self.preserve_filters and match: opts = self.model._meta current_url = '%s:%s' % (match.app_name, match.url_name) changelist_url = 'admin:%s_%s_changelist' % (opts.app_label, opts.model_name) if current_url == changelist_url: preserved_filters = request.GET.urlencode() else: preserved_filters = request.GET.get('_changelist_filters') if preserved_filters: return urlencode({'_changelist_filters': preserved_filters}) return ''
def get_queryset(
self, request)
Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view.
def get_queryset(self, request): """ Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view. """ qs = self.model._default_manager.get_queryset() # TODO: this should be handled by some parameter to the ChangeList. ordering = self.get_ordering(request) if ordering: qs = qs.order_by(*ordering) return qs
def get_readonly_fields(
self, request, obj=None)
Hook for specifying custom readonly fields.
def get_readonly_fields(self, request, obj=None): """ Hook for specifying custom readonly fields. """ return self.readonly_fields
def get_search_results(
self, request, queryset, search_term)
Returns a tuple containing a queryset to implement the search, and a boolean indicating if the results may contain duplicates.
def get_search_results(self, request, queryset, search_term): """ Returns a tuple containing a queryset to implement the search, and a boolean indicating if the results may contain duplicates. """ # Apply keyword searches. def construct_search(field_name): if field_name.startswith('^'): return "%s__istartswith" % field_name[1:] elif field_name.startswith('='): return "%s__iexact" % field_name[1:] elif field_name.startswith('@'): return "%s__search" % field_name[1:] else: return "%s__icontains" % field_name use_distinct = False if self.search_fields and search_term: orm_lookups = [construct_search(str(search_field)) for search_field in self.search_fields] for bit in search_term.split(): or_queries = [models.Q(**{orm_lookup: bit}) for orm_lookup in orm_lookups] queryset = queryset.filter(reduce(operator.or_, or_queries)) if not use_distinct: for search_spec in orm_lookups: if lookup_needs_distinct(self.opts, search_spec): use_distinct = True break return queryset, use_distinct
def get_urls(
self)
def get_urls(self): from django.conf.urls import patterns, url def wrap(view): def wrapper(*args, **kwargs): return self.admin_site.admin_view(view)(*args, **kwargs) return update_wrapper(wrapper, view) info = self.model._meta.app_label, self.model._meta.model_name urlpatterns = patterns('', url(r'^$', wrap(self.changelist_view), name='%s_%s_changelist' % info), url(r'^add/$', wrap(self.add_view), name='%s_%s_add' % info), url(r'^(.+)/history/$', wrap(self.history_view), name='%s_%s_history' % info), url(r'^(.+)/delete/$', wrap(self.delete_view), name='%s_%s_delete' % info), url(r'^(.+)/$', wrap(self.change_view), name='%s_%s_change' % info), ) return urlpatterns
def has_add_permission(
self, request)
Returns True if the given request has permission to add an object. Can be overridden by the user in subclasses.
def has_add_permission(self, request): """ Returns True if the given request has permission to add an object. Can be overridden by the user in subclasses. """ opts = self.opts codename = get_permission_codename('add', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_change_permission(
self, request, obj=None)
Returns True if the given request has permission to change the given
Django model instance, the default implementation doesn't examine the
obj
parameter.
Can be overridden by the user in subclasses. In such case it should
return True if the given request has permission to change the obj
model instance. If obj
is None, this should return True if the given
request has permission to change any object of the given type.
def has_change_permission(self, request, obj=None): """ Returns True if the given request has permission to change the given Django model instance, the default implementation doesn't examine the `obj` parameter. Can be overridden by the user in subclasses. In such case it should return True if the given request has permission to change the `obj` model instance. If `obj` is None, this should return True if the given request has permission to change *any* object of the given type. """ opts = self.opts codename = get_permission_codename('change', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_delete_permission(
self, request, obj=None)
Returns True if the given request has permission to change the given
Django model instance, the default implementation doesn't examine the
obj
parameter.
Can be overridden by the user in subclasses. In such case it should
return True if the given request has permission to delete the obj
model instance. If obj
is None, this should return True if the given
request has permission to delete any object of the given type.
def has_delete_permission(self, request, obj=None): """ Returns True if the given request has permission to change the given Django model instance, the default implementation doesn't examine the `obj` parameter. Can be overridden by the user in subclasses. In such case it should return True if the given request has permission to delete the `obj` model instance. If `obj` is None, this should return True if the given request has permission to delete *any* object of the given type. """ opts = self.opts codename = get_permission_codename('delete', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def history_view(
self, request, object_id, extra_context=None)
The 'history' admin view for this model.
def history_view(self, request, object_id, extra_context=None): "The 'history' admin view for this model." from django.contrib.admin.models import LogEntry # First check if the user can see this history. model = self.model obj = get_object_or_404(model, pk=unquote(object_id)) if not self.has_change_permission(request, obj): raise PermissionDenied # Then get the history for this object. opts = model._meta app_label = opts.app_label action_list = LogEntry.objects.filter( object_id=unquote(object_id), content_type__id__exact=ContentType.objects.get_for_model(model).id ).select_related().order_by('action_time') context = { 'title': _('Change history: %s') % force_text(obj), 'action_list': action_list, 'module_name': capfirst(force_text(opts.verbose_name_plural)), 'object': obj, 'app_label': app_label, 'opts': opts, 'preserved_filters': self.get_preserved_filters(request), } context.update(extra_context or {}) return TemplateResponse(request, self.object_history_template or [ "admin/%s/%s/object_history.html" % (app_label, opts.model_name), "admin/%s/object_history.html" % app_label, "admin/object_history.html" ], context, current_app=self.admin_site.name)
def log_addition(
self, request, object)
Log that an object has been successfully added.
The default implementation creates an admin LogEntry object.
def log_addition(self, request, object): """ Log that an object has been successfully added. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, ADDITION LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=ADDITION )
def log_change(
self, request, object, message)
Log that an object has been successfully changed.
The default implementation creates an admin LogEntry object.
def log_change(self, request, object, message): """ Log that an object has been successfully changed. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, CHANGE LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=CHANGE, change_message=message )
def log_deletion(
self, request, object, object_repr)
Log that an object will be deleted. Note that this method is called before the deletion.
The default implementation creates an admin LogEntry object.
def log_deletion(self, request, object, object_repr): """ Log that an object will be deleted. Note that this method is called before the deletion. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, DELETION LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(self.model).pk, object_id=object.pk, object_repr=object_repr, action_flag=DELETION )
def lookup_allowed(
self, lookup, value)
def lookup_allowed(self, lookup, value): model = self.model # Check FKey lookups that are allowed, so that popups produced by # ForeignKeyRawIdWidget, on the basis of ForeignKey.limit_choices_to, # are allowed to work. for l in model._meta.related_fkey_lookups: for k, v in widgets.url_params_from_lookup_dict(l).items(): if k == lookup and v == value: return True parts = lookup.split(LOOKUP_SEP) # Last term in lookup is a query term (__exact, __startswith etc) # This term can be ignored. if len(parts) > 1 and parts[-1] in QUERY_TERMS: parts.pop() # Special case -- foo__id__exact and foo__id queries are implied # if foo has been specifically included in the lookup list; so # drop __id if it is the last part. However, first we need to find # the pk attribute name. rel_name = None for part in parts[:-1]: try: field, _, _, _ = model._meta.get_field_by_name(part) except FieldDoesNotExist: # Lookups on non-existent fields are ok, since they're ignored # later. return True if hasattr(field, 'rel'): if field.rel is None: # This property or relation doesn't exist, but it's allowed # since it's ignored in ChangeList.get_filters(). return True model = field.rel.to rel_name = field.rel.get_related_field().name elif isinstance(field, RelatedObject): model = field.model rel_name = model._meta.pk.name else: rel_name = None if rel_name and len(parts) > 1 and parts[-1] == rel_name: parts.pop() if len(parts) == 1: return True clean_lookup = LOOKUP_SEP.join(parts) return clean_lookup in self.list_filter or clean_lookup == self.date_hierarchy
def message_user(
self, request, message, level=20, extra_tags='', fail_silently=False)
Send a message to the user. The default implementation posts a message using the django.contrib.messages backend.
Exposes almost the same API as messages.add_message(), but accepts the
positional arguments in a different order to maintain backwards
compatibility. For convenience, it accepts the level
argument as
a string rather than the usual level number.
def message_user(self, request, message, level=messages.INFO, extra_tags='', fail_silently=False): """ Send a message to the user. The default implementation posts a message using the django.contrib.messages backend. Exposes almost the same API as messages.add_message(), but accepts the positional arguments in a different order to maintain backwards compatibility. For convenience, it accepts the `level` argument as a string rather than the usual level number. """ if not isinstance(level, int): # attempt to get the level if passed a string try: level = getattr(messages.constants, level.upper()) except AttributeError: levels = messages.constants.DEFAULT_TAGS.values() levels_repr = ', '.join('`%s`' % l for l in levels) raise ValueError('Bad message level string: `%s`. ' 'Possible values are: %s' % (level, levels_repr)) messages.add_message(request, level, message, extra_tags=extra_tags, fail_silently=fail_silently)
def queryset(
*args, **kwargs)
def wrapped(*args, **kwargs): warnings.warn( "`%s.%s` is deprecated, use `%s` instead." % (self.class_name, self.old_method_name, self.new_method_name), self.deprecation_warning, 2) return f(*args, **kwargs)
def render_change_form(
self, request, context, add=False, change=False, form_url='', obj=None)
def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None): opts = self.model._meta app_label = opts.app_label preserved_filters = self.get_preserved_filters(request) form_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, form_url) context.update({ 'add': add, 'change': change, 'has_add_permission': self.has_add_permission(request), 'has_change_permission': self.has_change_permission(request, obj), 'has_delete_permission': self.has_delete_permission(request, obj), 'has_file_field': True, # FIXME - this should check if form or formsets have a FileField, 'has_absolute_url': hasattr(self.model, 'get_absolute_url'), 'form_url': form_url, 'opts': opts, 'content_type_id': ContentType.objects.get_for_model(self.model).id, 'save_as': self.save_as, 'save_on_top': self.save_on_top, }) if add and self.add_form_template is not None: form_template = self.add_form_template else: form_template = self.change_form_template return TemplateResponse(request, form_template or [ "admin/%s/%s/change_form.html" % (app_label, opts.model_name), "admin/%s/change_form.html" % app_label, "admin/change_form.html" ], context, current_app=self.admin_site.name)
def response_action(
self, request, queryset)
Handle an admin action. This is called if a request is POSTed to the changelist; it returns an HttpResponse if the action was handled, and None otherwise.
def response_action(self, request, queryset): """ Handle an admin action. This is called if a request is POSTed to the changelist; it returns an HttpResponse if the action was handled, and None otherwise. """ # There can be multiple action forms on the page (at the top # and bottom of the change list, for example). Get the action # whose button was pushed. try: action_index = int(request.POST.get('index', 0)) except ValueError: action_index = 0 # Construct the action form. data = request.POST.copy() data.pop(helpers.ACTION_CHECKBOX_NAME, None) data.pop("index", None) # Use the action whose button was pushed try: data.update({'action': data.getlist('action')[action_index]}) except IndexError: # If we didn't get an action from the chosen form that's invalid # POST data, so by deleting action it'll fail the validation check # below. So no need to do anything here pass action_form = self.action_form(data, auto_id=None) action_form.fields['action'].choices = self.get_action_choices(request) # If the form's valid we can handle the action. if action_form.is_valid(): action = action_form.cleaned_data['action'] select_across = action_form.cleaned_data['select_across'] func = self.get_actions(request)[action][0] # Get the list of selected PKs. If nothing's selected, we can't # perform an action on it, so bail. Except we want to perform # the action explicitly on all objects. selected = request.POST.getlist(helpers.ACTION_CHECKBOX_NAME) if not selected and not select_across: # Reminder that something needs to be selected or nothing will happen msg = _("Items must be selected in order to perform " "actions on them. No items have been changed.") self.message_user(request, msg, messages.WARNING) return None if not select_across: # Perform the action only on the selected objects queryset = queryset.filter(pk__in=selected) response = func(self, request, queryset) # Actions may return an HttpResponse-like object, which will be # used as the response from the POST. If not, we'll be a good # little HTTP citizen and redirect back to the changelist page. if isinstance(response, HttpResponseBase): return response else: return HttpResponseRedirect(request.get_full_path()) else: msg = _("No action selected.") self.message_user(request, msg, messages.WARNING) return None
def response_add(
self, request, obj, post_url_continue=None)
Determines the HttpResponse for the add_view stage.
def response_add(self, request, obj, post_url_continue=None): """ Determines the HttpResponse for the add_view stage. """ opts = obj._meta pk_value = obj._get_pk_val() preserved_filters = self.get_preserved_filters(request) msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)} # Here, we distinguish between different save types by checking for # the presence of keys in request.POST. if IS_POPUP_VAR in request.POST: return SimpleTemplateResponse('admin/popup_response.html', { 'pk_value': escape(pk_value), 'obj': escapejs(obj) }) elif "_continue" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) if post_url_continue is None: post_url_continue = reverse('admin:%s_%s_change' % (opts.app_label, opts.model_name), args=(pk_value,), current_app=self.admin_site.name) post_url_continue = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url_continue) return HttpResponseRedirect(post_url_continue) elif "_addanother" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may add another %(name)s below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = request.path redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) else: msg = _('The %(name)s "%(obj)s" was added successfully.') % msg_dict self.message_user(request, msg, messages.SUCCESS) return self.response_post_save_add(request, obj)
def response_change(
self, request, obj)
Determines the HttpResponse for the change_view stage.
def response_change(self, request, obj): """ Determines the HttpResponse for the change_view stage. """ opts = self.model._meta pk_value = obj._get_pk_val() preserved_filters = self.get_preserved_filters(request) msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)} if "_continue" in request.POST: msg = _('The %(name)s "%(obj)s" was changed successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = request.path redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) elif "_saveasnew" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = reverse('admin:%s_%s_change' % (opts.app_label, opts.model_name), args=(pk_value,), current_app=self.admin_site.name) redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) elif "_addanother" in request.POST: msg = _('The %(name)s "%(obj)s" was changed successfully. You may add another %(name)s below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = reverse('admin:%s_%s_add' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) else: msg = _('The %(name)s "%(obj)s" was changed successfully.') % msg_dict self.message_user(request, msg, messages.SUCCESS) return self.response_post_save_change(request, obj)
def response_post_save_add(
self, request, obj)
Figure out where to redirect after the 'Save' button has been pressed when adding a new object.
def response_post_save_add(self, request, obj): """ Figure out where to redirect after the 'Save' button has been pressed when adding a new object. """ opts = self.model._meta if self.has_change_permission(request, None): post_url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url) else: post_url = reverse('admin:index', current_app=self.admin_site.name) return HttpResponseRedirect(post_url)
def response_post_save_change(
self, request, obj)
Figure out where to redirect after the 'Save' button has been pressed when editing an existing object.
def response_post_save_change(self, request, obj): """ Figure out where to redirect after the 'Save' button has been pressed when editing an existing object. """ opts = self.model._meta if self.has_change_permission(request, None): post_url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url) else: post_url = reverse('admin:index', current_app=self.admin_site.name) return HttpResponseRedirect(post_url)
def save_form(
self, request, form, change)
Given a ModelForm return an unsaved instance. change
is True if
the object is being changed, and False if it's being added.
def save_form(self, request, form, change): """ Given a ModelForm return an unsaved instance. ``change`` is True if the object is being changed, and False if it's being added. """ return form.save(commit=False)
def save_formset(
self, request, form, formset, change)
Given an inline formset save it to the database.
def save_formset(self, request, form, formset, change): """ Given an inline formset save it to the database. """ formset.save()
def save_model(
self, request, obj, form, change)
Given a model instance save it to the database.
def save_model(self, request, obj, form, change): """ Given a model instance save it to the database. """ obj.save()
Given the HttpRequest
, the parent ModelForm
instance, the
list of inline formsets and a boolean value based on whether the
parent is being added or changed, save the related objects to the
database. Note that at this point save_form() and save_model() have
already been called.
def to_field_allowed(
self, request, to_field)
Returns True if the model associated with this admin should be allowed to be referenced by the specified field.
def to_field_allowed(self, request, to_field): """ Returns True if the model associated with this admin should be allowed to be referenced by the specified field. """ opts = self.model._meta try: field = opts.get_field(to_field) except FieldDoesNotExist: return False # Always allow referencing the primary key since it's already possible # to get this information from the change view URL. if field.primary_key: return True # Make sure at least one of the models registered for this site # references this field through a FK or a M2M relationship. registered_models = set() for model, admin in self.admin_site._registry.items(): registered_models.add(model) for inline in admin.inlines: registered_models.add(inline.model) for related_object in opts.get_all_related_objects(include_hidden=True): related_model = related_object.model if (any(issubclass(model, related_model) for model in registered_models) and related_object.field.rel.get_related_field() == field): return True return False
def validate(
cls, model)
@classmethod def validate(cls, model): validator = cls.validator_class() validator.validate(cls, model)
class InstrumentAliasAdmin
class InstrumentAliasAdmin(admin.ModelAdmin): search_fields = ['name'] ordering = ['name']
Ancestors (in MRO)
- InstrumentAliasAdmin
- django.contrib.admin.options.ModelAdmin
- django.contrib.admin.options.BaseModelAdmin
- __builtin__.object
Class variables
var action_form
var actions
var actions_on_bottom
var actions_on_top
var actions_selection_counter
var add_form_template
var change_form_template
var change_list_template
var date_hierarchy
var delete_confirmation_template
var delete_selected_confirmation_template
var exclude
var fields
var fieldsets
var filter_horizontal
var filter_vertical
var form
var formfield_overrides
var inlines
var list_display
var list_display_links
var list_editable
var list_filter
var list_max_show_all
var list_per_page
var object_history_template
var ordering
var paginator
var prepopulated_fields
var preserve_filters
var radio_fields
var raw_id_fields
var readonly_fields
var save_as
var save_on_top
var search_fields
var validator_class
Instance variables
var declared_fieldsets
var media
var urls
Methods
def __init__(
self, model, admin_site)
def __init__(self, model, admin_site): self.model = model self.opts = model._meta self.admin_site = admin_site super(ModelAdmin, self).__init__()
def action_checkbox(
self, obj)
A list_display column containing a checkbox widget.
def action_checkbox(self, obj): """ A list_display column containing a checkbox widget. """ return helpers.checkbox.render(helpers.ACTION_CHECKBOX_NAME, force_text(obj.pk))
def add_view(
self, *args, **kwargs)
The 'add' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def change_view(
self, *args, **kwargs)
The 'change' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def changelist_view(
self, *args, **kwargs)
The 'change list' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def construct_change_message(
self, request, form, formsets)
Construct a change message from a changed object.
def construct_change_message(self, request, form, formsets): """ Construct a change message from a changed object. """ change_message = [] if form.changed_data: change_message.append(_('Changed %s.') % get_text_list(form.changed_data, _('and'))) if formsets: for formset in formsets: for added_object in formset.new_objects: change_message.append(_('Added %(name)s "%(object)s".') % {'name': force_text(added_object._meta.verbose_name), 'object': force_text(added_object)}) for changed_object, changed_fields in formset.changed_objects: change_message.append(_('Changed %(list)s for %(name)s "%(object)s".') % {'list': get_text_list(changed_fields, _('and')), 'name': force_text(changed_object._meta.verbose_name), 'object': force_text(changed_object)}) for deleted_object in formset.deleted_objects: change_message.append(_('Deleted %(name)s "%(object)s".') % {'name': force_text(deleted_object._meta.verbose_name), 'object': force_text(deleted_object)}) change_message = ' '.join(change_message) return change_message or _('No fields changed.')
def delete_model(
self, request, obj)
Given a model instance delete it from the database.
def delete_model(self, request, obj): """ Given a model instance delete it from the database. """ obj.delete()
def delete_view(
self, *args, **kwargs)
The 'delete' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def formfield_for_choice_field(
self, db_field, request=None, **kwargs)
Get a form Field for a database Field that has declared choices.
def formfield_for_choice_field(self, db_field, request=None, **kwargs): """ Get a form Field for a database Field that has declared choices. """ # If the field is named as a radio_field, use a RadioSelect if db_field.name in self.radio_fields: # Avoid stomping on custom widget/choices arguments. if 'widget' not in kwargs: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) if 'choices' not in kwargs: kwargs['choices'] = db_field.get_choices( include_blank=db_field.blank, blank_choice=[('', _('None'))] ) return db_field.formfield(**kwargs)
def formfield_for_dbfield(
self, db_field, **kwargs)
Hook for specifying the form Field instance for a given database Field instance.
If kwargs are given, they're passed to the form Field's constructor.
def formfield_for_dbfield(self, db_field, **kwargs): """ Hook for specifying the form Field instance for a given database Field instance. If kwargs are given, they're passed to the form Field's constructor. """ request = kwargs.pop("request", None) # If the field specifies choices, we don't need to look for special # admin widgets - we just need to use a select widget of some kind. if db_field.choices: return self.formfield_for_choice_field(db_field, request, **kwargs) # ForeignKey or ManyToManyFields if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)): # Combine the field kwargs with any options for formfield_overrides. # Make sure the passed in **kwargs override anything in # formfield_overrides because **kwargs is more specific, and should # always win. if db_field.__class__ in self.formfield_overrides: kwargs = dict(self.formfield_overrides[db_field.__class__], **kwargs) # Get the correct formfield. if isinstance(db_field, models.ForeignKey): formfield = self.formfield_for_foreignkey(db_field, request, **kwargs) elif isinstance(db_field, models.ManyToManyField): formfield = self.formfield_for_manytomany(db_field, request, **kwargs) # For non-raw_id fields, wrap the widget with a wrapper that adds # extra HTML -- the "add other" interface -- to the end of the # rendered output. formfield can be None if it came from a # OneToOneField with parent_link=True or a M2M intermediary. if formfield and db_field.name not in self.raw_id_fields: related_modeladmin = self.admin_site._registry.get( db_field.rel.to) can_add_related = bool(related_modeladmin and related_modeladmin.has_add_permission(request)) formfield.widget = widgets.RelatedFieldWidgetWrapper( formfield.widget, db_field.rel, self.admin_site, can_add_related=can_add_related) return formfield # If we've got overrides for the formfield defined, use 'em. **kwargs # passed to formfield_for_dbfield override the defaults. for klass in db_field.__class__.mro(): if klass in self.formfield_overrides: kwargs = dict(copy.deepcopy(self.formfield_overrides[klass]), **kwargs) return db_field.formfield(**kwargs) # For any other type of field, just call its formfield() method. return db_field.formfield(**kwargs)
def formfield_for_foreignkey(
self, db_field, request=None, **kwargs)
Get a form Field for a ForeignKey.
def formfield_for_foreignkey(self, db_field, request=None, **kwargs): """ Get a form Field for a ForeignKey. """ db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel, self.admin_site, using=db) elif db_field.name in self.radio_fields: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) kwargs['empty_label'] = _('None') if db_field.blank else None if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def formfield_for_manytomany(
self, db_field, request=None, **kwargs)
Get a form Field for a ManyToManyField.
def formfield_for_manytomany(self, db_field, request=None, **kwargs): """ Get a form Field for a ManyToManyField. """ # If it uses an intermediary model that isn't auto created, don't show # a field in admin. if not db_field.rel.through._meta.auto_created: return None db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel, self.admin_site, using=db) kwargs['help_text'] = '' elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)): kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical)) if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def get_action(
self, action)
Return a given action from a parameter, which can either be a callable, or the name of a method on the ModelAdmin. Return is a tuple of (callable, name, description).
def get_action(self, action): """ Return a given action from a parameter, which can either be a callable, or the name of a method on the ModelAdmin. Return is a tuple of (callable, name, description). """ # If the action is a callable, just use it. if callable(action): func = action action = action.__name__ # Next, look for a method. Grab it off self.__class__ to get an unbound # method instead of a bound one; this ensures that the calling # conventions are the same for functions and methods. elif hasattr(self.__class__, action): func = getattr(self.__class__, action) # Finally, look for a named method on the admin site else: try: func = self.admin_site.get_action(action) except KeyError: return None if hasattr(func, 'short_description'): description = func.short_description else: description = capfirst(action.replace('_', ' ')) return func, action, description
def get_action_choices(
self, request, default_choices=[(u'', u'---------')])
Return a list of choices for use in a form object. Each choice is a tuple (name, description).
def get_action_choices(self, request, default_choices=BLANK_CHOICE_DASH): """ Return a list of choices for use in a form object. Each choice is a tuple (name, description). """ choices = [] + default_choices for func, name, description in six.itervalues(self.get_actions(request)): choice = (name, description % model_format_dict(self.opts)) choices.append(choice) return choices
def get_actions(
self, request)
Return a dictionary mapping the names of all actions for this ModelAdmin to a tuple of (callable, name, description) for each action.
def get_actions(self, request): """ Return a dictionary mapping the names of all actions for this ModelAdmin to a tuple of (callable, name, description) for each action. """ # If self.actions is explicitly set to None that means that we don't # want *any* actions enabled on this page. from django.contrib.admin.views.main import _is_changelist_popup if self.actions is None or _is_changelist_popup(request): return SortedDict() actions = [] # Gather actions from the admin site first for (name, func) in self.admin_site.actions: description = getattr(func, 'short_description', name.replace('_', ' ')) actions.append((func, name, description)) # Then gather them from the model admin and all parent classes, # starting with self and working back up. for klass in self.__class__.mro()[::-1]: class_actions = getattr(klass, 'actions', []) # Avoid trying to iterate over None if not class_actions: continue actions.extend([self.get_action(action) for action in class_actions]) # get_action might have returned None, so filter any of those out. actions = filter(None, actions) # Convert the actions into a SortedDict keyed by name. actions = SortedDict([ (name, (func, name, desc)) for func, name, desc in actions ]) return actions
def get_changelist(
self, request, **kwargs)
Returns the ChangeList class for use on the changelist page.
def get_changelist(self, request, **kwargs): """ Returns the ChangeList class for use on the changelist page. """ from django.contrib.admin.views.main import ChangeList return ChangeList
def get_changelist_form(
self, request, **kwargs)
Returns a Form class for use in the Formset on the changelist page.
def get_changelist_form(self, request, **kwargs): """ Returns a Form class for use in the Formset on the changelist page. """ defaults = { "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) if (defaults.get('fields') is None and not modelform_defines_fields(defaults.get('form'))): defaults['fields'] = forms.ALL_FIELDS return modelform_factory(self.model, **defaults)
def get_changelist_formset(
self, request, **kwargs)
Returns a FormSet class for use on the changelist page if list_editable is used.
def get_changelist_formset(self, request, **kwargs): """ Returns a FormSet class for use on the changelist page if list_editable is used. """ defaults = { "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) return modelformset_factory(self.model, self.get_changelist_form(request), extra=0, fields=self.list_editable, **defaults)
def get_field_queryset(
self, db, db_field, request)
If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case).
def get_field_queryset(self, db, db_field, request): """ If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case). """ related_admin = self.admin_site._registry.get(db_field.rel.to, None) if related_admin is not None: ordering = related_admin.get_ordering(request) if ordering is not None and ordering != (): return db_field.rel.to._default_manager.using(db).order_by(*ordering).complex_filter(db_field.rel.limit_choices_to) return None
def get_fieldsets(
self, request, obj=None)
Hook for specifying fieldsets for the add form.
def get_fieldsets(self, request, obj=None): "Hook for specifying fieldsets for the add form." if self.declared_fieldsets: return self.declared_fieldsets form = self.get_form(request, obj, fields=None) fields = list(form.base_fields) + list(self.get_readonly_fields(request, obj)) return [(None, {'fields': fields})]
def get_form(
self, request, obj=None, **kwargs)
Returns a Form class for use in the admin add view. This is used by add_view and change_view.
def get_form(self, request, obj=None, **kwargs): """ Returns a Form class for use in the admin add view. This is used by add_view and change_view. """ if 'fields' in kwargs: fields = kwargs.pop('fields') else: fields = flatten_fieldsets(self.get_fieldsets(request, obj)) if self.exclude is None: exclude = [] else: exclude = list(self.exclude) exclude.extend(self.get_readonly_fields(request, obj)) if self.exclude is None and hasattr(self.form, '_meta') and self.form._meta.exclude: # Take the custom ModelForm's Meta.exclude into account only if the # ModelAdmin doesn't define its own. exclude.extend(self.form._meta.exclude) # if exclude is an empty list we pass None to be consistent with the # default on modelform_factory exclude = exclude or None defaults = { "form": self.form, "fields": fields, "exclude": exclude, "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) if defaults['fields'] is None and not modelform_defines_fields(defaults['form']): defaults['fields'] = forms.ALL_FIELDS try: return modelform_factory(self.model, **defaults) except FieldError as e: raise FieldError('%s. Check fields/fieldsets/exclude attributes of class %s.' % (e, self.__class__.__name__))
def get_formsets(
self, request, obj=None)
def get_formsets(self, request, obj=None): for inline in self.get_inline_instances(request, obj): yield inline.get_formset(request, obj)
def get_inline_instances(
self, request, obj=None)
def get_inline_instances(self, request, obj=None): inline_instances = [] for inline_class in self.inlines: inline = inline_class(self.model, self.admin_site) if request: if not (inline.has_add_permission(request) or inline.has_change_permission(request, obj) or inline.has_delete_permission(request, obj)): continue if not inline.has_add_permission(request): inline.max_num = 0 inline_instances.append(inline) return inline_instances
def get_list_display(
self, request)
Return a sequence containing the fields to be displayed on the changelist.
def get_list_display(self, request): """ Return a sequence containing the fields to be displayed on the changelist. """ return self.list_display
def get_list_display_links(
self, request, list_display)
Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display().
def get_list_display_links(self, request, list_display): """ Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display(). """ if self.list_display_links or not list_display: return self.list_display_links else: # Use only the first item in list_display as link return list(list_display)[:1]
def get_list_filter(
self, request)
Returns a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page.
def get_list_filter(self, request): """ Returns a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page. """ return self.list_filter
def get_model_perms(
self, request)
Returns a dict of all perms for this model. This dict has the keys
add
, change
, and delete
mapping to the True/False for each
of those actions.
def get_model_perms(self, request): """ Returns a dict of all perms for this model. This dict has the keys ``add``, ``change``, and ``delete`` mapping to the True/False for each of those actions. """ return { 'add': self.has_add_permission(request), 'change': self.has_change_permission(request), 'delete': self.has_delete_permission(request), }
def get_object(
self, request, object_id)
Returns an instance matching the primary key provided. None
is
returned if no match is found (or the object_id failed validation
against the primary key field).
def get_object(self, request, object_id): """ Returns an instance matching the primary key provided. ``None`` is returned if no match is found (or the object_id failed validation against the primary key field). """ queryset = self.get_queryset(request) model = queryset.model try: object_id = model._meta.pk.to_python(object_id) return queryset.get(pk=object_id) except (model.DoesNotExist, ValidationError, ValueError): return None
def get_ordering(
self, request)
Hook for specifying field ordering.
def get_ordering(self, request): """ Hook for specifying field ordering. """ return self.ordering or () # otherwise we might try to *None, which is bad ;)
def get_paginator(
self, request, queryset, per_page, orphans=0, allow_empty_first_page=True)
def get_paginator(self, request, queryset, per_page, orphans=0, allow_empty_first_page=True): return self.paginator(queryset, per_page, orphans, allow_empty_first_page)
def get_prepopulated_fields(
self, request, obj=None)
Hook for specifying custom prepopulated fields.
def get_prepopulated_fields(self, request, obj=None): """ Hook for specifying custom prepopulated fields. """ return self.prepopulated_fields
def get_preserved_filters(
self, request)
Returns the preserved filters querystring.
def get_preserved_filters(self, request): """ Returns the preserved filters querystring. """ match = request.resolver_match if self.preserve_filters and match: opts = self.model._meta current_url = '%s:%s' % (match.app_name, match.url_name) changelist_url = 'admin:%s_%s_changelist' % (opts.app_label, opts.model_name) if current_url == changelist_url: preserved_filters = request.GET.urlencode() else: preserved_filters = request.GET.get('_changelist_filters') if preserved_filters: return urlencode({'_changelist_filters': preserved_filters}) return ''
def get_queryset(
self, request)
Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view.
def get_queryset(self, request): """ Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view. """ qs = self.model._default_manager.get_queryset() # TODO: this should be handled by some parameter to the ChangeList. ordering = self.get_ordering(request) if ordering: qs = qs.order_by(*ordering) return qs
def get_readonly_fields(
self, request, obj=None)
Hook for specifying custom readonly fields.
def get_readonly_fields(self, request, obj=None): """ Hook for specifying custom readonly fields. """ return self.readonly_fields
def get_search_results(
self, request, queryset, search_term)
Returns a tuple containing a queryset to implement the search, and a boolean indicating if the results may contain duplicates.
def get_search_results(self, request, queryset, search_term): """ Returns a tuple containing a queryset to implement the search, and a boolean indicating if the results may contain duplicates. """ # Apply keyword searches. def construct_search(field_name): if field_name.startswith('^'): return "%s__istartswith" % field_name[1:] elif field_name.startswith('='): return "%s__iexact" % field_name[1:] elif field_name.startswith('@'): return "%s__search" % field_name[1:] else: return "%s__icontains" % field_name use_distinct = False if self.search_fields and search_term: orm_lookups = [construct_search(str(search_field)) for search_field in self.search_fields] for bit in search_term.split(): or_queries = [models.Q(**{orm_lookup: bit}) for orm_lookup in orm_lookups] queryset = queryset.filter(reduce(operator.or_, or_queries)) if not use_distinct: for search_spec in orm_lookups: if lookup_needs_distinct(self.opts, search_spec): use_distinct = True break return queryset, use_distinct
def get_urls(
self)
def get_urls(self): from django.conf.urls import patterns, url def wrap(view): def wrapper(*args, **kwargs): return self.admin_site.admin_view(view)(*args, **kwargs) return update_wrapper(wrapper, view) info = self.model._meta.app_label, self.model._meta.model_name urlpatterns = patterns('', url(r'^$', wrap(self.changelist_view), name='%s_%s_changelist' % info), url(r'^add/$', wrap(self.add_view), name='%s_%s_add' % info), url(r'^(.+)/history/$', wrap(self.history_view), name='%s_%s_history' % info), url(r'^(.+)/delete/$', wrap(self.delete_view), name='%s_%s_delete' % info), url(r'^(.+)/$', wrap(self.change_view), name='%s_%s_change' % info), ) return urlpatterns
def has_add_permission(
self, request)
Returns True if the given request has permission to add an object. Can be overridden by the user in subclasses.
def has_add_permission(self, request): """ Returns True if the given request has permission to add an object. Can be overridden by the user in subclasses. """ opts = self.opts codename = get_permission_codename('add', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_change_permission(
self, request, obj=None)
Returns True if the given request has permission to change the given
Django model instance, the default implementation doesn't examine the
obj
parameter.
Can be overridden by the user in subclasses. In such case it should
return True if the given request has permission to change the obj
model instance. If obj
is None, this should return True if the given
request has permission to change any object of the given type.
def has_change_permission(self, request, obj=None): """ Returns True if the given request has permission to change the given Django model instance, the default implementation doesn't examine the `obj` parameter. Can be overridden by the user in subclasses. In such case it should return True if the given request has permission to change the `obj` model instance. If `obj` is None, this should return True if the given request has permission to change *any* object of the given type. """ opts = self.opts codename = get_permission_codename('change', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_delete_permission(
self, request, obj=None)
Returns True if the given request has permission to change the given
Django model instance, the default implementation doesn't examine the
obj
parameter.
Can be overridden by the user in subclasses. In such case it should
return True if the given request has permission to delete the obj
model instance. If obj
is None, this should return True if the given
request has permission to delete any object of the given type.
def has_delete_permission(self, request, obj=None): """ Returns True if the given request has permission to change the given Django model instance, the default implementation doesn't examine the `obj` parameter. Can be overridden by the user in subclasses. In such case it should return True if the given request has permission to delete the `obj` model instance. If `obj` is None, this should return True if the given request has permission to delete *any* object of the given type. """ opts = self.opts codename = get_permission_codename('delete', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def history_view(
self, request, object_id, extra_context=None)
The 'history' admin view for this model.
def history_view(self, request, object_id, extra_context=None): "The 'history' admin view for this model." from django.contrib.admin.models import LogEntry # First check if the user can see this history. model = self.model obj = get_object_or_404(model, pk=unquote(object_id)) if not self.has_change_permission(request, obj): raise PermissionDenied # Then get the history for this object. opts = model._meta app_label = opts.app_label action_list = LogEntry.objects.filter( object_id=unquote(object_id), content_type__id__exact=ContentType.objects.get_for_model(model).id ).select_related().order_by('action_time') context = { 'title': _('Change history: %s') % force_text(obj), 'action_list': action_list, 'module_name': capfirst(force_text(opts.verbose_name_plural)), 'object': obj, 'app_label': app_label, 'opts': opts, 'preserved_filters': self.get_preserved_filters(request), } context.update(extra_context or {}) return TemplateResponse(request, self.object_history_template or [ "admin/%s/%s/object_history.html" % (app_label, opts.model_name), "admin/%s/object_history.html" % app_label, "admin/object_history.html" ], context, current_app=self.admin_site.name)
def log_addition(
self, request, object)
Log that an object has been successfully added.
The default implementation creates an admin LogEntry object.
def log_addition(self, request, object): """ Log that an object has been successfully added. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, ADDITION LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=ADDITION )
def log_change(
self, request, object, message)
Log that an object has been successfully changed.
The default implementation creates an admin LogEntry object.
def log_change(self, request, object, message): """ Log that an object has been successfully changed. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, CHANGE LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=CHANGE, change_message=message )
def log_deletion(
self, request, object, object_repr)
Log that an object will be deleted. Note that this method is called before the deletion.
The default implementation creates an admin LogEntry object.
def log_deletion(self, request, object, object_repr): """ Log that an object will be deleted. Note that this method is called before the deletion. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, DELETION LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(self.model).pk, object_id=object.pk, object_repr=object_repr, action_flag=DELETION )
def lookup_allowed(
self, lookup, value)
def lookup_allowed(self, lookup, value): model = self.model # Check FKey lookups that are allowed, so that popups produced by # ForeignKeyRawIdWidget, on the basis of ForeignKey.limit_choices_to, # are allowed to work. for l in model._meta.related_fkey_lookups: for k, v in widgets.url_params_from_lookup_dict(l).items(): if k == lookup and v == value: return True parts = lookup.split(LOOKUP_SEP) # Last term in lookup is a query term (__exact, __startswith etc) # This term can be ignored. if len(parts) > 1 and parts[-1] in QUERY_TERMS: parts.pop() # Special case -- foo__id__exact and foo__id queries are implied # if foo has been specifically included in the lookup list; so # drop __id if it is the last part. However, first we need to find # the pk attribute name. rel_name = None for part in parts[:-1]: try: field, _, _, _ = model._meta.get_field_by_name(part) except FieldDoesNotExist: # Lookups on non-existent fields are ok, since they're ignored # later. return True if hasattr(field, 'rel'): if field.rel is None: # This property or relation doesn't exist, but it's allowed # since it's ignored in ChangeList.get_filters(). return True model = field.rel.to rel_name = field.rel.get_related_field().name elif isinstance(field, RelatedObject): model = field.model rel_name = model._meta.pk.name else: rel_name = None if rel_name and len(parts) > 1 and parts[-1] == rel_name: parts.pop() if len(parts) == 1: return True clean_lookup = LOOKUP_SEP.join(parts) return clean_lookup in self.list_filter or clean_lookup == self.date_hierarchy
def message_user(
self, request, message, level=20, extra_tags='', fail_silently=False)
Send a message to the user. The default implementation posts a message using the django.contrib.messages backend.
Exposes almost the same API as messages.add_message(), but accepts the
positional arguments in a different order to maintain backwards
compatibility. For convenience, it accepts the level
argument as
a string rather than the usual level number.
def message_user(self, request, message, level=messages.INFO, extra_tags='', fail_silently=False): """ Send a message to the user. The default implementation posts a message using the django.contrib.messages backend. Exposes almost the same API as messages.add_message(), but accepts the positional arguments in a different order to maintain backwards compatibility. For convenience, it accepts the `level` argument as a string rather than the usual level number. """ if not isinstance(level, int): # attempt to get the level if passed a string try: level = getattr(messages.constants, level.upper()) except AttributeError: levels = messages.constants.DEFAULT_TAGS.values() levels_repr = ', '.join('`%s`' % l for l in levels) raise ValueError('Bad message level string: `%s`. ' 'Possible values are: %s' % (level, levels_repr)) messages.add_message(request, level, message, extra_tags=extra_tags, fail_silently=fail_silently)
def queryset(
*args, **kwargs)
def wrapped(*args, **kwargs): warnings.warn( "`%s.%s` is deprecated, use `%s` instead." % (self.class_name, self.old_method_name, self.new_method_name), self.deprecation_warning, 2) return f(*args, **kwargs)
def render_change_form(
self, request, context, add=False, change=False, form_url='', obj=None)
def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None): opts = self.model._meta app_label = opts.app_label preserved_filters = self.get_preserved_filters(request) form_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, form_url) context.update({ 'add': add, 'change': change, 'has_add_permission': self.has_add_permission(request), 'has_change_permission': self.has_change_permission(request, obj), 'has_delete_permission': self.has_delete_permission(request, obj), 'has_file_field': True, # FIXME - this should check if form or formsets have a FileField, 'has_absolute_url': hasattr(self.model, 'get_absolute_url'), 'form_url': form_url, 'opts': opts, 'content_type_id': ContentType.objects.get_for_model(self.model).id, 'save_as': self.save_as, 'save_on_top': self.save_on_top, }) if add and self.add_form_template is not None: form_template = self.add_form_template else: form_template = self.change_form_template return TemplateResponse(request, form_template or [ "admin/%s/%s/change_form.html" % (app_label, opts.model_name), "admin/%s/change_form.html" % app_label, "admin/change_form.html" ], context, current_app=self.admin_site.name)
def response_action(
self, request, queryset)
Handle an admin action. This is called if a request is POSTed to the changelist; it returns an HttpResponse if the action was handled, and None otherwise.
def response_action(self, request, queryset): """ Handle an admin action. This is called if a request is POSTed to the changelist; it returns an HttpResponse if the action was handled, and None otherwise. """ # There can be multiple action forms on the page (at the top # and bottom of the change list, for example). Get the action # whose button was pushed. try: action_index = int(request.POST.get('index', 0)) except ValueError: action_index = 0 # Construct the action form. data = request.POST.copy() data.pop(helpers.ACTION_CHECKBOX_NAME, None) data.pop("index", None) # Use the action whose button was pushed try: data.update({'action': data.getlist('action')[action_index]}) except IndexError: # If we didn't get an action from the chosen form that's invalid # POST data, so by deleting action it'll fail the validation check # below. So no need to do anything here pass action_form = self.action_form(data, auto_id=None) action_form.fields['action'].choices = self.get_action_choices(request) # If the form's valid we can handle the action. if action_form.is_valid(): action = action_form.cleaned_data['action'] select_across = action_form.cleaned_data['select_across'] func = self.get_actions(request)[action][0] # Get the list of selected PKs. If nothing's selected, we can't # perform an action on it, so bail. Except we want to perform # the action explicitly on all objects. selected = request.POST.getlist(helpers.ACTION_CHECKBOX_NAME) if not selected and not select_across: # Reminder that something needs to be selected or nothing will happen msg = _("Items must be selected in order to perform " "actions on them. No items have been changed.") self.message_user(request, msg, messages.WARNING) return None if not select_across: # Perform the action only on the selected objects queryset = queryset.filter(pk__in=selected) response = func(self, request, queryset) # Actions may return an HttpResponse-like object, which will be # used as the response from the POST. If not, we'll be a good # little HTTP citizen and redirect back to the changelist page. if isinstance(response, HttpResponseBase): return response else: return HttpResponseRedirect(request.get_full_path()) else: msg = _("No action selected.") self.message_user(request, msg, messages.WARNING) return None
def response_add(
self, request, obj, post_url_continue=None)
Determines the HttpResponse for the add_view stage.
def response_add(self, request, obj, post_url_continue=None): """ Determines the HttpResponse for the add_view stage. """ opts = obj._meta pk_value = obj._get_pk_val() preserved_filters = self.get_preserved_filters(request) msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)} # Here, we distinguish between different save types by checking for # the presence of keys in request.POST. if IS_POPUP_VAR in request.POST: return SimpleTemplateResponse('admin/popup_response.html', { 'pk_value': escape(pk_value), 'obj': escapejs(obj) }) elif "_continue" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) if post_url_continue is None: post_url_continue = reverse('admin:%s_%s_change' % (opts.app_label, opts.model_name), args=(pk_value,), current_app=self.admin_site.name) post_url_continue = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url_continue) return HttpResponseRedirect(post_url_continue) elif "_addanother" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may add another %(name)s below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = request.path redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) else: msg = _('The %(name)s "%(obj)s" was added successfully.') % msg_dict self.message_user(request, msg, messages.SUCCESS) return self.response_post_save_add(request, obj)
def response_change(
self, request, obj)
Determines the HttpResponse for the change_view stage.
def response_change(self, request, obj): """ Determines the HttpResponse for the change_view stage. """ opts = self.model._meta pk_value = obj._get_pk_val() preserved_filters = self.get_preserved_filters(request) msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)} if "_continue" in request.POST: msg = _('The %(name)s "%(obj)s" was changed successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = request.path redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) elif "_saveasnew" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = reverse('admin:%s_%s_change' % (opts.app_label, opts.model_name), args=(pk_value,), current_app=self.admin_site.name) redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) elif "_addanother" in request.POST: msg = _('The %(name)s "%(obj)s" was changed successfully. You may add another %(name)s below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = reverse('admin:%s_%s_add' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) else: msg = _('The %(name)s "%(obj)s" was changed successfully.') % msg_dict self.message_user(request, msg, messages.SUCCESS) return self.response_post_save_change(request, obj)
def response_post_save_add(
self, request, obj)
Figure out where to redirect after the 'Save' button has been pressed when adding a new object.
def response_post_save_add(self, request, obj): """ Figure out where to redirect after the 'Save' button has been pressed when adding a new object. """ opts = self.model._meta if self.has_change_permission(request, None): post_url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url) else: post_url = reverse('admin:index', current_app=self.admin_site.name) return HttpResponseRedirect(post_url)
def response_post_save_change(
self, request, obj)
Figure out where to redirect after the 'Save' button has been pressed when editing an existing object.
def response_post_save_change(self, request, obj): """ Figure out where to redirect after the 'Save' button has been pressed when editing an existing object. """ opts = self.model._meta if self.has_change_permission(request, None): post_url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url) else: post_url = reverse('admin:index', current_app=self.admin_site.name) return HttpResponseRedirect(post_url)
def save_form(
self, request, form, change)
Given a ModelForm return an unsaved instance. change
is True if
the object is being changed, and False if it's being added.
def save_form(self, request, form, change): """ Given a ModelForm return an unsaved instance. ``change`` is True if the object is being changed, and False if it's being added. """ return form.save(commit=False)
def save_formset(
self, request, form, formset, change)
Given an inline formset save it to the database.
def save_formset(self, request, form, formset, change): """ Given an inline formset save it to the database. """ formset.save()
def save_model(
self, request, obj, form, change)
Given a model instance save it to the database.
def save_model(self, request, obj, form, change): """ Given a model instance save it to the database. """ obj.save()
Given the HttpRequest
, the parent ModelForm
instance, the
list of inline formsets and a boolean value based on whether the
parent is being added or changed, save the related objects to the
database. Note that at this point save_form() and save_model() have
already been called.
def to_field_allowed(
self, request, to_field)
Returns True if the model associated with this admin should be allowed to be referenced by the specified field.
def to_field_allowed(self, request, to_field): """ Returns True if the model associated with this admin should be allowed to be referenced by the specified field. """ opts = self.model._meta try: field = opts.get_field(to_field) except FieldDoesNotExist: return False # Always allow referencing the primary key since it's already possible # to get this information from the change view URL. if field.primary_key: return True # Make sure at least one of the models registered for this site # references this field through a FK or a M2M relationship. registered_models = set() for model, admin in self.admin_site._registry.items(): registered_models.add(model) for inline in admin.inlines: registered_models.add(inline.model) for related_object in opts.get_all_related_objects(include_hidden=True): related_model = related_object.model if (any(issubclass(model, related_model) for model in registered_models) and related_object.field.rel.get_related_field() == field): return True return False
def validate(
cls, model)
@classmethod def validate(cls, model): validator = cls.validator_class() validator.validate(cls, model)
class InstrumentAliasRelationAdmin
class InstrumentAliasRelationAdmin(admin.ModelAdmin): search_fields = ['alias__name', 'instrument__name'] ordering = ['alias__name']
Ancestors (in MRO)
- InstrumentAliasRelationAdmin
- django.contrib.admin.options.ModelAdmin
- django.contrib.admin.options.BaseModelAdmin
- __builtin__.object
Class variables
var action_form
var actions
var actions_on_bottom
var actions_on_top
var actions_selection_counter
var add_form_template
var change_form_template
var change_list_template
var date_hierarchy
var delete_confirmation_template
var delete_selected_confirmation_template
var exclude
var fields
var fieldsets
var filter_horizontal
var filter_vertical
var form
var formfield_overrides
var inlines
var list_display
var list_display_links
var list_editable
var list_filter
var list_max_show_all
var list_per_page
var object_history_template
var ordering
var paginator
var prepopulated_fields
var preserve_filters
var radio_fields
var raw_id_fields
var readonly_fields
var save_as
var save_on_top
var search_fields
var validator_class
Instance variables
var declared_fieldsets
var media
var urls
Methods
def __init__(
self, model, admin_site)
def __init__(self, model, admin_site): self.model = model self.opts = model._meta self.admin_site = admin_site super(ModelAdmin, self).__init__()
def action_checkbox(
self, obj)
A list_display column containing a checkbox widget.
def action_checkbox(self, obj): """ A list_display column containing a checkbox widget. """ return helpers.checkbox.render(helpers.ACTION_CHECKBOX_NAME, force_text(obj.pk))
def add_view(
self, *args, **kwargs)
The 'add' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def change_view(
self, *args, **kwargs)
The 'change' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def changelist_view(
self, *args, **kwargs)
The 'change list' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def construct_change_message(
self, request, form, formsets)
Construct a change message from a changed object.
def construct_change_message(self, request, form, formsets): """ Construct a change message from a changed object. """ change_message = [] if form.changed_data: change_message.append(_('Changed %s.') % get_text_list(form.changed_data, _('and'))) if formsets: for formset in formsets: for added_object in formset.new_objects: change_message.append(_('Added %(name)s "%(object)s".') % {'name': force_text(added_object._meta.verbose_name), 'object': force_text(added_object)}) for changed_object, changed_fields in formset.changed_objects: change_message.append(_('Changed %(list)s for %(name)s "%(object)s".') % {'list': get_text_list(changed_fields, _('and')), 'name': force_text(changed_object._meta.verbose_name), 'object': force_text(changed_object)}) for deleted_object in formset.deleted_objects: change_message.append(_('Deleted %(name)s "%(object)s".') % {'name': force_text(deleted_object._meta.verbose_name), 'object': force_text(deleted_object)}) change_message = ' '.join(change_message) return change_message or _('No fields changed.')
def delete_model(
self, request, obj)
Given a model instance delete it from the database.
def delete_model(self, request, obj): """ Given a model instance delete it from the database. """ obj.delete()
def delete_view(
self, *args, **kwargs)
The 'delete' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def formfield_for_choice_field(
self, db_field, request=None, **kwargs)
Get a form Field for a database Field that has declared choices.
def formfield_for_choice_field(self, db_field, request=None, **kwargs): """ Get a form Field for a database Field that has declared choices. """ # If the field is named as a radio_field, use a RadioSelect if db_field.name in self.radio_fields: # Avoid stomping on custom widget/choices arguments. if 'widget' not in kwargs: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) if 'choices' not in kwargs: kwargs['choices'] = db_field.get_choices( include_blank=db_field.blank, blank_choice=[('', _('None'))] ) return db_field.formfield(**kwargs)
def formfield_for_dbfield(
self, db_field, **kwargs)
Hook for specifying the form Field instance for a given database Field instance.
If kwargs are given, they're passed to the form Field's constructor.
def formfield_for_dbfield(self, db_field, **kwargs): """ Hook for specifying the form Field instance for a given database Field instance. If kwargs are given, they're passed to the form Field's constructor. """ request = kwargs.pop("request", None) # If the field specifies choices, we don't need to look for special # admin widgets - we just need to use a select widget of some kind. if db_field.choices: return self.formfield_for_choice_field(db_field, request, **kwargs) # ForeignKey or ManyToManyFields if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)): # Combine the field kwargs with any options for formfield_overrides. # Make sure the passed in **kwargs override anything in # formfield_overrides because **kwargs is more specific, and should # always win. if db_field.__class__ in self.formfield_overrides: kwargs = dict(self.formfield_overrides[db_field.__class__], **kwargs) # Get the correct formfield. if isinstance(db_field, models.ForeignKey): formfield = self.formfield_for_foreignkey(db_field, request, **kwargs) elif isinstance(db_field, models.ManyToManyField): formfield = self.formfield_for_manytomany(db_field, request, **kwargs) # For non-raw_id fields, wrap the widget with a wrapper that adds # extra HTML -- the "add other" interface -- to the end of the # rendered output. formfield can be None if it came from a # OneToOneField with parent_link=True or a M2M intermediary. if formfield and db_field.name not in self.raw_id_fields: related_modeladmin = self.admin_site._registry.get( db_field.rel.to) can_add_related = bool(related_modeladmin and related_modeladmin.has_add_permission(request)) formfield.widget = widgets.RelatedFieldWidgetWrapper( formfield.widget, db_field.rel, self.admin_site, can_add_related=can_add_related) return formfield # If we've got overrides for the formfield defined, use 'em. **kwargs # passed to formfield_for_dbfield override the defaults. for klass in db_field.__class__.mro(): if klass in self.formfield_overrides: kwargs = dict(copy.deepcopy(self.formfield_overrides[klass]), **kwargs) return db_field.formfield(**kwargs) # For any other type of field, just call its formfield() method. return db_field.formfield(**kwargs)
def formfield_for_foreignkey(
self, db_field, request=None, **kwargs)
Get a form Field for a ForeignKey.
def formfield_for_foreignkey(self, db_field, request=None, **kwargs): """ Get a form Field for a ForeignKey. """ db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel, self.admin_site, using=db) elif db_field.name in self.radio_fields: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) kwargs['empty_label'] = _('None') if db_field.blank else None if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def formfield_for_manytomany(
self, db_field, request=None, **kwargs)
Get a form Field for a ManyToManyField.
def formfield_for_manytomany(self, db_field, request=None, **kwargs): """ Get a form Field for a ManyToManyField. """ # If it uses an intermediary model that isn't auto created, don't show # a field in admin. if not db_field.rel.through._meta.auto_created: return None db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel, self.admin_site, using=db) kwargs['help_text'] = '' elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)): kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical)) if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def get_action(
self, action)
Return a given action from a parameter, which can either be a callable, or the name of a method on the ModelAdmin. Return is a tuple of (callable, name, description).
def get_action(self, action): """ Return a given action from a parameter, which can either be a callable, or the name of a method on the ModelAdmin. Return is a tuple of (callable, name, description). """ # If the action is a callable, just use it. if callable(action): func = action action = action.__name__ # Next, look for a method. Grab it off self.__class__ to get an unbound # method instead of a bound one; this ensures that the calling # conventions are the same for functions and methods. elif hasattr(self.__class__, action): func = getattr(self.__class__, action) # Finally, look for a named method on the admin site else: try: func = self.admin_site.get_action(action) except KeyError: return None if hasattr(func, 'short_description'): description = func.short_description else: description = capfirst(action.replace('_', ' ')) return func, action, description
def get_action_choices(
self, request, default_choices=[(u'', u'---------')])
Return a list of choices for use in a form object. Each choice is a tuple (name, description).
def get_action_choices(self, request, default_choices=BLANK_CHOICE_DASH): """ Return a list of choices for use in a form object. Each choice is a tuple (name, description). """ choices = [] + default_choices for func, name, description in six.itervalues(self.get_actions(request)): choice = (name, description % model_format_dict(self.opts)) choices.append(choice) return choices
def get_actions(
self, request)
Return a dictionary mapping the names of all actions for this ModelAdmin to a tuple of (callable, name, description) for each action.
def get_actions(self, request): """ Return a dictionary mapping the names of all actions for this ModelAdmin to a tuple of (callable, name, description) for each action. """ # If self.actions is explicitly set to None that means that we don't # want *any* actions enabled on this page. from django.contrib.admin.views.main import _is_changelist_popup if self.actions is None or _is_changelist_popup(request): return SortedDict() actions = [] # Gather actions from the admin site first for (name, func) in self.admin_site.actions: description = getattr(func, 'short_description', name.replace('_', ' ')) actions.append((func, name, description)) # Then gather them from the model admin and all parent classes, # starting with self and working back up. for klass in self.__class__.mro()[::-1]: class_actions = getattr(klass, 'actions', []) # Avoid trying to iterate over None if not class_actions: continue actions.extend([self.get_action(action) for action in class_actions]) # get_action might have returned None, so filter any of those out. actions = filter(None, actions) # Convert the actions into a SortedDict keyed by name. actions = SortedDict([ (name, (func, name, desc)) for func, name, desc in actions ]) return actions
def get_changelist(
self, request, **kwargs)
Returns the ChangeList class for use on the changelist page.
def get_changelist(self, request, **kwargs): """ Returns the ChangeList class for use on the changelist page. """ from django.contrib.admin.views.main import ChangeList return ChangeList
def get_changelist_form(
self, request, **kwargs)
Returns a Form class for use in the Formset on the changelist page.
def get_changelist_form(self, request, **kwargs): """ Returns a Form class for use in the Formset on the changelist page. """ defaults = { "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) if (defaults.get('fields') is None and not modelform_defines_fields(defaults.get('form'))): defaults['fields'] = forms.ALL_FIELDS return modelform_factory(self.model, **defaults)
def get_changelist_formset(
self, request, **kwargs)
Returns a FormSet class for use on the changelist page if list_editable is used.
def get_changelist_formset(self, request, **kwargs): """ Returns a FormSet class for use on the changelist page if list_editable is used. """ defaults = { "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) return modelformset_factory(self.model, self.get_changelist_form(request), extra=0, fields=self.list_editable, **defaults)
def get_field_queryset(
self, db, db_field, request)
If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case).
def get_field_queryset(self, db, db_field, request): """ If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case). """ related_admin = self.admin_site._registry.get(db_field.rel.to, None) if related_admin is not None: ordering = related_admin.get_ordering(request) if ordering is not None and ordering != (): return db_field.rel.to._default_manager.using(db).order_by(*ordering).complex_filter(db_field.rel.limit_choices_to) return None
def get_fieldsets(
self, request, obj=None)
Hook for specifying fieldsets for the add form.
def get_fieldsets(self, request, obj=None): "Hook for specifying fieldsets for the add form." if self.declared_fieldsets: return self.declared_fieldsets form = self.get_form(request, obj, fields=None) fields = list(form.base_fields) + list(self.get_readonly_fields(request, obj)) return [(None, {'fields': fields})]
def get_form(
self, request, obj=None, **kwargs)
Returns a Form class for use in the admin add view. This is used by add_view and change_view.
def get_form(self, request, obj=None, **kwargs): """ Returns a Form class for use in the admin add view. This is used by add_view and change_view. """ if 'fields' in kwargs: fields = kwargs.pop('fields') else: fields = flatten_fieldsets(self.get_fieldsets(request, obj)) if self.exclude is None: exclude = [] else: exclude = list(self.exclude) exclude.extend(self.get_readonly_fields(request, obj)) if self.exclude is None and hasattr(self.form, '_meta') and self.form._meta.exclude: # Take the custom ModelForm's Meta.exclude into account only if the # ModelAdmin doesn't define its own. exclude.extend(self.form._meta.exclude) # if exclude is an empty list we pass None to be consistent with the # default on modelform_factory exclude = exclude or None defaults = { "form": self.form, "fields": fields, "exclude": exclude, "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) if defaults['fields'] is None and not modelform_defines_fields(defaults['form']): defaults['fields'] = forms.ALL_FIELDS try: return modelform_factory(self.model, **defaults) except FieldError as e: raise FieldError('%s. Check fields/fieldsets/exclude attributes of class %s.' % (e, self.__class__.__name__))
def get_formsets(
self, request, obj=None)
def get_formsets(self, request, obj=None): for inline in self.get_inline_instances(request, obj): yield inline.get_formset(request, obj)
def get_inline_instances(
self, request, obj=None)
def get_inline_instances(self, request, obj=None): inline_instances = [] for inline_class in self.inlines: inline = inline_class(self.model, self.admin_site) if request: if not (inline.has_add_permission(request) or inline.has_change_permission(request, obj) or inline.has_delete_permission(request, obj)): continue if not inline.has_add_permission(request): inline.max_num = 0 inline_instances.append(inline) return inline_instances
def get_list_display(
self, request)
Return a sequence containing the fields to be displayed on the changelist.
def get_list_display(self, request): """ Return a sequence containing the fields to be displayed on the changelist. """ return self.list_display
def get_list_display_links(
self, request, list_display)
Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display().
def get_list_display_links(self, request, list_display): """ Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display(). """ if self.list_display_links or not list_display: return self.list_display_links else: # Use only the first item in list_display as link return list(list_display)[:1]
def get_list_filter(
self, request)
Returns a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page.
def get_list_filter(self, request): """ Returns a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page. """ return self.list_filter
def get_model_perms(
self, request)
Returns a dict of all perms for this model. This dict has the keys
add
, change
, and delete
mapping to the True/False for each
of those actions.
def get_model_perms(self, request): """ Returns a dict of all perms for this model. This dict has the keys ``add``, ``change``, and ``delete`` mapping to the True/False for each of those actions. """ return { 'add': self.has_add_permission(request), 'change': self.has_change_permission(request), 'delete': self.has_delete_permission(request), }
def get_object(
self, request, object_id)
Returns an instance matching the primary key provided. None
is
returned if no match is found (or the object_id failed validation
against the primary key field).
def get_object(self, request, object_id): """ Returns an instance matching the primary key provided. ``None`` is returned if no match is found (or the object_id failed validation against the primary key field). """ queryset = self.get_queryset(request) model = queryset.model try: object_id = model._meta.pk.to_python(object_id) return queryset.get(pk=object_id) except (model.DoesNotExist, ValidationError, ValueError): return None
def get_ordering(
self, request)
Hook for specifying field ordering.
def get_ordering(self, request): """ Hook for specifying field ordering. """ return self.ordering or () # otherwise we might try to *None, which is bad ;)
def get_paginator(
self, request, queryset, per_page, orphans=0, allow_empty_first_page=True)
def get_paginator(self, request, queryset, per_page, orphans=0, allow_empty_first_page=True): return self.paginator(queryset, per_page, orphans, allow_empty_first_page)
def get_prepopulated_fields(
self, request, obj=None)
Hook for specifying custom prepopulated fields.
def get_prepopulated_fields(self, request, obj=None): """ Hook for specifying custom prepopulated fields. """ return self.prepopulated_fields
def get_preserved_filters(
self, request)
Returns the preserved filters querystring.
def get_preserved_filters(self, request): """ Returns the preserved filters querystring. """ match = request.resolver_match if self.preserve_filters and match: opts = self.model._meta current_url = '%s:%s' % (match.app_name, match.url_name) changelist_url = 'admin:%s_%s_changelist' % (opts.app_label, opts.model_name) if current_url == changelist_url: preserved_filters = request.GET.urlencode() else: preserved_filters = request.GET.get('_changelist_filters') if preserved_filters: return urlencode({'_changelist_filters': preserved_filters}) return ''
def get_queryset(
self, request)
Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view.
def get_queryset(self, request): """ Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view. """ qs = self.model._default_manager.get_queryset() # TODO: this should be handled by some parameter to the ChangeList. ordering = self.get_ordering(request) if ordering: qs = qs.order_by(*ordering) return qs
def get_readonly_fields(
self, request, obj=None)
Hook for specifying custom readonly fields.
def get_readonly_fields(self, request, obj=None): """ Hook for specifying custom readonly fields. """ return self.readonly_fields
def get_search_results(
self, request, queryset, search_term)
Returns a tuple containing a queryset to implement the search, and a boolean indicating if the results may contain duplicates.
def get_search_results(self, request, queryset, search_term): """ Returns a tuple containing a queryset to implement the search, and a boolean indicating if the results may contain duplicates. """ # Apply keyword searches. def construct_search(field_name): if field_name.startswith('^'): return "%s__istartswith" % field_name[1:] elif field_name.startswith('='): return "%s__iexact" % field_name[1:] elif field_name.startswith('@'): return "%s__search" % field_name[1:] else: return "%s__icontains" % field_name use_distinct = False if self.search_fields and search_term: orm_lookups = [construct_search(str(search_field)) for search_field in self.search_fields] for bit in search_term.split(): or_queries = [models.Q(**{orm_lookup: bit}) for orm_lookup in orm_lookups] queryset = queryset.filter(reduce(operator.or_, or_queries)) if not use_distinct: for search_spec in orm_lookups: if lookup_needs_distinct(self.opts, search_spec): use_distinct = True break return queryset, use_distinct
def get_urls(
self)
def get_urls(self): from django.conf.urls import patterns, url def wrap(view): def wrapper(*args, **kwargs): return self.admin_site.admin_view(view)(*args, **kwargs) return update_wrapper(wrapper, view) info = self.model._meta.app_label, self.model._meta.model_name urlpatterns = patterns('', url(r'^$', wrap(self.changelist_view), name='%s_%s_changelist' % info), url(r'^add/$', wrap(self.add_view), name='%s_%s_add' % info), url(r'^(.+)/history/$', wrap(self.history_view), name='%s_%s_history' % info), url(r'^(.+)/delete/$', wrap(self.delete_view), name='%s_%s_delete' % info), url(r'^(.+)/$', wrap(self.change_view), name='%s_%s_change' % info), ) return urlpatterns
def has_add_permission(
self, request)
Returns True if the given request has permission to add an object. Can be overridden by the user in subclasses.
def has_add_permission(self, request): """ Returns True if the given request has permission to add an object. Can be overridden by the user in subclasses. """ opts = self.opts codename = get_permission_codename('add', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_change_permission(
self, request, obj=None)
Returns True if the given request has permission to change the given
Django model instance, the default implementation doesn't examine the
obj
parameter.
Can be overridden by the user in subclasses. In such case it should
return True if the given request has permission to change the obj
model instance. If obj
is None, this should return True if the given
request has permission to change any object of the given type.
def has_change_permission(self, request, obj=None): """ Returns True if the given request has permission to change the given Django model instance, the default implementation doesn't examine the `obj` parameter. Can be overridden by the user in subclasses. In such case it should return True if the given request has permission to change the `obj` model instance. If `obj` is None, this should return True if the given request has permission to change *any* object of the given type. """ opts = self.opts codename = get_permission_codename('change', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_delete_permission(
self, request, obj=None)
Returns True if the given request has permission to change the given
Django model instance, the default implementation doesn't examine the
obj
parameter.
Can be overridden by the user in subclasses. In such case it should
return True if the given request has permission to delete the obj
model instance. If obj
is None, this should return True if the given
request has permission to delete any object of the given type.
def has_delete_permission(self, request, obj=None): """ Returns True if the given request has permission to change the given Django model instance, the default implementation doesn't examine the `obj` parameter. Can be overridden by the user in subclasses. In such case it should return True if the given request has permission to delete the `obj` model instance. If `obj` is None, this should return True if the given request has permission to delete *any* object of the given type. """ opts = self.opts codename = get_permission_codename('delete', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def history_view(
self, request, object_id, extra_context=None)
The 'history' admin view for this model.
def history_view(self, request, object_id, extra_context=None): "The 'history' admin view for this model." from django.contrib.admin.models import LogEntry # First check if the user can see this history. model = self.model obj = get_object_or_404(model, pk=unquote(object_id)) if not self.has_change_permission(request, obj): raise PermissionDenied # Then get the history for this object. opts = model._meta app_label = opts.app_label action_list = LogEntry.objects.filter( object_id=unquote(object_id), content_type__id__exact=ContentType.objects.get_for_model(model).id ).select_related().order_by('action_time') context = { 'title': _('Change history: %s') % force_text(obj), 'action_list': action_list, 'module_name': capfirst(force_text(opts.verbose_name_plural)), 'object': obj, 'app_label': app_label, 'opts': opts, 'preserved_filters': self.get_preserved_filters(request), } context.update(extra_context or {}) return TemplateResponse(request, self.object_history_template or [ "admin/%s/%s/object_history.html" % (app_label, opts.model_name), "admin/%s/object_history.html" % app_label, "admin/object_history.html" ], context, current_app=self.admin_site.name)
def log_addition(
self, request, object)
Log that an object has been successfully added.
The default implementation creates an admin LogEntry object.
def log_addition(self, request, object): """ Log that an object has been successfully added. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, ADDITION LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=ADDITION )
def log_change(
self, request, object, message)
Log that an object has been successfully changed.
The default implementation creates an admin LogEntry object.
def log_change(self, request, object, message): """ Log that an object has been successfully changed. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, CHANGE LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=CHANGE, change_message=message )
def log_deletion(
self, request, object, object_repr)
Log that an object will be deleted. Note that this method is called before the deletion.
The default implementation creates an admin LogEntry object.
def log_deletion(self, request, object, object_repr): """ Log that an object will be deleted. Note that this method is called before the deletion. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, DELETION LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(self.model).pk, object_id=object.pk, object_repr=object_repr, action_flag=DELETION )
def lookup_allowed(
self, lookup, value)
def lookup_allowed(self, lookup, value): model = self.model # Check FKey lookups that are allowed, so that popups produced by # ForeignKeyRawIdWidget, on the basis of ForeignKey.limit_choices_to, # are allowed to work. for l in model._meta.related_fkey_lookups: for k, v in widgets.url_params_from_lookup_dict(l).items(): if k == lookup and v == value: return True parts = lookup.split(LOOKUP_SEP) # Last term in lookup is a query term (__exact, __startswith etc) # This term can be ignored. if len(parts) > 1 and parts[-1] in QUERY_TERMS: parts.pop() # Special case -- foo__id__exact and foo__id queries are implied # if foo has been specifically included in the lookup list; so # drop __id if it is the last part. However, first we need to find # the pk attribute name. rel_name = None for part in parts[:-1]: try: field, _, _, _ = model._meta.get_field_by_name(part) except FieldDoesNotExist: # Lookups on non-existent fields are ok, since they're ignored # later. return True if hasattr(field, 'rel'): if field.rel is None: # This property or relation doesn't exist, but it's allowed # since it's ignored in ChangeList.get_filters(). return True model = field.rel.to rel_name = field.rel.get_related_field().name elif isinstance(field, RelatedObject): model = field.model rel_name = model._meta.pk.name else: rel_name = None if rel_name and len(parts) > 1 and parts[-1] == rel_name: parts.pop() if len(parts) == 1: return True clean_lookup = LOOKUP_SEP.join(parts) return clean_lookup in self.list_filter or clean_lookup == self.date_hierarchy
def message_user(
self, request, message, level=20, extra_tags='', fail_silently=False)
Send a message to the user. The default implementation posts a message using the django.contrib.messages backend.
Exposes almost the same API as messages.add_message(), but accepts the
positional arguments in a different order to maintain backwards
compatibility. For convenience, it accepts the level
argument as
a string rather than the usual level number.
def message_user(self, request, message, level=messages.INFO, extra_tags='', fail_silently=False): """ Send a message to the user. The default implementation posts a message using the django.contrib.messages backend. Exposes almost the same API as messages.add_message(), but accepts the positional arguments in a different order to maintain backwards compatibility. For convenience, it accepts the `level` argument as a string rather than the usual level number. """ if not isinstance(level, int): # attempt to get the level if passed a string try: level = getattr(messages.constants, level.upper()) except AttributeError: levels = messages.constants.DEFAULT_TAGS.values() levels_repr = ', '.join('`%s`' % l for l in levels) raise ValueError('Bad message level string: `%s`. ' 'Possible values are: %s' % (level, levels_repr)) messages.add_message(request, level, message, extra_tags=extra_tags, fail_silently=fail_silently)
def queryset(
*args, **kwargs)
def wrapped(*args, **kwargs): warnings.warn( "`%s.%s` is deprecated, use `%s` instead." % (self.class_name, self.old_method_name, self.new_method_name), self.deprecation_warning, 2) return f(*args, **kwargs)
def render_change_form(
self, request, context, add=False, change=False, form_url='', obj=None)
def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None): opts = self.model._meta app_label = opts.app_label preserved_filters = self.get_preserved_filters(request) form_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, form_url) context.update({ 'add': add, 'change': change, 'has_add_permission': self.has_add_permission(request), 'has_change_permission': self.has_change_permission(request, obj), 'has_delete_permission': self.has_delete_permission(request, obj), 'has_file_field': True, # FIXME - this should check if form or formsets have a FileField, 'has_absolute_url': hasattr(self.model, 'get_absolute_url'), 'form_url': form_url, 'opts': opts, 'content_type_id': ContentType.objects.get_for_model(self.model).id, 'save_as': self.save_as, 'save_on_top': self.save_on_top, }) if add and self.add_form_template is not None: form_template = self.add_form_template else: form_template = self.change_form_template return TemplateResponse(request, form_template or [ "admin/%s/%s/change_form.html" % (app_label, opts.model_name), "admin/%s/change_form.html" % app_label, "admin/change_form.html" ], context, current_app=self.admin_site.name)
def response_action(
self, request, queryset)
Handle an admin action. This is called if a request is POSTed to the changelist; it returns an HttpResponse if the action was handled, and None otherwise.
def response_action(self, request, queryset): """ Handle an admin action. This is called if a request is POSTed to the changelist; it returns an HttpResponse if the action was handled, and None otherwise. """ # There can be multiple action forms on the page (at the top # and bottom of the change list, for example). Get the action # whose button was pushed. try: action_index = int(request.POST.get('index', 0)) except ValueError: action_index = 0 # Construct the action form. data = request.POST.copy() data.pop(helpers.ACTION_CHECKBOX_NAME, None) data.pop("index", None) # Use the action whose button was pushed try: data.update({'action': data.getlist('action')[action_index]}) except IndexError: # If we didn't get an action from the chosen form that's invalid # POST data, so by deleting action it'll fail the validation check # below. So no need to do anything here pass action_form = self.action_form(data, auto_id=None) action_form.fields['action'].choices = self.get_action_choices(request) # If the form's valid we can handle the action. if action_form.is_valid(): action = action_form.cleaned_data['action'] select_across = action_form.cleaned_data['select_across'] func = self.get_actions(request)[action][0] # Get the list of selected PKs. If nothing's selected, we can't # perform an action on it, so bail. Except we want to perform # the action explicitly on all objects. selected = request.POST.getlist(helpers.ACTION_CHECKBOX_NAME) if not selected and not select_across: # Reminder that something needs to be selected or nothing will happen msg = _("Items must be selected in order to perform " "actions on them. No items have been changed.") self.message_user(request, msg, messages.WARNING) return None if not select_across: # Perform the action only on the selected objects queryset = queryset.filter(pk__in=selected) response = func(self, request, queryset) # Actions may return an HttpResponse-like object, which will be # used as the response from the POST. If not, we'll be a good # little HTTP citizen and redirect back to the changelist page. if isinstance(response, HttpResponseBase): return response else: return HttpResponseRedirect(request.get_full_path()) else: msg = _("No action selected.") self.message_user(request, msg, messages.WARNING) return None
def response_add(
self, request, obj, post_url_continue=None)
Determines the HttpResponse for the add_view stage.
def response_add(self, request, obj, post_url_continue=None): """ Determines the HttpResponse for the add_view stage. """ opts = obj._meta pk_value = obj._get_pk_val() preserved_filters = self.get_preserved_filters(request) msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)} # Here, we distinguish between different save types by checking for # the presence of keys in request.POST. if IS_POPUP_VAR in request.POST: return SimpleTemplateResponse('admin/popup_response.html', { 'pk_value': escape(pk_value), 'obj': escapejs(obj) }) elif "_continue" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) if post_url_continue is None: post_url_continue = reverse('admin:%s_%s_change' % (opts.app_label, opts.model_name), args=(pk_value,), current_app=self.admin_site.name) post_url_continue = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url_continue) return HttpResponseRedirect(post_url_continue) elif "_addanother" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may add another %(name)s below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = request.path redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) else: msg = _('The %(name)s "%(obj)s" was added successfully.') % msg_dict self.message_user(request, msg, messages.SUCCESS) return self.response_post_save_add(request, obj)
def response_change(
self, request, obj)
Determines the HttpResponse for the change_view stage.
def response_change(self, request, obj): """ Determines the HttpResponse for the change_view stage. """ opts = self.model._meta pk_value = obj._get_pk_val() preserved_filters = self.get_preserved_filters(request) msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)} if "_continue" in request.POST: msg = _('The %(name)s "%(obj)s" was changed successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = request.path redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) elif "_saveasnew" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = reverse('admin:%s_%s_change' % (opts.app_label, opts.model_name), args=(pk_value,), current_app=self.admin_site.name) redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) elif "_addanother" in request.POST: msg = _('The %(name)s "%(obj)s" was changed successfully. You may add another %(name)s below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = reverse('admin:%s_%s_add' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) else: msg = _('The %(name)s "%(obj)s" was changed successfully.') % msg_dict self.message_user(request, msg, messages.SUCCESS) return self.response_post_save_change(request, obj)
def response_post_save_add(
self, request, obj)
Figure out where to redirect after the 'Save' button has been pressed when adding a new object.
def response_post_save_add(self, request, obj): """ Figure out where to redirect after the 'Save' button has been pressed when adding a new object. """ opts = self.model._meta if self.has_change_permission(request, None): post_url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url) else: post_url = reverse('admin:index', current_app=self.admin_site.name) return HttpResponseRedirect(post_url)
def response_post_save_change(
self, request, obj)
Figure out where to redirect after the 'Save' button has been pressed when editing an existing object.
def response_post_save_change(self, request, obj): """ Figure out where to redirect after the 'Save' button has been pressed when editing an existing object. """ opts = self.model._meta if self.has_change_permission(request, None): post_url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url) else: post_url = reverse('admin:index', current_app=self.admin_site.name) return HttpResponseRedirect(post_url)
def save_form(
self, request, form, change)
Given a ModelForm return an unsaved instance. change
is True if
the object is being changed, and False if it's being added.
def save_form(self, request, form, change): """ Given a ModelForm return an unsaved instance. ``change`` is True if the object is being changed, and False if it's being added. """ return form.save(commit=False)
def save_formset(
self, request, form, formset, change)
Given an inline formset save it to the database.
def save_formset(self, request, form, formset, change): """ Given an inline formset save it to the database. """ formset.save()
def save_model(
self, request, obj, form, change)
Given a model instance save it to the database.
def save_model(self, request, obj, form, change): """ Given a model instance save it to the database. """ obj.save()
Given the HttpRequest
, the parent ModelForm
instance, the
list of inline formsets and a boolean value based on whether the
parent is being added or changed, save the related objects to the
database. Note that at this point save_form() and save_model() have
already been called.
def to_field_allowed(
self, request, to_field)
Returns True if the model associated with this admin should be allowed to be referenced by the specified field.
def to_field_allowed(self, request, to_field): """ Returns True if the model associated with this admin should be allowed to be referenced by the specified field. """ opts = self.model._meta try: field = opts.get_field(to_field) except FieldDoesNotExist: return False # Always allow referencing the primary key since it's already possible # to get this information from the change view URL. if field.primary_key: return True # Make sure at least one of the models registered for this site # references this field through a FK or a M2M relationship. registered_models = set() for model, admin in self.admin_site._registry.items(): registered_models.add(model) for inline in admin.inlines: registered_models.add(inline.model) for related_object in opts.get_all_related_objects(include_hidden=True): related_model = related_object.model if (any(issubclass(model, related_model) for model in registered_models) and related_object.field.rel.get_related_field() == field): return True return False
def validate(
cls, model)
@classmethod def validate(cls, model): validator = cls.validator_class() validator.validate(cls, model)
class InstrumentRelationAdmin
class InstrumentRelationAdmin(admin.ModelAdmin): search_fields = ['instrument__name', 'parent_instrument__name'] ordering = ['parent_instrument__name']
Ancestors (in MRO)
- InstrumentRelationAdmin
- django.contrib.admin.options.ModelAdmin
- django.contrib.admin.options.BaseModelAdmin
- __builtin__.object
Class variables
var action_form
var actions
var actions_on_bottom
var actions_on_top
var actions_selection_counter
var add_form_template
var change_form_template
var change_list_template
var date_hierarchy
var delete_confirmation_template
var delete_selected_confirmation_template
var exclude
var fields
var fieldsets
var filter_horizontal
var filter_vertical
var form
var formfield_overrides
var inlines
var list_display
var list_display_links
var list_editable
var list_filter
var list_max_show_all
var list_per_page
var object_history_template
var ordering
var paginator
var prepopulated_fields
var preserve_filters
var radio_fields
var raw_id_fields
var readonly_fields
var save_as
var save_on_top
var search_fields
var validator_class
Instance variables
var declared_fieldsets
var media
var urls
Methods
def __init__(
self, model, admin_site)
def __init__(self, model, admin_site): self.model = model self.opts = model._meta self.admin_site = admin_site super(ModelAdmin, self).__init__()
def action_checkbox(
self, obj)
A list_display column containing a checkbox widget.
def action_checkbox(self, obj): """ A list_display column containing a checkbox widget. """ return helpers.checkbox.render(helpers.ACTION_CHECKBOX_NAME, force_text(obj.pk))
def add_view(
self, *args, **kwargs)
The 'add' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def change_view(
self, *args, **kwargs)
The 'change' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def changelist_view(
self, *args, **kwargs)
The 'change list' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def construct_change_message(
self, request, form, formsets)
Construct a change message from a changed object.
def construct_change_message(self, request, form, formsets): """ Construct a change message from a changed object. """ change_message = [] if form.changed_data: change_message.append(_('Changed %s.') % get_text_list(form.changed_data, _('and'))) if formsets: for formset in formsets: for added_object in formset.new_objects: change_message.append(_('Added %(name)s "%(object)s".') % {'name': force_text(added_object._meta.verbose_name), 'object': force_text(added_object)}) for changed_object, changed_fields in formset.changed_objects: change_message.append(_('Changed %(list)s for %(name)s "%(object)s".') % {'list': get_text_list(changed_fields, _('and')), 'name': force_text(changed_object._meta.verbose_name), 'object': force_text(changed_object)}) for deleted_object in formset.deleted_objects: change_message.append(_('Deleted %(name)s "%(object)s".') % {'name': force_text(deleted_object._meta.verbose_name), 'object': force_text(deleted_object)}) change_message = ' '.join(change_message) return change_message or _('No fields changed.')
def delete_model(
self, request, obj)
Given a model instance delete it from the database.
def delete_model(self, request, obj): """ Given a model instance delete it from the database. """ obj.delete()
def delete_view(
self, *args, **kwargs)
The 'delete' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def formfield_for_choice_field(
self, db_field, request=None, **kwargs)
Get a form Field for a database Field that has declared choices.
def formfield_for_choice_field(self, db_field, request=None, **kwargs): """ Get a form Field for a database Field that has declared choices. """ # If the field is named as a radio_field, use a RadioSelect if db_field.name in self.radio_fields: # Avoid stomping on custom widget/choices arguments. if 'widget' not in kwargs: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) if 'choices' not in kwargs: kwargs['choices'] = db_field.get_choices( include_blank=db_field.blank, blank_choice=[('', _('None'))] ) return db_field.formfield(**kwargs)
def formfield_for_dbfield(
self, db_field, **kwargs)
Hook for specifying the form Field instance for a given database Field instance.
If kwargs are given, they're passed to the form Field's constructor.
def formfield_for_dbfield(self, db_field, **kwargs): """ Hook for specifying the form Field instance for a given database Field instance. If kwargs are given, they're passed to the form Field's constructor. """ request = kwargs.pop("request", None) # If the field specifies choices, we don't need to look for special # admin widgets - we just need to use a select widget of some kind. if db_field.choices: return self.formfield_for_choice_field(db_field, request, **kwargs) # ForeignKey or ManyToManyFields if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)): # Combine the field kwargs with any options for formfield_overrides. # Make sure the passed in **kwargs override anything in # formfield_overrides because **kwargs is more specific, and should # always win. if db_field.__class__ in self.formfield_overrides: kwargs = dict(self.formfield_overrides[db_field.__class__], **kwargs) # Get the correct formfield. if isinstance(db_field, models.ForeignKey): formfield = self.formfield_for_foreignkey(db_field, request, **kwargs) elif isinstance(db_field, models.ManyToManyField): formfield = self.formfield_for_manytomany(db_field, request, **kwargs) # For non-raw_id fields, wrap the widget with a wrapper that adds # extra HTML -- the "add other" interface -- to the end of the # rendered output. formfield can be None if it came from a # OneToOneField with parent_link=True or a M2M intermediary. if formfield and db_field.name not in self.raw_id_fields: related_modeladmin = self.admin_site._registry.get( db_field.rel.to) can_add_related = bool(related_modeladmin and related_modeladmin.has_add_permission(request)) formfield.widget = widgets.RelatedFieldWidgetWrapper( formfield.widget, db_field.rel, self.admin_site, can_add_related=can_add_related) return formfield # If we've got overrides for the formfield defined, use 'em. **kwargs # passed to formfield_for_dbfield override the defaults. for klass in db_field.__class__.mro(): if klass in self.formfield_overrides: kwargs = dict(copy.deepcopy(self.formfield_overrides[klass]), **kwargs) return db_field.formfield(**kwargs) # For any other type of field, just call its formfield() method. return db_field.formfield(**kwargs)
def formfield_for_foreignkey(
self, db_field, request=None, **kwargs)
Get a form Field for a ForeignKey.
def formfield_for_foreignkey(self, db_field, request=None, **kwargs): """ Get a form Field for a ForeignKey. """ db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel, self.admin_site, using=db) elif db_field.name in self.radio_fields: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) kwargs['empty_label'] = _('None') if db_field.blank else None if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def formfield_for_manytomany(
self, db_field, request=None, **kwargs)
Get a form Field for a ManyToManyField.
def formfield_for_manytomany(self, db_field, request=None, **kwargs): """ Get a form Field for a ManyToManyField. """ # If it uses an intermediary model that isn't auto created, don't show # a field in admin. if not db_field.rel.through._meta.auto_created: return None db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel, self.admin_site, using=db) kwargs['help_text'] = '' elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)): kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical)) if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def get_action(
self, action)
Return a given action from a parameter, which can either be a callable, or the name of a method on the ModelAdmin. Return is a tuple of (callable, name, description).
def get_action(self, action): """ Return a given action from a parameter, which can either be a callable, or the name of a method on the ModelAdmin. Return is a tuple of (callable, name, description). """ # If the action is a callable, just use it. if callable(action): func = action action = action.__name__ # Next, look for a method. Grab it off self.__class__ to get an unbound # method instead of a bound one; this ensures that the calling # conventions are the same for functions and methods. elif hasattr(self.__class__, action): func = getattr(self.__class__, action) # Finally, look for a named method on the admin site else: try: func = self.admin_site.get_action(action) except KeyError: return None if hasattr(func, 'short_description'): description = func.short_description else: description = capfirst(action.replace('_', ' ')) return func, action, description
def get_action_choices(
self, request, default_choices=[(u'', u'---------')])
Return a list of choices for use in a form object. Each choice is a tuple (name, description).
def get_action_choices(self, request, default_choices=BLANK_CHOICE_DASH): """ Return a list of choices for use in a form object. Each choice is a tuple (name, description). """ choices = [] + default_choices for func, name, description in six.itervalues(self.get_actions(request)): choice = (name, description % model_format_dict(self.opts)) choices.append(choice) return choices
def get_actions(
self, request)
Return a dictionary mapping the names of all actions for this ModelAdmin to a tuple of (callable, name, description) for each action.
def get_actions(self, request): """ Return a dictionary mapping the names of all actions for this ModelAdmin to a tuple of (callable, name, description) for each action. """ # If self.actions is explicitly set to None that means that we don't # want *any* actions enabled on this page. from django.contrib.admin.views.main import _is_changelist_popup if self.actions is None or _is_changelist_popup(request): return SortedDict() actions = [] # Gather actions from the admin site first for (name, func) in self.admin_site.actions: description = getattr(func, 'short_description', name.replace('_', ' ')) actions.append((func, name, description)) # Then gather them from the model admin and all parent classes, # starting with self and working back up. for klass in self.__class__.mro()[::-1]: class_actions = getattr(klass, 'actions', []) # Avoid trying to iterate over None if not class_actions: continue actions.extend([self.get_action(action) for action in class_actions]) # get_action might have returned None, so filter any of those out. actions = filter(None, actions) # Convert the actions into a SortedDict keyed by name. actions = SortedDict([ (name, (func, name, desc)) for func, name, desc in actions ]) return actions
def get_changelist(
self, request, **kwargs)
Returns the ChangeList class for use on the changelist page.
def get_changelist(self, request, **kwargs): """ Returns the ChangeList class for use on the changelist page. """ from django.contrib.admin.views.main import ChangeList return ChangeList
def get_changelist_form(
self, request, **kwargs)
Returns a Form class for use in the Formset on the changelist page.
def get_changelist_form(self, request, **kwargs): """ Returns a Form class for use in the Formset on the changelist page. """ defaults = { "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) if (defaults.get('fields') is None and not modelform_defines_fields(defaults.get('form'))): defaults['fields'] = forms.ALL_FIELDS return modelform_factory(self.model, **defaults)
def get_changelist_formset(
self, request, **kwargs)
Returns a FormSet class for use on the changelist page if list_editable is used.
def get_changelist_formset(self, request, **kwargs): """ Returns a FormSet class for use on the changelist page if list_editable is used. """ defaults = { "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) return modelformset_factory(self.model, self.get_changelist_form(request), extra=0, fields=self.list_editable, **defaults)
def get_field_queryset(
self, db, db_field, request)
If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case).
def get_field_queryset(self, db, db_field, request): """ If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case). """ related_admin = self.admin_site._registry.get(db_field.rel.to, None) if related_admin is not None: ordering = related_admin.get_ordering(request) if ordering is not None and ordering != (): return db_field.rel.to._default_manager.using(db).order_by(*ordering).complex_filter(db_field.rel.limit_choices_to) return None
def get_fieldsets(
self, request, obj=None)
Hook for specifying fieldsets for the add form.
def get_fieldsets(self, request, obj=None): "Hook for specifying fieldsets for the add form." if self.declared_fieldsets: return self.declared_fieldsets form = self.get_form(request, obj, fields=None) fields = list(form.base_fields) + list(self.get_readonly_fields(request, obj)) return [(None, {'fields': fields})]
def get_form(
self, request, obj=None, **kwargs)
Returns a Form class for use in the admin add view. This is used by add_view and change_view.
def get_form(self, request, obj=None, **kwargs): """ Returns a Form class for use in the admin add view. This is used by add_view and change_view. """ if 'fields' in kwargs: fields = kwargs.pop('fields') else: fields = flatten_fieldsets(self.get_fieldsets(request, obj)) if self.exclude is None: exclude = [] else: exclude = list(self.exclude) exclude.extend(self.get_readonly_fields(request, obj)) if self.exclude is None and hasattr(self.form, '_meta') and self.form._meta.exclude: # Take the custom ModelForm's Meta.exclude into account only if the # ModelAdmin doesn't define its own. exclude.extend(self.form._meta.exclude) # if exclude is an empty list we pass None to be consistent with the # default on modelform_factory exclude = exclude or None defaults = { "form": self.form, "fields": fields, "exclude": exclude, "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) if defaults['fields'] is None and not modelform_defines_fields(defaults['form']): defaults['fields'] = forms.ALL_FIELDS try: return modelform_factory(self.model, **defaults) except FieldError as e: raise FieldError('%s. Check fields/fieldsets/exclude attributes of class %s.' % (e, self.__class__.__name__))
def get_formsets(
self, request, obj=None)
def get_formsets(self, request, obj=None): for inline in self.get_inline_instances(request, obj): yield inline.get_formset(request, obj)
def get_inline_instances(
self, request, obj=None)
def get_inline_instances(self, request, obj=None): inline_instances = [] for inline_class in self.inlines: inline = inline_class(self.model, self.admin_site) if request: if not (inline.has_add_permission(request) or inline.has_change_permission(request, obj) or inline.has_delete_permission(request, obj)): continue if not inline.has_add_permission(request): inline.max_num = 0 inline_instances.append(inline) return inline_instances
def get_list_display(
self, request)
Return a sequence containing the fields to be displayed on the changelist.
def get_list_display(self, request): """ Return a sequence containing the fields to be displayed on the changelist. """ return self.list_display
def get_list_display_links(
self, request, list_display)
Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display().
def get_list_display_links(self, request, list_display): """ Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display(). """ if self.list_display_links or not list_display: return self.list_display_links else: # Use only the first item in list_display as link return list(list_display)[:1]
def get_list_filter(
self, request)
Returns a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page.
def get_list_filter(self, request): """ Returns a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page. """ return self.list_filter
def get_model_perms(
self, request)
Returns a dict of all perms for this model. This dict has the keys
add
, change
, and delete
mapping to the True/False for each
of those actions.
def get_model_perms(self, request): """ Returns a dict of all perms for this model. This dict has the keys ``add``, ``change``, and ``delete`` mapping to the True/False for each of those actions. """ return { 'add': self.has_add_permission(request), 'change': self.has_change_permission(request), 'delete': self.has_delete_permission(request), }
def get_object(
self, request, object_id)
Returns an instance matching the primary key provided. None
is
returned if no match is found (or the object_id failed validation
against the primary key field).
def get_object(self, request, object_id): """ Returns an instance matching the primary key provided. ``None`` is returned if no match is found (or the object_id failed validation against the primary key field). """ queryset = self.get_queryset(request) model = queryset.model try: object_id = model._meta.pk.to_python(object_id) return queryset.get(pk=object_id) except (model.DoesNotExist, ValidationError, ValueError): return None
def get_ordering(
self, request)
Hook for specifying field ordering.
def get_ordering(self, request): """ Hook for specifying field ordering. """ return self.ordering or () # otherwise we might try to *None, which is bad ;)
def get_paginator(
self, request, queryset, per_page, orphans=0, allow_empty_first_page=True)
def get_paginator(self, request, queryset, per_page, orphans=0, allow_empty_first_page=True): return self.paginator(queryset, per_page, orphans, allow_empty_first_page)
def get_prepopulated_fields(
self, request, obj=None)
Hook for specifying custom prepopulated fields.
def get_prepopulated_fields(self, request, obj=None): """ Hook for specifying custom prepopulated fields. """ return self.prepopulated_fields
def get_preserved_filters(
self, request)
Returns the preserved filters querystring.
def get_preserved_filters(self, request): """ Returns the preserved filters querystring. """ match = request.resolver_match if self.preserve_filters and match: opts = self.model._meta current_url = '%s:%s' % (match.app_name, match.url_name) changelist_url = 'admin:%s_%s_changelist' % (opts.app_label, opts.model_name) if current_url == changelist_url: preserved_filters = request.GET.urlencode() else: preserved_filters = request.GET.get('_changelist_filters') if preserved_filters: return urlencode({'_changelist_filters': preserved_filters}) return ''
def get_queryset(
self, request)
Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view.
def get_queryset(self, request): """ Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view. """ qs = self.model._default_manager.get_queryset() # TODO: this should be handled by some parameter to the ChangeList. ordering = self.get_ordering(request) if ordering: qs = qs.order_by(*ordering) return qs
def get_readonly_fields(
self, request, obj=None)
Hook for specifying custom readonly fields.
def get_readonly_fields(self, request, obj=None): """ Hook for specifying custom readonly fields. """ return self.readonly_fields
def get_search_results(
self, request, queryset, search_term)
Returns a tuple containing a queryset to implement the search, and a boolean indicating if the results may contain duplicates.
def get_search_results(self, request, queryset, search_term): """ Returns a tuple containing a queryset to implement the search, and a boolean indicating if the results may contain duplicates. """ # Apply keyword searches. def construct_search(field_name): if field_name.startswith('^'): return "%s__istartswith" % field_name[1:] elif field_name.startswith('='): return "%s__iexact" % field_name[1:] elif field_name.startswith('@'): return "%s__search" % field_name[1:] else: return "%s__icontains" % field_name use_distinct = False if self.search_fields and search_term: orm_lookups = [construct_search(str(search_field)) for search_field in self.search_fields] for bit in search_term.split(): or_queries = [models.Q(**{orm_lookup: bit}) for orm_lookup in orm_lookups] queryset = queryset.filter(reduce(operator.or_, or_queries)) if not use_distinct: for search_spec in orm_lookups: if lookup_needs_distinct(self.opts, search_spec): use_distinct = True break return queryset, use_distinct
def get_urls(
self)
def get_urls(self): from django.conf.urls import patterns, url def wrap(view): def wrapper(*args, **kwargs): return self.admin_site.admin_view(view)(*args, **kwargs) return update_wrapper(wrapper, view) info = self.model._meta.app_label, self.model._meta.model_name urlpatterns = patterns('', url(r'^$', wrap(self.changelist_view), name='%s_%s_changelist' % info), url(r'^add/$', wrap(self.add_view), name='%s_%s_add' % info), url(r'^(.+)/history/$', wrap(self.history_view), name='%s_%s_history' % info), url(r'^(.+)/delete/$', wrap(self.delete_view), name='%s_%s_delete' % info), url(r'^(.+)/$', wrap(self.change_view), name='%s_%s_change' % info), ) return urlpatterns
def has_add_permission(
self, request)
Returns True if the given request has permission to add an object. Can be overridden by the user in subclasses.
def has_add_permission(self, request): """ Returns True if the given request has permission to add an object. Can be overridden by the user in subclasses. """ opts = self.opts codename = get_permission_codename('add', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_change_permission(
self, request, obj=None)
Returns True if the given request has permission to change the given
Django model instance, the default implementation doesn't examine the
obj
parameter.
Can be overridden by the user in subclasses. In such case it should
return True if the given request has permission to change the obj
model instance. If obj
is None, this should return True if the given
request has permission to change any object of the given type.
def has_change_permission(self, request, obj=None): """ Returns True if the given request has permission to change the given Django model instance, the default implementation doesn't examine the `obj` parameter. Can be overridden by the user in subclasses. In such case it should return True if the given request has permission to change the `obj` model instance. If `obj` is None, this should return True if the given request has permission to change *any* object of the given type. """ opts = self.opts codename = get_permission_codename('change', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_delete_permission(
self, request, obj=None)
Returns True if the given request has permission to change the given
Django model instance, the default implementation doesn't examine the
obj
parameter.
Can be overridden by the user in subclasses. In such case it should
return True if the given request has permission to delete the obj
model instance. If obj
is None, this should return True if the given
request has permission to delete any object of the given type.
def has_delete_permission(self, request, obj=None): """ Returns True if the given request has permission to change the given Django model instance, the default implementation doesn't examine the `obj` parameter. Can be overridden by the user in subclasses. In such case it should return True if the given request has permission to delete the `obj` model instance. If `obj` is None, this should return True if the given request has permission to delete *any* object of the given type. """ opts = self.opts codename = get_permission_codename('delete', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def history_view(
self, request, object_id, extra_context=None)
The 'history' admin view for this model.
def history_view(self, request, object_id, extra_context=None): "The 'history' admin view for this model." from django.contrib.admin.models import LogEntry # First check if the user can see this history. model = self.model obj = get_object_or_404(model, pk=unquote(object_id)) if not self.has_change_permission(request, obj): raise PermissionDenied # Then get the history for this object. opts = model._meta app_label = opts.app_label action_list = LogEntry.objects.filter( object_id=unquote(object_id), content_type__id__exact=ContentType.objects.get_for_model(model).id ).select_related().order_by('action_time') context = { 'title': _('Change history: %s') % force_text(obj), 'action_list': action_list, 'module_name': capfirst(force_text(opts.verbose_name_plural)), 'object': obj, 'app_label': app_label, 'opts': opts, 'preserved_filters': self.get_preserved_filters(request), } context.update(extra_context or {}) return TemplateResponse(request, self.object_history_template or [ "admin/%s/%s/object_history.html" % (app_label, opts.model_name), "admin/%s/object_history.html" % app_label, "admin/object_history.html" ], context, current_app=self.admin_site.name)
def log_addition(
self, request, object)
Log that an object has been successfully added.
The default implementation creates an admin LogEntry object.
def log_addition(self, request, object): """ Log that an object has been successfully added. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, ADDITION LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=ADDITION )
def log_change(
self, request, object, message)
Log that an object has been successfully changed.
The default implementation creates an admin LogEntry object.
def log_change(self, request, object, message): """ Log that an object has been successfully changed. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, CHANGE LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=CHANGE, change_message=message )
def log_deletion(
self, request, object, object_repr)
Log that an object will be deleted. Note that this method is called before the deletion.
The default implementation creates an admin LogEntry object.
def log_deletion(self, request, object, object_repr): """ Log that an object will be deleted. Note that this method is called before the deletion. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, DELETION LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(self.model).pk, object_id=object.pk, object_repr=object_repr, action_flag=DELETION )
def lookup_allowed(
self, lookup, value)
def lookup_allowed(self, lookup, value): model = self.model # Check FKey lookups that are allowed, so that popups produced by # ForeignKeyRawIdWidget, on the basis of ForeignKey.limit_choices_to, # are allowed to work. for l in model._meta.related_fkey_lookups: for k, v in widgets.url_params_from_lookup_dict(l).items(): if k == lookup and v == value: return True parts = lookup.split(LOOKUP_SEP) # Last term in lookup is a query term (__exact, __startswith etc) # This term can be ignored. if len(parts) > 1 and parts[-1] in QUERY_TERMS: parts.pop() # Special case -- foo__id__exact and foo__id queries are implied # if foo has been specifically included in the lookup list; so # drop __id if it is the last part. However, first we need to find # the pk attribute name. rel_name = None for part in parts[:-1]: try: field, _, _, _ = model._meta.get_field_by_name(part) except FieldDoesNotExist: # Lookups on non-existent fields are ok, since they're ignored # later. return True if hasattr(field, 'rel'): if field.rel is None: # This property or relation doesn't exist, but it's allowed # since it's ignored in ChangeList.get_filters(). return True model = field.rel.to rel_name = field.rel.get_related_field().name elif isinstance(field, RelatedObject): model = field.model rel_name = model._meta.pk.name else: rel_name = None if rel_name and len(parts) > 1 and parts[-1] == rel_name: parts.pop() if len(parts) == 1: return True clean_lookup = LOOKUP_SEP.join(parts) return clean_lookup in self.list_filter or clean_lookup == self.date_hierarchy
def message_user(
self, request, message, level=20, extra_tags='', fail_silently=False)
Send a message to the user. The default implementation posts a message using the django.contrib.messages backend.
Exposes almost the same API as messages.add_message(), but accepts the
positional arguments in a different order to maintain backwards
compatibility. For convenience, it accepts the level
argument as
a string rather than the usual level number.
def message_user(self, request, message, level=messages.INFO, extra_tags='', fail_silently=False): """ Send a message to the user. The default implementation posts a message using the django.contrib.messages backend. Exposes almost the same API as messages.add_message(), but accepts the positional arguments in a different order to maintain backwards compatibility. For convenience, it accepts the `level` argument as a string rather than the usual level number. """ if not isinstance(level, int): # attempt to get the level if passed a string try: level = getattr(messages.constants, level.upper()) except AttributeError: levels = messages.constants.DEFAULT_TAGS.values() levels_repr = ', '.join('`%s`' % l for l in levels) raise ValueError('Bad message level string: `%s`. ' 'Possible values are: %s' % (level, levels_repr)) messages.add_message(request, level, message, extra_tags=extra_tags, fail_silently=fail_silently)
def queryset(
*args, **kwargs)
def wrapped(*args, **kwargs): warnings.warn( "`%s.%s` is deprecated, use `%s` instead." % (self.class_name, self.old_method_name, self.new_method_name), self.deprecation_warning, 2) return f(*args, **kwargs)
def render_change_form(
self, request, context, add=False, change=False, form_url='', obj=None)
def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None): opts = self.model._meta app_label = opts.app_label preserved_filters = self.get_preserved_filters(request) form_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, form_url) context.update({ 'add': add, 'change': change, 'has_add_permission': self.has_add_permission(request), 'has_change_permission': self.has_change_permission(request, obj), 'has_delete_permission': self.has_delete_permission(request, obj), 'has_file_field': True, # FIXME - this should check if form or formsets have a FileField, 'has_absolute_url': hasattr(self.model, 'get_absolute_url'), 'form_url': form_url, 'opts': opts, 'content_type_id': ContentType.objects.get_for_model(self.model).id, 'save_as': self.save_as, 'save_on_top': self.save_on_top, }) if add and self.add_form_template is not None: form_template = self.add_form_template else: form_template = self.change_form_template return TemplateResponse(request, form_template or [ "admin/%s/%s/change_form.html" % (app_label, opts.model_name), "admin/%s/change_form.html" % app_label, "admin/change_form.html" ], context, current_app=self.admin_site.name)
def response_action(
self, request, queryset)
Handle an admin action. This is called if a request is POSTed to the changelist; it returns an HttpResponse if the action was handled, and None otherwise.
def response_action(self, request, queryset): """ Handle an admin action. This is called if a request is POSTed to the changelist; it returns an HttpResponse if the action was handled, and None otherwise. """ # There can be multiple action forms on the page (at the top # and bottom of the change list, for example). Get the action # whose button was pushed. try: action_index = int(request.POST.get('index', 0)) except ValueError: action_index = 0 # Construct the action form. data = request.POST.copy() data.pop(helpers.ACTION_CHECKBOX_NAME, None) data.pop("index", None) # Use the action whose button was pushed try: data.update({'action': data.getlist('action')[action_index]}) except IndexError: # If we didn't get an action from the chosen form that's invalid # POST data, so by deleting action it'll fail the validation check # below. So no need to do anything here pass action_form = self.action_form(data, auto_id=None) action_form.fields['action'].choices = self.get_action_choices(request) # If the form's valid we can handle the action. if action_form.is_valid(): action = action_form.cleaned_data['action'] select_across = action_form.cleaned_data['select_across'] func = self.get_actions(request)[action][0] # Get the list of selected PKs. If nothing's selected, we can't # perform an action on it, so bail. Except we want to perform # the action explicitly on all objects. selected = request.POST.getlist(helpers.ACTION_CHECKBOX_NAME) if not selected and not select_across: # Reminder that something needs to be selected or nothing will happen msg = _("Items must be selected in order to perform " "actions on them. No items have been changed.") self.message_user(request, msg, messages.WARNING) return None if not select_across: # Perform the action only on the selected objects queryset = queryset.filter(pk__in=selected) response = func(self, request, queryset) # Actions may return an HttpResponse-like object, which will be # used as the response from the POST. If not, we'll be a good # little HTTP citizen and redirect back to the changelist page. if isinstance(response, HttpResponseBase): return response else: return HttpResponseRedirect(request.get_full_path()) else: msg = _("No action selected.") self.message_user(request, msg, messages.WARNING) return None
def response_add(
self, request, obj, post_url_continue=None)
Determines the HttpResponse for the add_view stage.
def response_add(self, request, obj, post_url_continue=None): """ Determines the HttpResponse for the add_view stage. """ opts = obj._meta pk_value = obj._get_pk_val() preserved_filters = self.get_preserved_filters(request) msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)} # Here, we distinguish between different save types by checking for # the presence of keys in request.POST. if IS_POPUP_VAR in request.POST: return SimpleTemplateResponse('admin/popup_response.html', { 'pk_value': escape(pk_value), 'obj': escapejs(obj) }) elif "_continue" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) if post_url_continue is None: post_url_continue = reverse('admin:%s_%s_change' % (opts.app_label, opts.model_name), args=(pk_value,), current_app=self.admin_site.name) post_url_continue = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url_continue) return HttpResponseRedirect(post_url_continue) elif "_addanother" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may add another %(name)s below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = request.path redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) else: msg = _('The %(name)s "%(obj)s" was added successfully.') % msg_dict self.message_user(request, msg, messages.SUCCESS) return self.response_post_save_add(request, obj)
def response_change(
self, request, obj)
Determines the HttpResponse for the change_view stage.
def response_change(self, request, obj): """ Determines the HttpResponse for the change_view stage. """ opts = self.model._meta pk_value = obj._get_pk_val() preserved_filters = self.get_preserved_filters(request) msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)} if "_continue" in request.POST: msg = _('The %(name)s "%(obj)s" was changed successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = request.path redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) elif "_saveasnew" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = reverse('admin:%s_%s_change' % (opts.app_label, opts.model_name), args=(pk_value,), current_app=self.admin_site.name) redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) elif "_addanother" in request.POST: msg = _('The %(name)s "%(obj)s" was changed successfully. You may add another %(name)s below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = reverse('admin:%s_%s_add' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) else: msg = _('The %(name)s "%(obj)s" was changed successfully.') % msg_dict self.message_user(request, msg, messages.SUCCESS) return self.response_post_save_change(request, obj)
def response_post_save_add(
self, request, obj)
Figure out where to redirect after the 'Save' button has been pressed when adding a new object.
def response_post_save_add(self, request, obj): """ Figure out where to redirect after the 'Save' button has been pressed when adding a new object. """ opts = self.model._meta if self.has_change_permission(request, None): post_url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url) else: post_url = reverse('admin:index', current_app=self.admin_site.name) return HttpResponseRedirect(post_url)
def response_post_save_change(
self, request, obj)
Figure out where to redirect after the 'Save' button has been pressed when editing an existing object.
def response_post_save_change(self, request, obj): """ Figure out where to redirect after the 'Save' button has been pressed when editing an existing object. """ opts = self.model._meta if self.has_change_permission(request, None): post_url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url) else: post_url = reverse('admin:index', current_app=self.admin_site.name) return HttpResponseRedirect(post_url)
def save_form(
self, request, form, change)
Given a ModelForm return an unsaved instance. change
is True if
the object is being changed, and False if it's being added.
def save_form(self, request, form, change): """ Given a ModelForm return an unsaved instance. ``change`` is True if the object is being changed, and False if it's being added. """ return form.save(commit=False)
def save_formset(
self, request, form, formset, change)
Given an inline formset save it to the database.
def save_formset(self, request, form, formset, change): """ Given an inline formset save it to the database. """ formset.save()
def save_model(
self, request, obj, form, change)
Given a model instance save it to the database.
def save_model(self, request, obj, form, change): """ Given a model instance save it to the database. """ obj.save()
Given the HttpRequest
, the parent ModelForm
instance, the
list of inline formsets and a boolean value based on whether the
parent is being added or changed, save the related objects to the
database. Note that at this point save_form() and save_model() have
already been called.
def to_field_allowed(
self, request, to_field)
Returns True if the model associated with this admin should be allowed to be referenced by the specified field.
def to_field_allowed(self, request, to_field): """ Returns True if the model associated with this admin should be allowed to be referenced by the specified field. """ opts = self.model._meta try: field = opts.get_field(to_field) except FieldDoesNotExist: return False # Always allow referencing the primary key since it's already possible # to get this information from the change view URL. if field.primary_key: return True # Make sure at least one of the models registered for this site # references this field through a FK or a M2M relationship. registered_models = set() for model, admin in self.admin_site._registry.items(): registered_models.add(model) for inline in admin.inlines: registered_models.add(inline.model) for related_object in opts.get_all_related_objects(include_hidden=True): related_model = related_object.model if (any(issubclass(model, related_model) for model in registered_models) and related_object.field.rel.get_related_field() == field): return True return False
def validate(
cls, model)
@classmethod def validate(cls, model): validator = cls.validator_class() validator.validate(cls, model)
class LanguageAdmin
class LanguageAdmin(admin.ModelAdmin): search_fields = ['name', 'identifier'] ordering = ['name']
Ancestors (in MRO)
- LanguageAdmin
- django.contrib.admin.options.ModelAdmin
- django.contrib.admin.options.BaseModelAdmin
- __builtin__.object
Class variables
var action_form
var actions
var actions_on_bottom
var actions_on_top
var actions_selection_counter
var add_form_template
var change_form_template
var change_list_template
var date_hierarchy
var delete_confirmation_template
var delete_selected_confirmation_template
var exclude
var fields
var fieldsets
var filter_horizontal
var filter_vertical
var form
var formfield_overrides
var inlines
var list_display
var list_display_links
var list_editable
var list_filter
var list_max_show_all
var list_per_page
var object_history_template
var ordering
var paginator
var prepopulated_fields
var preserve_filters
var radio_fields
var raw_id_fields
var readonly_fields
var save_as
var save_on_top
var search_fields
var validator_class
Instance variables
var declared_fieldsets
var media
var urls
Methods
def __init__(
self, model, admin_site)
def __init__(self, model, admin_site): self.model = model self.opts = model._meta self.admin_site = admin_site super(ModelAdmin, self).__init__()
def action_checkbox(
self, obj)
A list_display column containing a checkbox widget.
def action_checkbox(self, obj): """ A list_display column containing a checkbox widget. """ return helpers.checkbox.render(helpers.ACTION_CHECKBOX_NAME, force_text(obj.pk))
def add_view(
self, *args, **kwargs)
The 'add' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def change_view(
self, *args, **kwargs)
The 'change' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def changelist_view(
self, *args, **kwargs)
The 'change list' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def construct_change_message(
self, request, form, formsets)
Construct a change message from a changed object.
def construct_change_message(self, request, form, formsets): """ Construct a change message from a changed object. """ change_message = [] if form.changed_data: change_message.append(_('Changed %s.') % get_text_list(form.changed_data, _('and'))) if formsets: for formset in formsets: for added_object in formset.new_objects: change_message.append(_('Added %(name)s "%(object)s".') % {'name': force_text(added_object._meta.verbose_name), 'object': force_text(added_object)}) for changed_object, changed_fields in formset.changed_objects: change_message.append(_('Changed %(list)s for %(name)s "%(object)s".') % {'list': get_text_list(changed_fields, _('and')), 'name': force_text(changed_object._meta.verbose_name), 'object': force_text(changed_object)}) for deleted_object in formset.deleted_objects: change_message.append(_('Deleted %(name)s "%(object)s".') % {'name': force_text(deleted_object._meta.verbose_name), 'object': force_text(deleted_object)}) change_message = ' '.join(change_message) return change_message or _('No fields changed.')
def delete_model(
self, request, obj)
Given a model instance delete it from the database.
def delete_model(self, request, obj): """ Given a model instance delete it from the database. """ obj.delete()
def delete_view(
self, *args, **kwargs)
The 'delete' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def formfield_for_choice_field(
self, db_field, request=None, **kwargs)
Get a form Field for a database Field that has declared choices.
def formfield_for_choice_field(self, db_field, request=None, **kwargs): """ Get a form Field for a database Field that has declared choices. """ # If the field is named as a radio_field, use a RadioSelect if db_field.name in self.radio_fields: # Avoid stomping on custom widget/choices arguments. if 'widget' not in kwargs: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) if 'choices' not in kwargs: kwargs['choices'] = db_field.get_choices( include_blank=db_field.blank, blank_choice=[('', _('None'))] ) return db_field.formfield(**kwargs)
def formfield_for_dbfield(
self, db_field, **kwargs)
Hook for specifying the form Field instance for a given database Field instance.
If kwargs are given, they're passed to the form Field's constructor.
def formfield_for_dbfield(self, db_field, **kwargs): """ Hook for specifying the form Field instance for a given database Field instance. If kwargs are given, they're passed to the form Field's constructor. """ request = kwargs.pop("request", None) # If the field specifies choices, we don't need to look for special # admin widgets - we just need to use a select widget of some kind. if db_field.choices: return self.formfield_for_choice_field(db_field, request, **kwargs) # ForeignKey or ManyToManyFields if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)): # Combine the field kwargs with any options for formfield_overrides. # Make sure the passed in **kwargs override anything in # formfield_overrides because **kwargs is more specific, and should # always win. if db_field.__class__ in self.formfield_overrides: kwargs = dict(self.formfield_overrides[db_field.__class__], **kwargs) # Get the correct formfield. if isinstance(db_field, models.ForeignKey): formfield = self.formfield_for_foreignkey(db_field, request, **kwargs) elif isinstance(db_field, models.ManyToManyField): formfield = self.formfield_for_manytomany(db_field, request, **kwargs) # For non-raw_id fields, wrap the widget with a wrapper that adds # extra HTML -- the "add other" interface -- to the end of the # rendered output. formfield can be None if it came from a # OneToOneField with parent_link=True or a M2M intermediary. if formfield and db_field.name not in self.raw_id_fields: related_modeladmin = self.admin_site._registry.get( db_field.rel.to) can_add_related = bool(related_modeladmin and related_modeladmin.has_add_permission(request)) formfield.widget = widgets.RelatedFieldWidgetWrapper( formfield.widget, db_field.rel, self.admin_site, can_add_related=can_add_related) return formfield # If we've got overrides for the formfield defined, use 'em. **kwargs # passed to formfield_for_dbfield override the defaults. for klass in db_field.__class__.mro(): if klass in self.formfield_overrides: kwargs = dict(copy.deepcopy(self.formfield_overrides[klass]), **kwargs) return db_field.formfield(**kwargs) # For any other type of field, just call its formfield() method. return db_field.formfield(**kwargs)
def formfield_for_foreignkey(
self, db_field, request=None, **kwargs)
Get a form Field for a ForeignKey.
def formfield_for_foreignkey(self, db_field, request=None, **kwargs): """ Get a form Field for a ForeignKey. """ db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel, self.admin_site, using=db) elif db_field.name in self.radio_fields: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) kwargs['empty_label'] = _('None') if db_field.blank else None if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def formfield_for_manytomany(
self, db_field, request=None, **kwargs)
Get a form Field for a ManyToManyField.
def formfield_for_manytomany(self, db_field, request=None, **kwargs): """ Get a form Field for a ManyToManyField. """ # If it uses an intermediary model that isn't auto created, don't show # a field in admin. if not db_field.rel.through._meta.auto_created: return None db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel, self.admin_site, using=db) kwargs['help_text'] = '' elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)): kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical)) if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def get_action(
self, action)
Return a given action from a parameter, which can either be a callable, or the name of a method on the ModelAdmin. Return is a tuple of (callable, name, description).
def get_action(self, action): """ Return a given action from a parameter, which can either be a callable, or the name of a method on the ModelAdmin. Return is a tuple of (callable, name, description). """ # If the action is a callable, just use it. if callable(action): func = action action = action.__name__ # Next, look for a method. Grab it off self.__class__ to get an unbound # method instead of a bound one; this ensures that the calling # conventions are the same for functions and methods. elif hasattr(self.__class__, action): func = getattr(self.__class__, action) # Finally, look for a named method on the admin site else: try: func = self.admin_site.get_action(action) except KeyError: return None if hasattr(func, 'short_description'): description = func.short_description else: description = capfirst(action.replace('_', ' ')) return func, action, description
def get_action_choices(
self, request, default_choices=[(u'', u'---------')])
Return a list of choices for use in a form object. Each choice is a tuple (name, description).
def get_action_choices(self, request, default_choices=BLANK_CHOICE_DASH): """ Return a list of choices for use in a form object. Each choice is a tuple (name, description). """ choices = [] + default_choices for func, name, description in six.itervalues(self.get_actions(request)): choice = (name, description % model_format_dict(self.opts)) choices.append(choice) return choices
def get_actions(
self, request)
Return a dictionary mapping the names of all actions for this ModelAdmin to a tuple of (callable, name, description) for each action.
def get_actions(self, request): """ Return a dictionary mapping the names of all actions for this ModelAdmin to a tuple of (callable, name, description) for each action. """ # If self.actions is explicitly set to None that means that we don't # want *any* actions enabled on this page. from django.contrib.admin.views.main import _is_changelist_popup if self.actions is None or _is_changelist_popup(request): return SortedDict() actions = [] # Gather actions from the admin site first for (name, func) in self.admin_site.actions: description = getattr(func, 'short_description', name.replace('_', ' ')) actions.append((func, name, description)) # Then gather them from the model admin and all parent classes, # starting with self and working back up. for klass in self.__class__.mro()[::-1]: class_actions = getattr(klass, 'actions', []) # Avoid trying to iterate over None if not class_actions: continue actions.extend([self.get_action(action) for action in class_actions]) # get_action might have returned None, so filter any of those out. actions = filter(None, actions) # Convert the actions into a SortedDict keyed by name. actions = SortedDict([ (name, (func, name, desc)) for func, name, desc in actions ]) return actions
def get_changelist(
self, request, **kwargs)
Returns the ChangeList class for use on the changelist page.
def get_changelist(self, request, **kwargs): """ Returns the ChangeList class for use on the changelist page. """ from django.contrib.admin.views.main import ChangeList return ChangeList
def get_changelist_form(
self, request, **kwargs)
Returns a Form class for use in the Formset on the changelist page.
def get_changelist_form(self, request, **kwargs): """ Returns a Form class for use in the Formset on the changelist page. """ defaults = { "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) if (defaults.get('fields') is None and not modelform_defines_fields(defaults.get('form'))): defaults['fields'] = forms.ALL_FIELDS return modelform_factory(self.model, **defaults)
def get_changelist_formset(
self, request, **kwargs)
Returns a FormSet class for use on the changelist page if list_editable is used.
def get_changelist_formset(self, request, **kwargs): """ Returns a FormSet class for use on the changelist page if list_editable is used. """ defaults = { "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) return modelformset_factory(self.model, self.get_changelist_form(request), extra=0, fields=self.list_editable, **defaults)
def get_field_queryset(
self, db, db_field, request)
If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case).
def get_field_queryset(self, db, db_field, request): """ If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case). """ related_admin = self.admin_site._registry.get(db_field.rel.to, None) if related_admin is not None: ordering = related_admin.get_ordering(request) if ordering is not None and ordering != (): return db_field.rel.to._default_manager.using(db).order_by(*ordering).complex_filter(db_field.rel.limit_choices_to) return None
def get_fieldsets(
self, request, obj=None)
Hook for specifying fieldsets for the add form.
def get_fieldsets(self, request, obj=None): "Hook for specifying fieldsets for the add form." if self.declared_fieldsets: return self.declared_fieldsets form = self.get_form(request, obj, fields=None) fields = list(form.base_fields) + list(self.get_readonly_fields(request, obj)) return [(None, {'fields': fields})]
def get_form(
self, request, obj=None, **kwargs)
Returns a Form class for use in the admin add view. This is used by add_view and change_view.
def get_form(self, request, obj=None, **kwargs): """ Returns a Form class for use in the admin add view. This is used by add_view and change_view. """ if 'fields' in kwargs: fields = kwargs.pop('fields') else: fields = flatten_fieldsets(self.get_fieldsets(request, obj)) if self.exclude is None: exclude = [] else: exclude = list(self.exclude) exclude.extend(self.get_readonly_fields(request, obj)) if self.exclude is None and hasattr(self.form, '_meta') and self.form._meta.exclude: # Take the custom ModelForm's Meta.exclude into account only if the # ModelAdmin doesn't define its own. exclude.extend(self.form._meta.exclude) # if exclude is an empty list we pass None to be consistent with the # default on modelform_factory exclude = exclude or None defaults = { "form": self.form, "fields": fields, "exclude": exclude, "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) if defaults['fields'] is None and not modelform_defines_fields(defaults['form']): defaults['fields'] = forms.ALL_FIELDS try: return modelform_factory(self.model, **defaults) except FieldError as e: raise FieldError('%s. Check fields/fieldsets/exclude attributes of class %s.' % (e, self.__class__.__name__))
def get_formsets(
self, request, obj=None)
def get_formsets(self, request, obj=None): for inline in self.get_inline_instances(request, obj): yield inline.get_formset(request, obj)
def get_inline_instances(
self, request, obj=None)
def get_inline_instances(self, request, obj=None): inline_instances = [] for inline_class in self.inlines: inline = inline_class(self.model, self.admin_site) if request: if not (inline.has_add_permission(request) or inline.has_change_permission(request, obj) or inline.has_delete_permission(request, obj)): continue if not inline.has_add_permission(request): inline.max_num = 0 inline_instances.append(inline) return inline_instances
def get_list_display(
self, request)
Return a sequence containing the fields to be displayed on the changelist.
def get_list_display(self, request): """ Return a sequence containing the fields to be displayed on the changelist. """ return self.list_display
def get_list_display_links(
self, request, list_display)
Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display().
def get_list_display_links(self, request, list_display): """ Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display(). """ if self.list_display_links or not list_display: return self.list_display_links else: # Use only the first item in list_display as link return list(list_display)[:1]
def get_list_filter(
self, request)
Returns a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page.
def get_list_filter(self, request): """ Returns a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page. """ return self.list_filter
def get_model_perms(
self, request)
Returns a dict of all perms for this model. This dict has the keys
add
, change
, and delete
mapping to the True/False for each
of those actions.
def get_model_perms(self, request): """ Returns a dict of all perms for this model. This dict has the keys ``add``, ``change``, and ``delete`` mapping to the True/False for each of those actions. """ return { 'add': self.has_add_permission(request), 'change': self.has_change_permission(request), 'delete': self.has_delete_permission(request), }
def get_object(
self, request, object_id)
Returns an instance matching the primary key provided. None
is
returned if no match is found (or the object_id failed validation
against the primary key field).
def get_object(self, request, object_id): """ Returns an instance matching the primary key provided. ``None`` is returned if no match is found (or the object_id failed validation against the primary key field). """ queryset = self.get_queryset(request) model = queryset.model try: object_id = model._meta.pk.to_python(object_id) return queryset.get(pk=object_id) except (model.DoesNotExist, ValidationError, ValueError): return None
def get_ordering(
self, request)
Hook for specifying field ordering.
def get_ordering(self, request): """ Hook for specifying field ordering. """ return self.ordering or () # otherwise we might try to *None, which is bad ;)
def get_paginator(
self, request, queryset, per_page, orphans=0, allow_empty_first_page=True)
def get_paginator(self, request, queryset, per_page, orphans=0, allow_empty_first_page=True): return self.paginator(queryset, per_page, orphans, allow_empty_first_page)
def get_prepopulated_fields(
self, request, obj=None)
Hook for specifying custom prepopulated fields.
def get_prepopulated_fields(self, request, obj=None): """ Hook for specifying custom prepopulated fields. """ return self.prepopulated_fields
def get_preserved_filters(
self, request)
Returns the preserved filters querystring.
def get_preserved_filters(self, request): """ Returns the preserved filters querystring. """ match = request.resolver_match if self.preserve_filters and match: opts = self.model._meta current_url = '%s:%s' % (match.app_name, match.url_name) changelist_url = 'admin:%s_%s_changelist' % (opts.app_label, opts.model_name) if current_url == changelist_url: preserved_filters = request.GET.urlencode() else: preserved_filters = request.GET.get('_changelist_filters') if preserved_filters: return urlencode({'_changelist_filters': preserved_filters}) return ''
def get_queryset(
self, request)
Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view.
def get_queryset(self, request): """ Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view. """ qs = self.model._default_manager.get_queryset() # TODO: this should be handled by some parameter to the ChangeList. ordering = self.get_ordering(request) if ordering: qs = qs.order_by(*ordering) return qs
def get_readonly_fields(
self, request, obj=None)
Hook for specifying custom readonly fields.
def get_readonly_fields(self, request, obj=None): """ Hook for specifying custom readonly fields. """ return self.readonly_fields
def get_search_results(
self, request, queryset, search_term)
Returns a tuple containing a queryset to implement the search, and a boolean indicating if the results may contain duplicates.
def get_search_results(self, request, queryset, search_term): """ Returns a tuple containing a queryset to implement the search, and a boolean indicating if the results may contain duplicates. """ # Apply keyword searches. def construct_search(field_name): if field_name.startswith('^'): return "%s__istartswith" % field_name[1:] elif field_name.startswith('='): return "%s__iexact" % field_name[1:] elif field_name.startswith('@'): return "%s__search" % field_name[1:] else: return "%s__icontains" % field_name use_distinct = False if self.search_fields and search_term: orm_lookups = [construct_search(str(search_field)) for search_field in self.search_fields] for bit in search_term.split(): or_queries = [models.Q(**{orm_lookup: bit}) for orm_lookup in orm_lookups] queryset = queryset.filter(reduce(operator.or_, or_queries)) if not use_distinct: for search_spec in orm_lookups: if lookup_needs_distinct(self.opts, search_spec): use_distinct = True break return queryset, use_distinct
def get_urls(
self)
def get_urls(self): from django.conf.urls import patterns, url def wrap(view): def wrapper(*args, **kwargs): return self.admin_site.admin_view(view)(*args, **kwargs) return update_wrapper(wrapper, view) info = self.model._meta.app_label, self.model._meta.model_name urlpatterns = patterns('', url(r'^$', wrap(self.changelist_view), name='%s_%s_changelist' % info), url(r'^add/$', wrap(self.add_view), name='%s_%s_add' % info), url(r'^(.+)/history/$', wrap(self.history_view), name='%s_%s_history' % info), url(r'^(.+)/delete/$', wrap(self.delete_view), name='%s_%s_delete' % info), url(r'^(.+)/$', wrap(self.change_view), name='%s_%s_change' % info), ) return urlpatterns
def has_add_permission(
self, request)
Returns True if the given request has permission to add an object. Can be overridden by the user in subclasses.
def has_add_permission(self, request): """ Returns True if the given request has permission to add an object. Can be overridden by the user in subclasses. """ opts = self.opts codename = get_permission_codename('add', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_change_permission(
self, request, obj=None)
Returns True if the given request has permission to change the given
Django model instance, the default implementation doesn't examine the
obj
parameter.
Can be overridden by the user in subclasses. In such case it should
return True if the given request has permission to change the obj
model instance. If obj
is None, this should return True if the given
request has permission to change any object of the given type.
def has_change_permission(self, request, obj=None): """ Returns True if the given request has permission to change the given Django model instance, the default implementation doesn't examine the `obj` parameter. Can be overridden by the user in subclasses. In such case it should return True if the given request has permission to change the `obj` model instance. If `obj` is None, this should return True if the given request has permission to change *any* object of the given type. """ opts = self.opts codename = get_permission_codename('change', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_delete_permission(
self, request, obj=None)
Returns True if the given request has permission to change the given
Django model instance, the default implementation doesn't examine the
obj
parameter.
Can be overridden by the user in subclasses. In such case it should
return True if the given request has permission to delete the obj
model instance. If obj
is None, this should return True if the given
request has permission to delete any object of the given type.
def has_delete_permission(self, request, obj=None): """ Returns True if the given request has permission to change the given Django model instance, the default implementation doesn't examine the `obj` parameter. Can be overridden by the user in subclasses. In such case it should return True if the given request has permission to delete the `obj` model instance. If `obj` is None, this should return True if the given request has permission to delete *any* object of the given type. """ opts = self.opts codename = get_permission_codename('delete', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def history_view(
self, request, object_id, extra_context=None)
The 'history' admin view for this model.
def history_view(self, request, object_id, extra_context=None): "The 'history' admin view for this model." from django.contrib.admin.models import LogEntry # First check if the user can see this history. model = self.model obj = get_object_or_404(model, pk=unquote(object_id)) if not self.has_change_permission(request, obj): raise PermissionDenied # Then get the history for this object. opts = model._meta app_label = opts.app_label action_list = LogEntry.objects.filter( object_id=unquote(object_id), content_type__id__exact=ContentType.objects.get_for_model(model).id ).select_related().order_by('action_time') context = { 'title': _('Change history: %s') % force_text(obj), 'action_list': action_list, 'module_name': capfirst(force_text(opts.verbose_name_plural)), 'object': obj, 'app_label': app_label, 'opts': opts, 'preserved_filters': self.get_preserved_filters(request), } context.update(extra_context or {}) return TemplateResponse(request, self.object_history_template or [ "admin/%s/%s/object_history.html" % (app_label, opts.model_name), "admin/%s/object_history.html" % app_label, "admin/object_history.html" ], context, current_app=self.admin_site.name)
def log_addition(
self, request, object)
Log that an object has been successfully added.
The default implementation creates an admin LogEntry object.
def log_addition(self, request, object): """ Log that an object has been successfully added. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, ADDITION LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=ADDITION )
def log_change(
self, request, object, message)
Log that an object has been successfully changed.
The default implementation creates an admin LogEntry object.
def log_change(self, request, object, message): """ Log that an object has been successfully changed. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, CHANGE LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=CHANGE, change_message=message )
def log_deletion(
self, request, object, object_repr)
Log that an object will be deleted. Note that this method is called before the deletion.
The default implementation creates an admin LogEntry object.
def log_deletion(self, request, object, object_repr): """ Log that an object will be deleted. Note that this method is called before the deletion. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, DELETION LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(self.model).pk, object_id=object.pk, object_repr=object_repr, action_flag=DELETION )
def lookup_allowed(
self, lookup, value)
def lookup_allowed(self, lookup, value): model = self.model # Check FKey lookups that are allowed, so that popups produced by # ForeignKeyRawIdWidget, on the basis of ForeignKey.limit_choices_to, # are allowed to work. for l in model._meta.related_fkey_lookups: for k, v in widgets.url_params_from_lookup_dict(l).items(): if k == lookup and v == value: return True parts = lookup.split(LOOKUP_SEP) # Last term in lookup is a query term (__exact, __startswith etc) # This term can be ignored. if len(parts) > 1 and parts[-1] in QUERY_TERMS: parts.pop() # Special case -- foo__id__exact and foo__id queries are implied # if foo has been specifically included in the lookup list; so # drop __id if it is the last part. However, first we need to find # the pk attribute name. rel_name = None for part in parts[:-1]: try: field, _, _, _ = model._meta.get_field_by_name(part) except FieldDoesNotExist: # Lookups on non-existent fields are ok, since they're ignored # later. return True if hasattr(field, 'rel'): if field.rel is None: # This property or relation doesn't exist, but it's allowed # since it's ignored in ChangeList.get_filters(). return True model = field.rel.to rel_name = field.rel.get_related_field().name elif isinstance(field, RelatedObject): model = field.model rel_name = model._meta.pk.name else: rel_name = None if rel_name and len(parts) > 1 and parts[-1] == rel_name: parts.pop() if len(parts) == 1: return True clean_lookup = LOOKUP_SEP.join(parts) return clean_lookup in self.list_filter or clean_lookup == self.date_hierarchy
def message_user(
self, request, message, level=20, extra_tags='', fail_silently=False)
Send a message to the user. The default implementation posts a message using the django.contrib.messages backend.
Exposes almost the same API as messages.add_message(), but accepts the
positional arguments in a different order to maintain backwards
compatibility. For convenience, it accepts the level
argument as
a string rather than the usual level number.
def message_user(self, request, message, level=messages.INFO, extra_tags='', fail_silently=False): """ Send a message to the user. The default implementation posts a message using the django.contrib.messages backend. Exposes almost the same API as messages.add_message(), but accepts the positional arguments in a different order to maintain backwards compatibility. For convenience, it accepts the `level` argument as a string rather than the usual level number. """ if not isinstance(level, int): # attempt to get the level if passed a string try: level = getattr(messages.constants, level.upper()) except AttributeError: levels = messages.constants.DEFAULT_TAGS.values() levels_repr = ', '.join('`%s`' % l for l in levels) raise ValueError('Bad message level string: `%s`. ' 'Possible values are: %s' % (level, levels_repr)) messages.add_message(request, level, message, extra_tags=extra_tags, fail_silently=fail_silently)
def queryset(
*args, **kwargs)
def wrapped(*args, **kwargs): warnings.warn( "`%s.%s` is deprecated, use `%s` instead." % (self.class_name, self.old_method_name, self.new_method_name), self.deprecation_warning, 2) return f(*args, **kwargs)
def render_change_form(
self, request, context, add=False, change=False, form_url='', obj=None)
def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None): opts = self.model._meta app_label = opts.app_label preserved_filters = self.get_preserved_filters(request) form_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, form_url) context.update({ 'add': add, 'change': change, 'has_add_permission': self.has_add_permission(request), 'has_change_permission': self.has_change_permission(request, obj), 'has_delete_permission': self.has_delete_permission(request, obj), 'has_file_field': True, # FIXME - this should check if form or formsets have a FileField, 'has_absolute_url': hasattr(self.model, 'get_absolute_url'), 'form_url': form_url, 'opts': opts, 'content_type_id': ContentType.objects.get_for_model(self.model).id, 'save_as': self.save_as, 'save_on_top': self.save_on_top, }) if add and self.add_form_template is not None: form_template = self.add_form_template else: form_template = self.change_form_template return TemplateResponse(request, form_template or [ "admin/%s/%s/change_form.html" % (app_label, opts.model_name), "admin/%s/change_form.html" % app_label, "admin/change_form.html" ], context, current_app=self.admin_site.name)
def response_action(
self, request, queryset)
Handle an admin action. This is called if a request is POSTed to the changelist; it returns an HttpResponse if the action was handled, and None otherwise.
def response_action(self, request, queryset): """ Handle an admin action. This is called if a request is POSTed to the changelist; it returns an HttpResponse if the action was handled, and None otherwise. """ # There can be multiple action forms on the page (at the top # and bottom of the change list, for example). Get the action # whose button was pushed. try: action_index = int(request.POST.get('index', 0)) except ValueError: action_index = 0 # Construct the action form. data = request.POST.copy() data.pop(helpers.ACTION_CHECKBOX_NAME, None) data.pop("index", None) # Use the action whose button was pushed try: data.update({'action': data.getlist('action')[action_index]}) except IndexError: # If we didn't get an action from the chosen form that's invalid # POST data, so by deleting action it'll fail the validation check # below. So no need to do anything here pass action_form = self.action_form(data, auto_id=None) action_form.fields['action'].choices = self.get_action_choices(request) # If the form's valid we can handle the action. if action_form.is_valid(): action = action_form.cleaned_data['action'] select_across = action_form.cleaned_data['select_across'] func = self.get_actions(request)[action][0] # Get the list of selected PKs. If nothing's selected, we can't # perform an action on it, so bail. Except we want to perform # the action explicitly on all objects. selected = request.POST.getlist(helpers.ACTION_CHECKBOX_NAME) if not selected and not select_across: # Reminder that something needs to be selected or nothing will happen msg = _("Items must be selected in order to perform " "actions on them. No items have been changed.") self.message_user(request, msg, messages.WARNING) return None if not select_across: # Perform the action only on the selected objects queryset = queryset.filter(pk__in=selected) response = func(self, request, queryset) # Actions may return an HttpResponse-like object, which will be # used as the response from the POST. If not, we'll be a good # little HTTP citizen and redirect back to the changelist page. if isinstance(response, HttpResponseBase): return response else: return HttpResponseRedirect(request.get_full_path()) else: msg = _("No action selected.") self.message_user(request, msg, messages.WARNING) return None
def response_add(
self, request, obj, post_url_continue=None)
Determines the HttpResponse for the add_view stage.
def response_add(self, request, obj, post_url_continue=None): """ Determines the HttpResponse for the add_view stage. """ opts = obj._meta pk_value = obj._get_pk_val() preserved_filters = self.get_preserved_filters(request) msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)} # Here, we distinguish between different save types by checking for # the presence of keys in request.POST. if IS_POPUP_VAR in request.POST: return SimpleTemplateResponse('admin/popup_response.html', { 'pk_value': escape(pk_value), 'obj': escapejs(obj) }) elif "_continue" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) if post_url_continue is None: post_url_continue = reverse('admin:%s_%s_change' % (opts.app_label, opts.model_name), args=(pk_value,), current_app=self.admin_site.name) post_url_continue = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url_continue) return HttpResponseRedirect(post_url_continue) elif "_addanother" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may add another %(name)s below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = request.path redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) else: msg = _('The %(name)s "%(obj)s" was added successfully.') % msg_dict self.message_user(request, msg, messages.SUCCESS) return self.response_post_save_add(request, obj)
def response_change(
self, request, obj)
Determines the HttpResponse for the change_view stage.
def response_change(self, request, obj): """ Determines the HttpResponse for the change_view stage. """ opts = self.model._meta pk_value = obj._get_pk_val() preserved_filters = self.get_preserved_filters(request) msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)} if "_continue" in request.POST: msg = _('The %(name)s "%(obj)s" was changed successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = request.path redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) elif "_saveasnew" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = reverse('admin:%s_%s_change' % (opts.app_label, opts.model_name), args=(pk_value,), current_app=self.admin_site.name) redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) elif "_addanother" in request.POST: msg = _('The %(name)s "%(obj)s" was changed successfully. You may add another %(name)s below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = reverse('admin:%s_%s_add' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) else: msg = _('The %(name)s "%(obj)s" was changed successfully.') % msg_dict self.message_user(request, msg, messages.SUCCESS) return self.response_post_save_change(request, obj)
def response_post_save_add(
self, request, obj)
Figure out where to redirect after the 'Save' button has been pressed when adding a new object.
def response_post_save_add(self, request, obj): """ Figure out where to redirect after the 'Save' button has been pressed when adding a new object. """ opts = self.model._meta if self.has_change_permission(request, None): post_url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url) else: post_url = reverse('admin:index', current_app=self.admin_site.name) return HttpResponseRedirect(post_url)
def response_post_save_change(
self, request, obj)
Figure out where to redirect after the 'Save' button has been pressed when editing an existing object.
def response_post_save_change(self, request, obj): """ Figure out where to redirect after the 'Save' button has been pressed when editing an existing object. """ opts = self.model._meta if self.has_change_permission(request, None): post_url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url) else: post_url = reverse('admin:index', current_app=self.admin_site.name) return HttpResponseRedirect(post_url)
def save_form(
self, request, form, change)
Given a ModelForm return an unsaved instance. change
is True if
the object is being changed, and False if it's being added.
def save_form(self, request, form, change): """ Given a ModelForm return an unsaved instance. ``change`` is True if the object is being changed, and False if it's being added. """ return form.save(commit=False)
def save_formset(
self, request, form, formset, change)
Given an inline formset save it to the database.
def save_formset(self, request, form, formset, change): """ Given an inline formset save it to the database. """ formset.save()
def save_model(
self, request, obj, form, change)
Given a model instance save it to the database.
def save_model(self, request, obj, form, change): """ Given a model instance save it to the database. """ obj.save()
Given the HttpRequest
, the parent ModelForm
instance, the
list of inline formsets and a boolean value based on whether the
parent is being added or changed, save the related objects to the
database. Note that at this point save_form() and save_model() have
already been called.
def to_field_allowed(
self, request, to_field)
Returns True if the model associated with this admin should be allowed to be referenced by the specified field.
def to_field_allowed(self, request, to_field): """ Returns True if the model associated with this admin should be allowed to be referenced by the specified field. """ opts = self.model._meta try: field = opts.get_field(to_field) except FieldDoesNotExist: return False # Always allow referencing the primary key since it's already possible # to get this information from the change view URL. if field.primary_key: return True # Make sure at least one of the models registered for this site # references this field through a FK or a M2M relationship. registered_models = set() for model, admin in self.admin_site._registry.items(): registered_models.add(model) for inline in admin.inlines: registered_models.add(inline.model) for related_object in opts.get_all_related_objects(include_hidden=True): related_model = related_object.model if (any(issubclass(model, related_model) for model in registered_models) and related_object.field.rel.get_related_field() == field): return True return False
def validate(
cls, model)
@classmethod def validate(cls, model): validator = cls.validator_class() validator.validate(cls, model)
class LocationAdmin
class LocationAdmin(admin.ModelAdmin): search_fields = ['name'] ordering = ['name']
Ancestors (in MRO)
- LocationAdmin
- django.contrib.admin.options.ModelAdmin
- django.contrib.admin.options.BaseModelAdmin
- __builtin__.object
Class variables
var action_form
var actions
var actions_on_bottom
var actions_on_top
var actions_selection_counter
var add_form_template
var change_form_template
var change_list_template
var date_hierarchy
var delete_confirmation_template
var delete_selected_confirmation_template
var exclude
var fields
var fieldsets
var filter_horizontal
var filter_vertical
var form
var formfield_overrides
var inlines
var list_display
var list_display_links
var list_editable
var list_filter
var list_max_show_all
var list_per_page
var object_history_template
var ordering
var paginator
var prepopulated_fields
var preserve_filters
var radio_fields
var raw_id_fields
var readonly_fields
var save_as
var save_on_top
var search_fields
var validator_class
Instance variables
var declared_fieldsets
var media
var urls
Methods
def __init__(
self, model, admin_site)
def __init__(self, model, admin_site): self.model = model self.opts = model._meta self.admin_site = admin_site super(ModelAdmin, self).__init__()
def action_checkbox(
self, obj)
A list_display column containing a checkbox widget.
def action_checkbox(self, obj): """ A list_display column containing a checkbox widget. """ return helpers.checkbox.render(helpers.ACTION_CHECKBOX_NAME, force_text(obj.pk))
def add_view(
self, *args, **kwargs)
The 'add' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def change_view(
self, *args, **kwargs)
The 'change' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def changelist_view(
self, *args, **kwargs)
The 'change list' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def construct_change_message(
self, request, form, formsets)
Construct a change message from a changed object.
def construct_change_message(self, request, form, formsets): """ Construct a change message from a changed object. """ change_message = [] if form.changed_data: change_message.append(_('Changed %s.') % get_text_list(form.changed_data, _('and'))) if formsets: for formset in formsets: for added_object in formset.new_objects: change_message.append(_('Added %(name)s "%(object)s".') % {'name': force_text(added_object._meta.verbose_name), 'object': force_text(added_object)}) for changed_object, changed_fields in formset.changed_objects: change_message.append(_('Changed %(list)s for %(name)s "%(object)s".') % {'list': get_text_list(changed_fields, _('and')), 'name': force_text(changed_object._meta.verbose_name), 'object': force_text(changed_object)}) for deleted_object in formset.deleted_objects: change_message.append(_('Deleted %(name)s "%(object)s".') % {'name': force_text(deleted_object._meta.verbose_name), 'object': force_text(deleted_object)}) change_message = ' '.join(change_message) return change_message or _('No fields changed.')
def delete_model(
self, request, obj)
Given a model instance delete it from the database.
def delete_model(self, request, obj): """ Given a model instance delete it from the database. """ obj.delete()
def delete_view(
self, *args, **kwargs)
The 'delete' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def formfield_for_choice_field(
self, db_field, request=None, **kwargs)
Get a form Field for a database Field that has declared choices.
def formfield_for_choice_field(self, db_field, request=None, **kwargs): """ Get a form Field for a database Field that has declared choices. """ # If the field is named as a radio_field, use a RadioSelect if db_field.name in self.radio_fields: # Avoid stomping on custom widget/choices arguments. if 'widget' not in kwargs: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) if 'choices' not in kwargs: kwargs['choices'] = db_field.get_choices( include_blank=db_field.blank, blank_choice=[('', _('None'))] ) return db_field.formfield(**kwargs)
def formfield_for_dbfield(
self, db_field, **kwargs)
Hook for specifying the form Field instance for a given database Field instance.
If kwargs are given, they're passed to the form Field's constructor.
def formfield_for_dbfield(self, db_field, **kwargs): """ Hook for specifying the form Field instance for a given database Field instance. If kwargs are given, they're passed to the form Field's constructor. """ request = kwargs.pop("request", None) # If the field specifies choices, we don't need to look for special # admin widgets - we just need to use a select widget of some kind. if db_field.choices: return self.formfield_for_choice_field(db_field, request, **kwargs) # ForeignKey or ManyToManyFields if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)): # Combine the field kwargs with any options for formfield_overrides. # Make sure the passed in **kwargs override anything in # formfield_overrides because **kwargs is more specific, and should # always win. if db_field.__class__ in self.formfield_overrides: kwargs = dict(self.formfield_overrides[db_field.__class__], **kwargs) # Get the correct formfield. if isinstance(db_field, models.ForeignKey): formfield = self.formfield_for_foreignkey(db_field, request, **kwargs) elif isinstance(db_field, models.ManyToManyField): formfield = self.formfield_for_manytomany(db_field, request, **kwargs) # For non-raw_id fields, wrap the widget with a wrapper that adds # extra HTML -- the "add other" interface -- to the end of the # rendered output. formfield can be None if it came from a # OneToOneField with parent_link=True or a M2M intermediary. if formfield and db_field.name not in self.raw_id_fields: related_modeladmin = self.admin_site._registry.get( db_field.rel.to) can_add_related = bool(related_modeladmin and related_modeladmin.has_add_permission(request)) formfield.widget = widgets.RelatedFieldWidgetWrapper( formfield.widget, db_field.rel, self.admin_site, can_add_related=can_add_related) return formfield # If we've got overrides for the formfield defined, use 'em. **kwargs # passed to formfield_for_dbfield override the defaults. for klass in db_field.__class__.mro(): if klass in self.formfield_overrides: kwargs = dict(copy.deepcopy(self.formfield_overrides[klass]), **kwargs) return db_field.formfield(**kwargs) # For any other type of field, just call its formfield() method. return db_field.formfield(**kwargs)
def formfield_for_foreignkey(
self, db_field, request=None, **kwargs)
Get a form Field for a ForeignKey.
def formfield_for_foreignkey(self, db_field, request=None, **kwargs): """ Get a form Field for a ForeignKey. """ db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel, self.admin_site, using=db) elif db_field.name in self.radio_fields: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) kwargs['empty_label'] = _('None') if db_field.blank else None if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def formfield_for_manytomany(
self, db_field, request=None, **kwargs)
Get a form Field for a ManyToManyField.
def formfield_for_manytomany(self, db_field, request=None, **kwargs): """ Get a form Field for a ManyToManyField. """ # If it uses an intermediary model that isn't auto created, don't show # a field in admin. if not db_field.rel.through._meta.auto_created: return None db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel, self.admin_site, using=db) kwargs['help_text'] = '' elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)): kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical)) if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def get_action(
self, action)
Return a given action from a parameter, which can either be a callable, or the name of a method on the ModelAdmin. Return is a tuple of (callable, name, description).
def get_action(self, action): """ Return a given action from a parameter, which can either be a callable, or the name of a method on the ModelAdmin. Return is a tuple of (callable, name, description). """ # If the action is a callable, just use it. if callable(action): func = action action = action.__name__ # Next, look for a method. Grab it off self.__class__ to get an unbound # method instead of a bound one; this ensures that the calling # conventions are the same for functions and methods. elif hasattr(self.__class__, action): func = getattr(self.__class__, action) # Finally, look for a named method on the admin site else: try: func = self.admin_site.get_action(action) except KeyError: return None if hasattr(func, 'short_description'): description = func.short_description else: description = capfirst(action.replace('_', ' ')) return func, action, description
def get_action_choices(
self, request, default_choices=[(u'', u'---------')])
Return a list of choices for use in a form object. Each choice is a tuple (name, description).
def get_action_choices(self, request, default_choices=BLANK_CHOICE_DASH): """ Return a list of choices for use in a form object. Each choice is a tuple (name, description). """ choices = [] + default_choices for func, name, description in six.itervalues(self.get_actions(request)): choice = (name, description % model_format_dict(self.opts)) choices.append(choice) return choices
def get_actions(
self, request)
Return a dictionary mapping the names of all actions for this ModelAdmin to a tuple of (callable, name, description) for each action.
def get_actions(self, request): """ Return a dictionary mapping the names of all actions for this ModelAdmin to a tuple of (callable, name, description) for each action. """ # If self.actions is explicitly set to None that means that we don't # want *any* actions enabled on this page. from django.contrib.admin.views.main import _is_changelist_popup if self.actions is None or _is_changelist_popup(request): return SortedDict() actions = [] # Gather actions from the admin site first for (name, func) in self.admin_site.actions: description = getattr(func, 'short_description', name.replace('_', ' ')) actions.append((func, name, description)) # Then gather them from the model admin and all parent classes, # starting with self and working back up. for klass in self.__class__.mro()[::-1]: class_actions = getattr(klass, 'actions', []) # Avoid trying to iterate over None if not class_actions: continue actions.extend([self.get_action(action) for action in class_actions]) # get_action might have returned None, so filter any of those out. actions = filter(None, actions) # Convert the actions into a SortedDict keyed by name. actions = SortedDict([ (name, (func, name, desc)) for func, name, desc in actions ]) return actions
def get_changelist(
self, request, **kwargs)
Returns the ChangeList class for use on the changelist page.
def get_changelist(self, request, **kwargs): """ Returns the ChangeList class for use on the changelist page. """ from django.contrib.admin.views.main import ChangeList return ChangeList
def get_changelist_form(
self, request, **kwargs)
Returns a Form class for use in the Formset on the changelist page.
def get_changelist_form(self, request, **kwargs): """ Returns a Form class for use in the Formset on the changelist page. """ defaults = { "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) if (defaults.get('fields') is None and not modelform_defines_fields(defaults.get('form'))): defaults['fields'] = forms.ALL_FIELDS return modelform_factory(self.model, **defaults)
def get_changelist_formset(
self, request, **kwargs)
Returns a FormSet class for use on the changelist page if list_editable is used.
def get_changelist_formset(self, request, **kwargs): """ Returns a FormSet class for use on the changelist page if list_editable is used. """ defaults = { "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) return modelformset_factory(self.model, self.get_changelist_form(request), extra=0, fields=self.list_editable, **defaults)
def get_field_queryset(
self, db, db_field, request)
If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case).
def get_field_queryset(self, db, db_field, request): """ If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case). """ related_admin = self.admin_site._registry.get(db_field.rel.to, None) if related_admin is not None: ordering = related_admin.get_ordering(request) if ordering is not None and ordering != (): return db_field.rel.to._default_manager.using(db).order_by(*ordering).complex_filter(db_field.rel.limit_choices_to) return None
def get_fieldsets(
self, request, obj=None)
Hook for specifying fieldsets for the add form.
def get_fieldsets(self, request, obj=None): "Hook for specifying fieldsets for the add form." if self.declared_fieldsets: return self.declared_fieldsets form = self.get_form(request, obj, fields=None) fields = list(form.base_fields) + list(self.get_readonly_fields(request, obj)) return [(None, {'fields': fields})]
def get_form(
self, request, obj=None, **kwargs)
Returns a Form class for use in the admin add view. This is used by add_view and change_view.
def get_form(self, request, obj=None, **kwargs): """ Returns a Form class for use in the admin add view. This is used by add_view and change_view. """ if 'fields' in kwargs: fields = kwargs.pop('fields') else: fields = flatten_fieldsets(self.get_fieldsets(request, obj)) if self.exclude is None: exclude = [] else: exclude = list(self.exclude) exclude.extend(self.get_readonly_fields(request, obj)) if self.exclude is None and hasattr(self.form, '_meta') and self.form._meta.exclude: # Take the custom ModelForm's Meta.exclude into account only if the # ModelAdmin doesn't define its own. exclude.extend(self.form._meta.exclude) # if exclude is an empty list we pass None to be consistent with the # default on modelform_factory exclude = exclude or None defaults = { "form": self.form, "fields": fields, "exclude": exclude, "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) if defaults['fields'] is None and not modelform_defines_fields(defaults['form']): defaults['fields'] = forms.ALL_FIELDS try: return modelform_factory(self.model, **defaults) except FieldError as e: raise FieldError('%s. Check fields/fieldsets/exclude attributes of class %s.' % (e, self.__class__.__name__))
def get_formsets(
self, request, obj=None)
def get_formsets(self, request, obj=None): for inline in self.get_inline_instances(request, obj): yield inline.get_formset(request, obj)
def get_inline_instances(
self, request, obj=None)
def get_inline_instances(self, request, obj=None): inline_instances = [] for inline_class in self.inlines: inline = inline_class(self.model, self.admin_site) if request: if not (inline.has_add_permission(request) or inline.has_change_permission(request, obj) or inline.has_delete_permission(request, obj)): continue if not inline.has_add_permission(request): inline.max_num = 0 inline_instances.append(inline) return inline_instances
def get_list_display(
self, request)
Return a sequence containing the fields to be displayed on the changelist.
def get_list_display(self, request): """ Return a sequence containing the fields to be displayed on the changelist. """ return self.list_display
def get_list_display_links(
self, request, list_display)
Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display().
def get_list_display_links(self, request, list_display): """ Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display(). """ if self.list_display_links or not list_display: return self.list_display_links else: # Use only the first item in list_display as link return list(list_display)[:1]
def get_list_filter(
self, request)
Returns a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page.
def get_list_filter(self, request): """ Returns a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page. """ return self.list_filter
def get_model_perms(
self, request)
Returns a dict of all perms for this model. This dict has the keys
add
, change
, and delete
mapping to the True/False for each
of those actions.
def get_model_perms(self, request): """ Returns a dict of all perms for this model. This dict has the keys ``add``, ``change``, and ``delete`` mapping to the True/False for each of those actions. """ return { 'add': self.has_add_permission(request), 'change': self.has_change_permission(request), 'delete': self.has_delete_permission(request), }
def get_object(
self, request, object_id)
Returns an instance matching the primary key provided. None
is
returned if no match is found (or the object_id failed validation
against the primary key field).
def get_object(self, request, object_id): """ Returns an instance matching the primary key provided. ``None`` is returned if no match is found (or the object_id failed validation against the primary key field). """ queryset = self.get_queryset(request) model = queryset.model try: object_id = model._meta.pk.to_python(object_id) return queryset.get(pk=object_id) except (model.DoesNotExist, ValidationError, ValueError): return None
def get_ordering(
self, request)
Hook for specifying field ordering.
def get_ordering(self, request): """ Hook for specifying field ordering. """ return self.ordering or () # otherwise we might try to *None, which is bad ;)
def get_paginator(
self, request, queryset, per_page, orphans=0, allow_empty_first_page=True)
def get_paginator(self, request, queryset, per_page, orphans=0, allow_empty_first_page=True): return self.paginator(queryset, per_page, orphans, allow_empty_first_page)
def get_prepopulated_fields(
self, request, obj=None)
Hook for specifying custom prepopulated fields.
def get_prepopulated_fields(self, request, obj=None): """ Hook for specifying custom prepopulated fields. """ return self.prepopulated_fields
def get_preserved_filters(
self, request)
Returns the preserved filters querystring.
def get_preserved_filters(self, request): """ Returns the preserved filters querystring. """ match = request.resolver_match if self.preserve_filters and match: opts = self.model._meta current_url = '%s:%s' % (match.app_name, match.url_name) changelist_url = 'admin:%s_%s_changelist' % (opts.app_label, opts.model_name) if current_url == changelist_url: preserved_filters = request.GET.urlencode() else: preserved_filters = request.GET.get('_changelist_filters') if preserved_filters: return urlencode({'_changelist_filters': preserved_filters}) return ''
def get_queryset(
self, request)
Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view.
def get_queryset(self, request): """ Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view. """ qs = self.model._default_manager.get_queryset() # TODO: this should be handled by some parameter to the ChangeList. ordering = self.get_ordering(request) if ordering: qs = qs.order_by(*ordering) return qs
def get_readonly_fields(
self, request, obj=None)
Hook for specifying custom readonly fields.
def get_readonly_fields(self, request, obj=None): """ Hook for specifying custom readonly fields. """ return self.readonly_fields
def get_search_results(
self, request, queryset, search_term)
Returns a tuple containing a queryset to implement the search, and a boolean indicating if the results may contain duplicates.
def get_search_results(self, request, queryset, search_term): """ Returns a tuple containing a queryset to implement the search, and a boolean indicating if the results may contain duplicates. """ # Apply keyword searches. def construct_search(field_name): if field_name.startswith('^'): return "%s__istartswith" % field_name[1:] elif field_name.startswith('='): return "%s__iexact" % field_name[1:] elif field_name.startswith('@'): return "%s__search" % field_name[1:] else: return "%s__icontains" % field_name use_distinct = False if self.search_fields and search_term: orm_lookups = [construct_search(str(search_field)) for search_field in self.search_fields] for bit in search_term.split(): or_queries = [models.Q(**{orm_lookup: bit}) for orm_lookup in orm_lookups] queryset = queryset.filter(reduce(operator.or_, or_queries)) if not use_distinct: for search_spec in orm_lookups: if lookup_needs_distinct(self.opts, search_spec): use_distinct = True break return queryset, use_distinct
def get_urls(
self)
def get_urls(self): from django.conf.urls import patterns, url def wrap(view): def wrapper(*args, **kwargs): return self.admin_site.admin_view(view)(*args, **kwargs) return update_wrapper(wrapper, view) info = self.model._meta.app_label, self.model._meta.model_name urlpatterns = patterns('', url(r'^$', wrap(self.changelist_view), name='%s_%s_changelist' % info), url(r'^add/$', wrap(self.add_view), name='%s_%s_add' % info), url(r'^(.+)/history/$', wrap(self.history_view), name='%s_%s_history' % info), url(r'^(.+)/delete/$', wrap(self.delete_view), name='%s_%s_delete' % info), url(r'^(.+)/$', wrap(self.change_view), name='%s_%s_change' % info), ) return urlpatterns
def has_add_permission(
self, request)
Returns True if the given request has permission to add an object. Can be overridden by the user in subclasses.
def has_add_permission(self, request): """ Returns True if the given request has permission to add an object. Can be overridden by the user in subclasses. """ opts = self.opts codename = get_permission_codename('add', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_change_permission(
self, request, obj=None)
Returns True if the given request has permission to change the given
Django model instance, the default implementation doesn't examine the
obj
parameter.
Can be overridden by the user in subclasses. In such case it should
return True if the given request has permission to change the obj
model instance. If obj
is None, this should return True if the given
request has permission to change any object of the given type.
def has_change_permission(self, request, obj=None): """ Returns True if the given request has permission to change the given Django model instance, the default implementation doesn't examine the `obj` parameter. Can be overridden by the user in subclasses. In such case it should return True if the given request has permission to change the `obj` model instance. If `obj` is None, this should return True if the given request has permission to change *any* object of the given type. """ opts = self.opts codename = get_permission_codename('change', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_delete_permission(
self, request, obj=None)
Returns True if the given request has permission to change the given
Django model instance, the default implementation doesn't examine the
obj
parameter.
Can be overridden by the user in subclasses. In such case it should
return True if the given request has permission to delete the obj
model instance. If obj
is None, this should return True if the given
request has permission to delete any object of the given type.
def has_delete_permission(self, request, obj=None): """ Returns True if the given request has permission to change the given Django model instance, the default implementation doesn't examine the `obj` parameter. Can be overridden by the user in subclasses. In such case it should return True if the given request has permission to delete the `obj` model instance. If `obj` is None, this should return True if the given request has permission to delete *any* object of the given type. """ opts = self.opts codename = get_permission_codename('delete', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def history_view(
self, request, object_id, extra_context=None)
The 'history' admin view for this model.
def history_view(self, request, object_id, extra_context=None): "The 'history' admin view for this model." from django.contrib.admin.models import LogEntry # First check if the user can see this history. model = self.model obj = get_object_or_404(model, pk=unquote(object_id)) if not self.has_change_permission(request, obj): raise PermissionDenied # Then get the history for this object. opts = model._meta app_label = opts.app_label action_list = LogEntry.objects.filter( object_id=unquote(object_id), content_type__id__exact=ContentType.objects.get_for_model(model).id ).select_related().order_by('action_time') context = { 'title': _('Change history: %s') % force_text(obj), 'action_list': action_list, 'module_name': capfirst(force_text(opts.verbose_name_plural)), 'object': obj, 'app_label': app_label, 'opts': opts, 'preserved_filters': self.get_preserved_filters(request), } context.update(extra_context or {}) return TemplateResponse(request, self.object_history_template or [ "admin/%s/%s/object_history.html" % (app_label, opts.model_name), "admin/%s/object_history.html" % app_label, "admin/object_history.html" ], context, current_app=self.admin_site.name)
def log_addition(
self, request, object)
Log that an object has been successfully added.
The default implementation creates an admin LogEntry object.
def log_addition(self, request, object): """ Log that an object has been successfully added. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, ADDITION LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=ADDITION )
def log_change(
self, request, object, message)
Log that an object has been successfully changed.
The default implementation creates an admin LogEntry object.
def log_change(self, request, object, message): """ Log that an object has been successfully changed. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, CHANGE LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=CHANGE, change_message=message )
def log_deletion(
self, request, object, object_repr)
Log that an object will be deleted. Note that this method is called before the deletion.
The default implementation creates an admin LogEntry object.
def log_deletion(self, request, object, object_repr): """ Log that an object will be deleted. Note that this method is called before the deletion. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, DELETION LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(self.model).pk, object_id=object.pk, object_repr=object_repr, action_flag=DELETION )
def lookup_allowed(
self, lookup, value)
def lookup_allowed(self, lookup, value): model = self.model # Check FKey lookups that are allowed, so that popups produced by # ForeignKeyRawIdWidget, on the basis of ForeignKey.limit_choices_to, # are allowed to work. for l in model._meta.related_fkey_lookups: for k, v in widgets.url_params_from_lookup_dict(l).items(): if k == lookup and v == value: return True parts = lookup.split(LOOKUP_SEP) # Last term in lookup is a query term (__exact, __startswith etc) # This term can be ignored. if len(parts) > 1 and parts[-1] in QUERY_TERMS: parts.pop() # Special case -- foo__id__exact and foo__id queries are implied # if foo has been specifically included in the lookup list; so # drop __id if it is the last part. However, first we need to find # the pk attribute name. rel_name = None for part in parts[:-1]: try: field, _, _, _ = model._meta.get_field_by_name(part) except FieldDoesNotExist: # Lookups on non-existent fields are ok, since they're ignored # later. return True if hasattr(field, 'rel'): if field.rel is None: # This property or relation doesn't exist, but it's allowed # since it's ignored in ChangeList.get_filters(). return True model = field.rel.to rel_name = field.rel.get_related_field().name elif isinstance(field, RelatedObject): model = field.model rel_name = model._meta.pk.name else: rel_name = None if rel_name and len(parts) > 1 and parts[-1] == rel_name: parts.pop() if len(parts) == 1: return True clean_lookup = LOOKUP_SEP.join(parts) return clean_lookup in self.list_filter or clean_lookup == self.date_hierarchy
def message_user(
self, request, message, level=20, extra_tags='', fail_silently=False)
Send a message to the user. The default implementation posts a message using the django.contrib.messages backend.
Exposes almost the same API as messages.add_message(), but accepts the
positional arguments in a different order to maintain backwards
compatibility. For convenience, it accepts the level
argument as
a string rather than the usual level number.
def message_user(self, request, message, level=messages.INFO, extra_tags='', fail_silently=False): """ Send a message to the user. The default implementation posts a message using the django.contrib.messages backend. Exposes almost the same API as messages.add_message(), but accepts the positional arguments in a different order to maintain backwards compatibility. For convenience, it accepts the `level` argument as a string rather than the usual level number. """ if not isinstance(level, int): # attempt to get the level if passed a string try: level = getattr(messages.constants, level.upper()) except AttributeError: levels = messages.constants.DEFAULT_TAGS.values() levels_repr = ', '.join('`%s`' % l for l in levels) raise ValueError('Bad message level string: `%s`. ' 'Possible values are: %s' % (level, levels_repr)) messages.add_message(request, level, message, extra_tags=extra_tags, fail_silently=fail_silently)
def queryset(
*args, **kwargs)
def wrapped(*args, **kwargs): warnings.warn( "`%s.%s` is deprecated, use `%s` instead." % (self.class_name, self.old_method_name, self.new_method_name), self.deprecation_warning, 2) return f(*args, **kwargs)
def render_change_form(
self, request, context, add=False, change=False, form_url='', obj=None)
def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None): opts = self.model._meta app_label = opts.app_label preserved_filters = self.get_preserved_filters(request) form_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, form_url) context.update({ 'add': add, 'change': change, 'has_add_permission': self.has_add_permission(request), 'has_change_permission': self.has_change_permission(request, obj), 'has_delete_permission': self.has_delete_permission(request, obj), 'has_file_field': True, # FIXME - this should check if form or formsets have a FileField, 'has_absolute_url': hasattr(self.model, 'get_absolute_url'), 'form_url': form_url, 'opts': opts, 'content_type_id': ContentType.objects.get_for_model(self.model).id, 'save_as': self.save_as, 'save_on_top': self.save_on_top, }) if add and self.add_form_template is not None: form_template = self.add_form_template else: form_template = self.change_form_template return TemplateResponse(request, form_template or [ "admin/%s/%s/change_form.html" % (app_label, opts.model_name), "admin/%s/change_form.html" % app_label, "admin/change_form.html" ], context, current_app=self.admin_site.name)
def response_action(
self, request, queryset)
Handle an admin action. This is called if a request is POSTed to the changelist; it returns an HttpResponse if the action was handled, and None otherwise.
def response_action(self, request, queryset): """ Handle an admin action. This is called if a request is POSTed to the changelist; it returns an HttpResponse if the action was handled, and None otherwise. """ # There can be multiple action forms on the page (at the top # and bottom of the change list, for example). Get the action # whose button was pushed. try: action_index = int(request.POST.get('index', 0)) except ValueError: action_index = 0 # Construct the action form. data = request.POST.copy() data.pop(helpers.ACTION_CHECKBOX_NAME, None) data.pop("index", None) # Use the action whose button was pushed try: data.update({'action': data.getlist('action')[action_index]}) except IndexError: # If we didn't get an action from the chosen form that's invalid # POST data, so by deleting action it'll fail the validation check # below. So no need to do anything here pass action_form = self.action_form(data, auto_id=None) action_form.fields['action'].choices = self.get_action_choices(request) # If the form's valid we can handle the action. if action_form.is_valid(): action = action_form.cleaned_data['action'] select_across = action_form.cleaned_data['select_across'] func = self.get_actions(request)[action][0] # Get the list of selected PKs. If nothing's selected, we can't # perform an action on it, so bail. Except we want to perform # the action explicitly on all objects. selected = request.POST.getlist(helpers.ACTION_CHECKBOX_NAME) if not selected and not select_across: # Reminder that something needs to be selected or nothing will happen msg = _("Items must be selected in order to perform " "actions on them. No items have been changed.") self.message_user(request, msg, messages.WARNING) return None if not select_across: # Perform the action only on the selected objects queryset = queryset.filter(pk__in=selected) response = func(self, request, queryset) # Actions may return an HttpResponse-like object, which will be # used as the response from the POST. If not, we'll be a good # little HTTP citizen and redirect back to the changelist page. if isinstance(response, HttpResponseBase): return response else: return HttpResponseRedirect(request.get_full_path()) else: msg = _("No action selected.") self.message_user(request, msg, messages.WARNING) return None
def response_add(
self, request, obj, post_url_continue=None)
Determines the HttpResponse for the add_view stage.
def response_add(self, request, obj, post_url_continue=None): """ Determines the HttpResponse for the add_view stage. """ opts = obj._meta pk_value = obj._get_pk_val() preserved_filters = self.get_preserved_filters(request) msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)} # Here, we distinguish between different save types by checking for # the presence of keys in request.POST. if IS_POPUP_VAR in request.POST: return SimpleTemplateResponse('admin/popup_response.html', { 'pk_value': escape(pk_value), 'obj': escapejs(obj) }) elif "_continue" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) if post_url_continue is None: post_url_continue = reverse('admin:%s_%s_change' % (opts.app_label, opts.model_name), args=(pk_value,), current_app=self.admin_site.name) post_url_continue = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url_continue) return HttpResponseRedirect(post_url_continue) elif "_addanother" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may add another %(name)s below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = request.path redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) else: msg = _('The %(name)s "%(obj)s" was added successfully.') % msg_dict self.message_user(request, msg, messages.SUCCESS) return self.response_post_save_add(request, obj)
def response_change(
self, request, obj)
Determines the HttpResponse for the change_view stage.
def response_change(self, request, obj): """ Determines the HttpResponse for the change_view stage. """ opts = self.model._meta pk_value = obj._get_pk_val() preserved_filters = self.get_preserved_filters(request) msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)} if "_continue" in request.POST: msg = _('The %(name)s "%(obj)s" was changed successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = request.path redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) elif "_saveasnew" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = reverse('admin:%s_%s_change' % (opts.app_label, opts.model_name), args=(pk_value,), current_app=self.admin_site.name) redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) elif "_addanother" in request.POST: msg = _('The %(name)s "%(obj)s" was changed successfully. You may add another %(name)s below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = reverse('admin:%s_%s_add' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) else: msg = _('The %(name)s "%(obj)s" was changed successfully.') % msg_dict self.message_user(request, msg, messages.SUCCESS) return self.response_post_save_change(request, obj)
def response_post_save_add(
self, request, obj)
Figure out where to redirect after the 'Save' button has been pressed when adding a new object.
def response_post_save_add(self, request, obj): """ Figure out where to redirect after the 'Save' button has been pressed when adding a new object. """ opts = self.model._meta if self.has_change_permission(request, None): post_url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url) else: post_url = reverse('admin:index', current_app=self.admin_site.name) return HttpResponseRedirect(post_url)
def response_post_save_change(
self, request, obj)
Figure out where to redirect after the 'Save' button has been pressed when editing an existing object.
def response_post_save_change(self, request, obj): """ Figure out where to redirect after the 'Save' button has been pressed when editing an existing object. """ opts = self.model._meta if self.has_change_permission(request, None): post_url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url) else: post_url = reverse('admin:index', current_app=self.admin_site.name) return HttpResponseRedirect(post_url)
def save_form(
self, request, form, change)
Given a ModelForm return an unsaved instance. change
is True if
the object is being changed, and False if it's being added.
def save_form(self, request, form, change): """ Given a ModelForm return an unsaved instance. ``change`` is True if the object is being changed, and False if it's being added. """ return form.save(commit=False)
def save_formset(
self, request, form, formset, change)
Given an inline formset save it to the database.
def save_formset(self, request, form, formset, change): """ Given an inline formset save it to the database. """ formset.save()
def save_model(
self, request, obj, form, change)
Given a model instance save it to the database.
def save_model(self, request, obj, form, change): """ Given a model instance save it to the database. """ obj.save()
Given the HttpRequest
, the parent ModelForm
instance, the
list of inline formsets and a boolean value based on whether the
parent is being added or changed, save the related objects to the
database. Note that at this point save_form() and save_model() have
already been called.
def to_field_allowed(
self, request, to_field)
Returns True if the model associated with this admin should be allowed to be referenced by the specified field.
def to_field_allowed(self, request, to_field): """ Returns True if the model associated with this admin should be allowed to be referenced by the specified field. """ opts = self.model._meta try: field = opts.get_field(to_field) except FieldDoesNotExist: return False # Always allow referencing the primary key since it's already possible # to get this information from the change view URL. if field.primary_key: return True # Make sure at least one of the models registered for this site # references this field through a FK or a M2M relationship. registered_models = set() for model, admin in self.admin_site._registry.items(): registered_models.add(model) for inline in admin.inlines: registered_models.add(inline.model) for related_object in opts.get_all_related_objects(include_hidden=True): related_model = related_object.model if (any(issubclass(model, related_model) for model in registered_models) and related_object.field.rel.get_related_field() == field): return True return False
def validate(
cls, model)
@classmethod def validate(cls, model): validator = cls.validator_class() validator.validate(cls, model)
class LocationAliasAdmin
class LocationAliasAdmin(admin.ModelAdmin): search_fields = ['location__name', 'alias'] ordering = ['alias']
Ancestors (in MRO)
- LocationAliasAdmin
- django.contrib.admin.options.ModelAdmin
- django.contrib.admin.options.BaseModelAdmin
- __builtin__.object
Class variables
var action_form
var actions
var actions_on_bottom
var actions_on_top
var actions_selection_counter
var add_form_template
var change_form_template
var change_list_template
var date_hierarchy
var delete_confirmation_template
var delete_selected_confirmation_template
var exclude
var fields
var fieldsets
var filter_horizontal
var filter_vertical
var form
var formfield_overrides
var inlines
var list_display
var list_display_links
var list_editable
var list_filter
var list_max_show_all
var list_per_page
var object_history_template
var ordering
var paginator
var prepopulated_fields
var preserve_filters
var radio_fields
var raw_id_fields
var readonly_fields
var save_as
var save_on_top
var search_fields
var validator_class
Instance variables
var declared_fieldsets
var media
var urls
Methods
def __init__(
self, model, admin_site)
def __init__(self, model, admin_site): self.model = model self.opts = model._meta self.admin_site = admin_site super(ModelAdmin, self).__init__()
def action_checkbox(
self, obj)
A list_display column containing a checkbox widget.
def action_checkbox(self, obj): """ A list_display column containing a checkbox widget. """ return helpers.checkbox.render(helpers.ACTION_CHECKBOX_NAME, force_text(obj.pk))
def add_view(
self, *args, **kwargs)
The 'add' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def change_view(
self, *args, **kwargs)
The 'change' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def changelist_view(
self, *args, **kwargs)
The 'change list' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def construct_change_message(
self, request, form, formsets)
Construct a change message from a changed object.
def construct_change_message(self, request, form, formsets): """ Construct a change message from a changed object. """ change_message = [] if form.changed_data: change_message.append(_('Changed %s.') % get_text_list(form.changed_data, _('and'))) if formsets: for formset in formsets: for added_object in formset.new_objects: change_message.append(_('Added %(name)s "%(object)s".') % {'name': force_text(added_object._meta.verbose_name), 'object': force_text(added_object)}) for changed_object, changed_fields in formset.changed_objects: change_message.append(_('Changed %(list)s for %(name)s "%(object)s".') % {'list': get_text_list(changed_fields, _('and')), 'name': force_text(changed_object._meta.verbose_name), 'object': force_text(changed_object)}) for deleted_object in formset.deleted_objects: change_message.append(_('Deleted %(name)s "%(object)s".') % {'name': force_text(deleted_object._meta.verbose_name), 'object': force_text(deleted_object)}) change_message = ' '.join(change_message) return change_message or _('No fields changed.')
def delete_model(
self, request, obj)
Given a model instance delete it from the database.
def delete_model(self, request, obj): """ Given a model instance delete it from the database. """ obj.delete()
def delete_view(
self, *args, **kwargs)
The 'delete' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def formfield_for_choice_field(
self, db_field, request=None, **kwargs)
Get a form Field for a database Field that has declared choices.
def formfield_for_choice_field(self, db_field, request=None, **kwargs): """ Get a form Field for a database Field that has declared choices. """ # If the field is named as a radio_field, use a RadioSelect if db_field.name in self.radio_fields: # Avoid stomping on custom widget/choices arguments. if 'widget' not in kwargs: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) if 'choices' not in kwargs: kwargs['choices'] = db_field.get_choices( include_blank=db_field.blank, blank_choice=[('', _('None'))] ) return db_field.formfield(**kwargs)
def formfield_for_dbfield(
self, db_field, **kwargs)
Hook for specifying the form Field instance for a given database Field instance.
If kwargs are given, they're passed to the form Field's constructor.
def formfield_for_dbfield(self, db_field, **kwargs): """ Hook for specifying the form Field instance for a given database Field instance. If kwargs are given, they're passed to the form Field's constructor. """ request = kwargs.pop("request", None) # If the field specifies choices, we don't need to look for special # admin widgets - we just need to use a select widget of some kind. if db_field.choices: return self.formfield_for_choice_field(db_field, request, **kwargs) # ForeignKey or ManyToManyFields if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)): # Combine the field kwargs with any options for formfield_overrides. # Make sure the passed in **kwargs override anything in # formfield_overrides because **kwargs is more specific, and should # always win. if db_field.__class__ in self.formfield_overrides: kwargs = dict(self.formfield_overrides[db_field.__class__], **kwargs) # Get the correct formfield. if isinstance(db_field, models.ForeignKey): formfield = self.formfield_for_foreignkey(db_field, request, **kwargs) elif isinstance(db_field, models.ManyToManyField): formfield = self.formfield_for_manytomany(db_field, request, **kwargs) # For non-raw_id fields, wrap the widget with a wrapper that adds # extra HTML -- the "add other" interface -- to the end of the # rendered output. formfield can be None if it came from a # OneToOneField with parent_link=True or a M2M intermediary. if formfield and db_field.name not in self.raw_id_fields: related_modeladmin = self.admin_site._registry.get( db_field.rel.to) can_add_related = bool(related_modeladmin and related_modeladmin.has_add_permission(request)) formfield.widget = widgets.RelatedFieldWidgetWrapper( formfield.widget, db_field.rel, self.admin_site, can_add_related=can_add_related) return formfield # If we've got overrides for the formfield defined, use 'em. **kwargs # passed to formfield_for_dbfield override the defaults. for klass in db_field.__class__.mro(): if klass in self.formfield_overrides: kwargs = dict(copy.deepcopy(self.formfield_overrides[klass]), **kwargs) return db_field.formfield(**kwargs) # For any other type of field, just call its formfield() method. return db_field.formfield(**kwargs)
def formfield_for_foreignkey(
self, db_field, request=None, **kwargs)
Get a form Field for a ForeignKey.
def formfield_for_foreignkey(self, db_field, request=None, **kwargs): """ Get a form Field for a ForeignKey. """ db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel, self.admin_site, using=db) elif db_field.name in self.radio_fields: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) kwargs['empty_label'] = _('None') if db_field.blank else None if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def formfield_for_manytomany(
self, db_field, request=None, **kwargs)
Get a form Field for a ManyToManyField.
def formfield_for_manytomany(self, db_field, request=None, **kwargs): """ Get a form Field for a ManyToManyField. """ # If it uses an intermediary model that isn't auto created, don't show # a field in admin. if not db_field.rel.through._meta.auto_created: return None db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel, self.admin_site, using=db) kwargs['help_text'] = '' elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)): kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical)) if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def get_action(
self, action)
Return a given action from a parameter, which can either be a callable, or the name of a method on the ModelAdmin. Return is a tuple of (callable, name, description).
def get_action(self, action): """ Return a given action from a parameter, which can either be a callable, or the name of a method on the ModelAdmin. Return is a tuple of (callable, name, description). """ # If the action is a callable, just use it. if callable(action): func = action action = action.__name__ # Next, look for a method. Grab it off self.__class__ to get an unbound # method instead of a bound one; this ensures that the calling # conventions are the same for functions and methods. elif hasattr(self.__class__, action): func = getattr(self.__class__, action) # Finally, look for a named method on the admin site else: try: func = self.admin_site.get_action(action) except KeyError: return None if hasattr(func, 'short_description'): description = func.short_description else: description = capfirst(action.replace('_', ' ')) return func, action, description
def get_action_choices(
self, request, default_choices=[(u'', u'---------')])
Return a list of choices for use in a form object. Each choice is a tuple (name, description).
def get_action_choices(self, request, default_choices=BLANK_CHOICE_DASH): """ Return a list of choices for use in a form object. Each choice is a tuple (name, description). """ choices = [] + default_choices for func, name, description in six.itervalues(self.get_actions(request)): choice = (name, description % model_format_dict(self.opts)) choices.append(choice) return choices
def get_actions(
self, request)
Return a dictionary mapping the names of all actions for this ModelAdmin to a tuple of (callable, name, description) for each action.
def get_actions(self, request): """ Return a dictionary mapping the names of all actions for this ModelAdmin to a tuple of (callable, name, description) for each action. """ # If self.actions is explicitly set to None that means that we don't # want *any* actions enabled on this page. from django.contrib.admin.views.main import _is_changelist_popup if self.actions is None or _is_changelist_popup(request): return SortedDict() actions = [] # Gather actions from the admin site first for (name, func) in self.admin_site.actions: description = getattr(func, 'short_description', name.replace('_', ' ')) actions.append((func, name, description)) # Then gather them from the model admin and all parent classes, # starting with self and working back up. for klass in self.__class__.mro()[::-1]: class_actions = getattr(klass, 'actions', []) # Avoid trying to iterate over None if not class_actions: continue actions.extend([self.get_action(action) for action in class_actions]) # get_action might have returned None, so filter any of those out. actions = filter(None, actions) # Convert the actions into a SortedDict keyed by name. actions = SortedDict([ (name, (func, name, desc)) for func, name, desc in actions ]) return actions
def get_changelist(
self, request, **kwargs)
Returns the ChangeList class for use on the changelist page.
def get_changelist(self, request, **kwargs): """ Returns the ChangeList class for use on the changelist page. """ from django.contrib.admin.views.main import ChangeList return ChangeList
def get_changelist_form(
self, request, **kwargs)
Returns a Form class for use in the Formset on the changelist page.
def get_changelist_form(self, request, **kwargs): """ Returns a Form class for use in the Formset on the changelist page. """ defaults = { "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) if (defaults.get('fields') is None and not modelform_defines_fields(defaults.get('form'))): defaults['fields'] = forms.ALL_FIELDS return modelform_factory(self.model, **defaults)
def get_changelist_formset(
self, request, **kwargs)
Returns a FormSet class for use on the changelist page if list_editable is used.
def get_changelist_formset(self, request, **kwargs): """ Returns a FormSet class for use on the changelist page if list_editable is used. """ defaults = { "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) return modelformset_factory(self.model, self.get_changelist_form(request), extra=0, fields=self.list_editable, **defaults)
def get_field_queryset(
self, db, db_field, request)
If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case).
def get_field_queryset(self, db, db_field, request): """ If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case). """ related_admin = self.admin_site._registry.get(db_field.rel.to, None) if related_admin is not None: ordering = related_admin.get_ordering(request) if ordering is not None and ordering != (): return db_field.rel.to._default_manager.using(db).order_by(*ordering).complex_filter(db_field.rel.limit_choices_to) return None
def get_fieldsets(
self, request, obj=None)
Hook for specifying fieldsets for the add form.
def get_fieldsets(self, request, obj=None): "Hook for specifying fieldsets for the add form." if self.declared_fieldsets: return self.declared_fieldsets form = self.get_form(request, obj, fields=None) fields = list(form.base_fields) + list(self.get_readonly_fields(request, obj)) return [(None, {'fields': fields})]
def get_form(
self, request, obj=None, **kwargs)
Returns a Form class for use in the admin add view. This is used by add_view and change_view.
def get_form(self, request, obj=None, **kwargs): """ Returns a Form class for use in the admin add view. This is used by add_view and change_view. """ if 'fields' in kwargs: fields = kwargs.pop('fields') else: fields = flatten_fieldsets(self.get_fieldsets(request, obj)) if self.exclude is None: exclude = [] else: exclude = list(self.exclude) exclude.extend(self.get_readonly_fields(request, obj)) if self.exclude is None and hasattr(self.form, '_meta') and self.form._meta.exclude: # Take the custom ModelForm's Meta.exclude into account only if the # ModelAdmin doesn't define its own. exclude.extend(self.form._meta.exclude) # if exclude is an empty list we pass None to be consistent with the # default on modelform_factory exclude = exclude or None defaults = { "form": self.form, "fields": fields, "exclude": exclude, "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) if defaults['fields'] is None and not modelform_defines_fields(defaults['form']): defaults['fields'] = forms.ALL_FIELDS try: return modelform_factory(self.model, **defaults) except FieldError as e: raise FieldError('%s. Check fields/fieldsets/exclude attributes of class %s.' % (e, self.__class__.__name__))
def get_formsets(
self, request, obj=None)
def get_formsets(self, request, obj=None): for inline in self.get_inline_instances(request, obj): yield inline.get_formset(request, obj)
def get_inline_instances(
self, request, obj=None)
def get_inline_instances(self, request, obj=None): inline_instances = [] for inline_class in self.inlines: inline = inline_class(self.model, self.admin_site) if request: if not (inline.has_add_permission(request) or inline.has_change_permission(request, obj) or inline.has_delete_permission(request, obj)): continue if not inline.has_add_permission(request): inline.max_num = 0 inline_instances.append(inline) return inline_instances
def get_list_display(
self, request)
Return a sequence containing the fields to be displayed on the changelist.
def get_list_display(self, request): """ Return a sequence containing the fields to be displayed on the changelist. """ return self.list_display
def get_list_display_links(
self, request, list_display)
Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display().
def get_list_display_links(self, request, list_display): """ Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display(). """ if self.list_display_links or not list_display: return self.list_display_links else: # Use only the first item in list_display as link return list(list_display)[:1]
def get_list_filter(
self, request)
Returns a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page.
def get_list_filter(self, request): """ Returns a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page. """ return self.list_filter
def get_model_perms(
self, request)
Returns a dict of all perms for this model. This dict has the keys
add
, change
, and delete
mapping to the True/False for each
of those actions.
def get_model_perms(self, request): """ Returns a dict of all perms for this model. This dict has the keys ``add``, ``change``, and ``delete`` mapping to the True/False for each of those actions. """ return { 'add': self.has_add_permission(request), 'change': self.has_change_permission(request), 'delete': self.has_delete_permission(request), }
def get_object(
self, request, object_id)
Returns an instance matching the primary key provided. None
is
returned if no match is found (or the object_id failed validation
against the primary key field).
def get_object(self, request, object_id): """ Returns an instance matching the primary key provided. ``None`` is returned if no match is found (or the object_id failed validation against the primary key field). """ queryset = self.get_queryset(request) model = queryset.model try: object_id = model._meta.pk.to_python(object_id) return queryset.get(pk=object_id) except (model.DoesNotExist, ValidationError, ValueError): return None
def get_ordering(
self, request)
Hook for specifying field ordering.
def get_ordering(self, request): """ Hook for specifying field ordering. """ return self.ordering or () # otherwise we might try to *None, which is bad ;)
def get_paginator(
self, request, queryset, per_page, orphans=0, allow_empty_first_page=True)
def get_paginator(self, request, queryset, per_page, orphans=0, allow_empty_first_page=True): return self.paginator(queryset, per_page, orphans, allow_empty_first_page)
def get_prepopulated_fields(
self, request, obj=None)
Hook for specifying custom prepopulated fields.
def get_prepopulated_fields(self, request, obj=None): """ Hook for specifying custom prepopulated fields. """ return self.prepopulated_fields
def get_preserved_filters(
self, request)
Returns the preserved filters querystring.
def get_preserved_filters(self, request): """ Returns the preserved filters querystring. """ match = request.resolver_match if self.preserve_filters and match: opts = self.model._meta current_url = '%s:%s' % (match.app_name, match.url_name) changelist_url = 'admin:%s_%s_changelist' % (opts.app_label, opts.model_name) if current_url == changelist_url: preserved_filters = request.GET.urlencode() else: preserved_filters = request.GET.get('_changelist_filters') if preserved_filters: return urlencode({'_changelist_filters': preserved_filters}) return ''
def get_queryset(
self, request)
Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view.
def get_queryset(self, request): """ Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view. """ qs = self.model._default_manager.get_queryset() # TODO: this should be handled by some parameter to the ChangeList. ordering = self.get_ordering(request) if ordering: qs = qs.order_by(*ordering) return qs
def get_readonly_fields(
self, request, obj=None)
Hook for specifying custom readonly fields.
def get_readonly_fields(self, request, obj=None): """ Hook for specifying custom readonly fields. """ return self.readonly_fields
def get_search_results(
self, request, queryset, search_term)
Returns a tuple containing a queryset to implement the search, and a boolean indicating if the results may contain duplicates.
def get_search_results(self, request, queryset, search_term): """ Returns a tuple containing a queryset to implement the search, and a boolean indicating if the results may contain duplicates. """ # Apply keyword searches. def construct_search(field_name): if field_name.startswith('^'): return "%s__istartswith" % field_name[1:] elif field_name.startswith('='): return "%s__iexact" % field_name[1:] elif field_name.startswith('@'): return "%s__search" % field_name[1:] else: return "%s__icontains" % field_name use_distinct = False if self.search_fields and search_term: orm_lookups = [construct_search(str(search_field)) for search_field in self.search_fields] for bit in search_term.split(): or_queries = [models.Q(**{orm_lookup: bit}) for orm_lookup in orm_lookups] queryset = queryset.filter(reduce(operator.or_, or_queries)) if not use_distinct: for search_spec in orm_lookups: if lookup_needs_distinct(self.opts, search_spec): use_distinct = True break return queryset, use_distinct
def get_urls(
self)
def get_urls(self): from django.conf.urls import patterns, url def wrap(view): def wrapper(*args, **kwargs): return self.admin_site.admin_view(view)(*args, **kwargs) return update_wrapper(wrapper, view) info = self.model._meta.app_label, self.model._meta.model_name urlpatterns = patterns('', url(r'^$', wrap(self.changelist_view), name='%s_%s_changelist' % info), url(r'^add/$', wrap(self.add_view), name='%s_%s_add' % info), url(r'^(.+)/history/$', wrap(self.history_view), name='%s_%s_history' % info), url(r'^(.+)/delete/$', wrap(self.delete_view), name='%s_%s_delete' % info), url(r'^(.+)/$', wrap(self.change_view), name='%s_%s_change' % info), ) return urlpatterns
def has_add_permission(
self, request)
Returns True if the given request has permission to add an object. Can be overridden by the user in subclasses.
def has_add_permission(self, request): """ Returns True if the given request has permission to add an object. Can be overridden by the user in subclasses. """ opts = self.opts codename = get_permission_codename('add', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_change_permission(
self, request, obj=None)
Returns True if the given request has permission to change the given
Django model instance, the default implementation doesn't examine the
obj
parameter.
Can be overridden by the user in subclasses. In such case it should
return True if the given request has permission to change the obj
model instance. If obj
is None, this should return True if the given
request has permission to change any object of the given type.
def has_change_permission(self, request, obj=None): """ Returns True if the given request has permission to change the given Django model instance, the default implementation doesn't examine the `obj` parameter. Can be overridden by the user in subclasses. In such case it should return True if the given request has permission to change the `obj` model instance. If `obj` is None, this should return True if the given request has permission to change *any* object of the given type. """ opts = self.opts codename = get_permission_codename('change', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_delete_permission(
self, request, obj=None)
Returns True if the given request has permission to change the given
Django model instance, the default implementation doesn't examine the
obj
parameter.
Can be overridden by the user in subclasses. In such case it should
return True if the given request has permission to delete the obj
model instance. If obj
is None, this should return True if the given
request has permission to delete any object of the given type.
def has_delete_permission(self, request, obj=None): """ Returns True if the given request has permission to change the given Django model instance, the default implementation doesn't examine the `obj` parameter. Can be overridden by the user in subclasses. In such case it should return True if the given request has permission to delete the `obj` model instance. If `obj` is None, this should return True if the given request has permission to delete *any* object of the given type. """ opts = self.opts codename = get_permission_codename('delete', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def history_view(
self, request, object_id, extra_context=None)
The 'history' admin view for this model.
def history_view(self, request, object_id, extra_context=None): "The 'history' admin view for this model." from django.contrib.admin.models import LogEntry # First check if the user can see this history. model = self.model obj = get_object_or_404(model, pk=unquote(object_id)) if not self.has_change_permission(request, obj): raise PermissionDenied # Then get the history for this object. opts = model._meta app_label = opts.app_label action_list = LogEntry.objects.filter( object_id=unquote(object_id), content_type__id__exact=ContentType.objects.get_for_model(model).id ).select_related().order_by('action_time') context = { 'title': _('Change history: %s') % force_text(obj), 'action_list': action_list, 'module_name': capfirst(force_text(opts.verbose_name_plural)), 'object': obj, 'app_label': app_label, 'opts': opts, 'preserved_filters': self.get_preserved_filters(request), } context.update(extra_context or {}) return TemplateResponse(request, self.object_history_template or [ "admin/%s/%s/object_history.html" % (app_label, opts.model_name), "admin/%s/object_history.html" % app_label, "admin/object_history.html" ], context, current_app=self.admin_site.name)
def log_addition(
self, request, object)
Log that an object has been successfully added.
The default implementation creates an admin LogEntry object.
def log_addition(self, request, object): """ Log that an object has been successfully added. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, ADDITION LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=ADDITION )
def log_change(
self, request, object, message)
Log that an object has been successfully changed.
The default implementation creates an admin LogEntry object.
def log_change(self, request, object, message): """ Log that an object has been successfully changed. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, CHANGE LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=CHANGE, change_message=message )
def log_deletion(
self, request, object, object_repr)
Log that an object will be deleted. Note that this method is called before the deletion.
The default implementation creates an admin LogEntry object.
def log_deletion(self, request, object, object_repr): """ Log that an object will be deleted. Note that this method is called before the deletion. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, DELETION LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(self.model).pk, object_id=object.pk, object_repr=object_repr, action_flag=DELETION )
def lookup_allowed(
self, lookup, value)
def lookup_allowed(self, lookup, value): model = self.model # Check FKey lookups that are allowed, so that popups produced by # ForeignKeyRawIdWidget, on the basis of ForeignKey.limit_choices_to, # are allowed to work. for l in model._meta.related_fkey_lookups: for k, v in widgets.url_params_from_lookup_dict(l).items(): if k == lookup and v == value: return True parts = lookup.split(LOOKUP_SEP) # Last term in lookup is a query term (__exact, __startswith etc) # This term can be ignored. if len(parts) > 1 and parts[-1] in QUERY_TERMS: parts.pop() # Special case -- foo__id__exact and foo__id queries are implied # if foo has been specifically included in the lookup list; so # drop __id if it is the last part. However, first we need to find # the pk attribute name. rel_name = None for part in parts[:-1]: try: field, _, _, _ = model._meta.get_field_by_name(part) except FieldDoesNotExist: # Lookups on non-existent fields are ok, since they're ignored # later. return True if hasattr(field, 'rel'): if field.rel is None: # This property or relation doesn't exist, but it's allowed # since it's ignored in ChangeList.get_filters(). return True model = field.rel.to rel_name = field.rel.get_related_field().name elif isinstance(field, RelatedObject): model = field.model rel_name = model._meta.pk.name else: rel_name = None if rel_name and len(parts) > 1 and parts[-1] == rel_name: parts.pop() if len(parts) == 1: return True clean_lookup = LOOKUP_SEP.join(parts) return clean_lookup in self.list_filter or clean_lookup == self.date_hierarchy
def message_user(
self, request, message, level=20, extra_tags='', fail_silently=False)
Send a message to the user. The default implementation posts a message using the django.contrib.messages backend.
Exposes almost the same API as messages.add_message(), but accepts the
positional arguments in a different order to maintain backwards
compatibility. For convenience, it accepts the level
argument as
a string rather than the usual level number.
def message_user(self, request, message, level=messages.INFO, extra_tags='', fail_silently=False): """ Send a message to the user. The default implementation posts a message using the django.contrib.messages backend. Exposes almost the same API as messages.add_message(), but accepts the positional arguments in a different order to maintain backwards compatibility. For convenience, it accepts the `level` argument as a string rather than the usual level number. """ if not isinstance(level, int): # attempt to get the level if passed a string try: level = getattr(messages.constants, level.upper()) except AttributeError: levels = messages.constants.DEFAULT_TAGS.values() levels_repr = ', '.join('`%s`' % l for l in levels) raise ValueError('Bad message level string: `%s`. ' 'Possible values are: %s' % (level, levels_repr)) messages.add_message(request, level, message, extra_tags=extra_tags, fail_silently=fail_silently)
def queryset(
*args, **kwargs)
def wrapped(*args, **kwargs): warnings.warn( "`%s.%s` is deprecated, use `%s` instead." % (self.class_name, self.old_method_name, self.new_method_name), self.deprecation_warning, 2) return f(*args, **kwargs)
def render_change_form(
self, request, context, add=False, change=False, form_url='', obj=None)
def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None): opts = self.model._meta app_label = opts.app_label preserved_filters = self.get_preserved_filters(request) form_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, form_url) context.update({ 'add': add, 'change': change, 'has_add_permission': self.has_add_permission(request), 'has_change_permission': self.has_change_permission(request, obj), 'has_delete_permission': self.has_delete_permission(request, obj), 'has_file_field': True, # FIXME - this should check if form or formsets have a FileField, 'has_absolute_url': hasattr(self.model, 'get_absolute_url'), 'form_url': form_url, 'opts': opts, 'content_type_id': ContentType.objects.get_for_model(self.model).id, 'save_as': self.save_as, 'save_on_top': self.save_on_top, }) if add and self.add_form_template is not None: form_template = self.add_form_template else: form_template = self.change_form_template return TemplateResponse(request, form_template or [ "admin/%s/%s/change_form.html" % (app_label, opts.model_name), "admin/%s/change_form.html" % app_label, "admin/change_form.html" ], context, current_app=self.admin_site.name)
def response_action(
self, request, queryset)
Handle an admin action. This is called if a request is POSTed to the changelist; it returns an HttpResponse if the action was handled, and None otherwise.
def response_action(self, request, queryset): """ Handle an admin action. This is called if a request is POSTed to the changelist; it returns an HttpResponse if the action was handled, and None otherwise. """ # There can be multiple action forms on the page (at the top # and bottom of the change list, for example). Get the action # whose button was pushed. try: action_index = int(request.POST.get('index', 0)) except ValueError: action_index = 0 # Construct the action form. data = request.POST.copy() data.pop(helpers.ACTION_CHECKBOX_NAME, None) data.pop("index", None) # Use the action whose button was pushed try: data.update({'action': data.getlist('action')[action_index]}) except IndexError: # If we didn't get an action from the chosen form that's invalid # POST data, so by deleting action it'll fail the validation check # below. So no need to do anything here pass action_form = self.action_form(data, auto_id=None) action_form.fields['action'].choices = self.get_action_choices(request) # If the form's valid we can handle the action. if action_form.is_valid(): action = action_form.cleaned_data['action'] select_across = action_form.cleaned_data['select_across'] func = self.get_actions(request)[action][0] # Get the list of selected PKs. If nothing's selected, we can't # perform an action on it, so bail. Except we want to perform # the action explicitly on all objects. selected = request.POST.getlist(helpers.ACTION_CHECKBOX_NAME) if not selected and not select_across: # Reminder that something needs to be selected or nothing will happen msg = _("Items must be selected in order to perform " "actions on them. No items have been changed.") self.message_user(request, msg, messages.WARNING) return None if not select_across: # Perform the action only on the selected objects queryset = queryset.filter(pk__in=selected) response = func(self, request, queryset) # Actions may return an HttpResponse-like object, which will be # used as the response from the POST. If not, we'll be a good # little HTTP citizen and redirect back to the changelist page. if isinstance(response, HttpResponseBase): return response else: return HttpResponseRedirect(request.get_full_path()) else: msg = _("No action selected.") self.message_user(request, msg, messages.WARNING) return None
def response_add(
self, request, obj, post_url_continue=None)
Determines the HttpResponse for the add_view stage.
def response_add(self, request, obj, post_url_continue=None): """ Determines the HttpResponse for the add_view stage. """ opts = obj._meta pk_value = obj._get_pk_val() preserved_filters = self.get_preserved_filters(request) msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)} # Here, we distinguish between different save types by checking for # the presence of keys in request.POST. if IS_POPUP_VAR in request.POST: return SimpleTemplateResponse('admin/popup_response.html', { 'pk_value': escape(pk_value), 'obj': escapejs(obj) }) elif "_continue" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) if post_url_continue is None: post_url_continue = reverse('admin:%s_%s_change' % (opts.app_label, opts.model_name), args=(pk_value,), current_app=self.admin_site.name) post_url_continue = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url_continue) return HttpResponseRedirect(post_url_continue) elif "_addanother" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may add another %(name)s below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = request.path redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) else: msg = _('The %(name)s "%(obj)s" was added successfully.') % msg_dict self.message_user(request, msg, messages.SUCCESS) return self.response_post_save_add(request, obj)
def response_change(
self, request, obj)
Determines the HttpResponse for the change_view stage.
def response_change(self, request, obj): """ Determines the HttpResponse for the change_view stage. """ opts = self.model._meta pk_value = obj._get_pk_val() preserved_filters = self.get_preserved_filters(request) msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)} if "_continue" in request.POST: msg = _('The %(name)s "%(obj)s" was changed successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = request.path redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) elif "_saveasnew" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = reverse('admin:%s_%s_change' % (opts.app_label, opts.model_name), args=(pk_value,), current_app=self.admin_site.name) redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) elif "_addanother" in request.POST: msg = _('The %(name)s "%(obj)s" was changed successfully. You may add another %(name)s below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = reverse('admin:%s_%s_add' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) else: msg = _('The %(name)s "%(obj)s" was changed successfully.') % msg_dict self.message_user(request, msg, messages.SUCCESS) return self.response_post_save_change(request, obj)
def response_post_save_add(
self, request, obj)
Figure out where to redirect after the 'Save' button has been pressed when adding a new object.
def response_post_save_add(self, request, obj): """ Figure out where to redirect after the 'Save' button has been pressed when adding a new object. """ opts = self.model._meta if self.has_change_permission(request, None): post_url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url) else: post_url = reverse('admin:index', current_app=self.admin_site.name) return HttpResponseRedirect(post_url)
def response_post_save_change(
self, request, obj)
Figure out where to redirect after the 'Save' button has been pressed when editing an existing object.
def response_post_save_change(self, request, obj): """ Figure out where to redirect after the 'Save' button has been pressed when editing an existing object. """ opts = self.model._meta if self.has_change_permission(request, None): post_url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url) else: post_url = reverse('admin:index', current_app=self.admin_site.name) return HttpResponseRedirect(post_url)
def save_form(
self, request, form, change)
Given a ModelForm return an unsaved instance. change
is True if
the object is being changed, and False if it's being added.
def save_form(self, request, form, change): """ Given a ModelForm return an unsaved instance. ``change`` is True if the object is being changed, and False if it's being added. """ return form.save(commit=False)
def save_formset(
self, request, form, formset, change)
Given an inline formset save it to the database.
def save_formset(self, request, form, formset, change): """ Given an inline formset save it to the database. """ formset.save()
def save_model(
self, request, obj, form, change)
Given a model instance save it to the database.
def save_model(self, request, obj, form, change): """ Given a model instance save it to the database. """ obj.save()
Given the HttpRequest
, the parent ModelForm
instance, the
list of inline formsets and a boolean value based on whether the
parent is being added or changed, save the related objects to the
database. Note that at this point save_form() and save_model() have
already been called.
def to_field_allowed(
self, request, to_field)
Returns True if the model associated with this admin should be allowed to be referenced by the specified field.
def to_field_allowed(self, request, to_field): """ Returns True if the model associated with this admin should be allowed to be referenced by the specified field. """ opts = self.model._meta try: field = opts.get_field(to_field) except FieldDoesNotExist: return False # Always allow referencing the primary key since it's already possible # to get this information from the change view URL. if field.primary_key: return True # Make sure at least one of the models registered for this site # references this field through a FK or a M2M relationship. registered_models = set() for model, admin in self.admin_site._registry.items(): registered_models.add(model) for inline in admin.inlines: registered_models.add(inline.model) for related_object in opts.get_all_related_objects(include_hidden=True): related_model = related_object.model if (any(issubclass(model, related_model) for model in registered_models) and related_object.field.rel.get_related_field() == field): return True return False
def validate(
cls, model)
@classmethod def validate(cls, model): validator = cls.validator_class() validator.validate(cls, model)
class LocationRelationAdmin
class LocationRelationAdmin(admin.ModelAdmin): search_fields = ['location__name', 'ancestor_location__name'] ordering = ['ancestor_location__name']
Ancestors (in MRO)
- LocationRelationAdmin
- django.contrib.admin.options.ModelAdmin
- django.contrib.admin.options.BaseModelAdmin
- __builtin__.object
Class variables
var action_form
var actions
var actions_on_bottom
var actions_on_top
var actions_selection_counter
var add_form_template
var change_form_template
var change_list_template
var date_hierarchy
var delete_confirmation_template
var delete_selected_confirmation_template
var exclude
var fields
var fieldsets
var filter_horizontal
var filter_vertical
var form
var formfield_overrides
var inlines
var list_display
var list_display_links
var list_editable
var list_filter
var list_max_show_all
var list_per_page
var object_history_template
var ordering
var paginator
var prepopulated_fields
var preserve_filters
var radio_fields
var raw_id_fields
var readonly_fields
var save_as
var save_on_top
var search_fields
var validator_class
Instance variables
var declared_fieldsets
var media
var urls
Methods
def __init__(
self, model, admin_site)
def __init__(self, model, admin_site): self.model = model self.opts = model._meta self.admin_site = admin_site super(ModelAdmin, self).__init__()
def action_checkbox(
self, obj)
A list_display column containing a checkbox widget.
def action_checkbox(self, obj): """ A list_display column containing a checkbox widget. """ return helpers.checkbox.render(helpers.ACTION_CHECKBOX_NAME, force_text(obj.pk))
def add_view(
self, *args, **kwargs)
The 'add' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def change_view(
self, *args, **kwargs)
The 'change' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def changelist_view(
self, *args, **kwargs)
The 'change list' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def construct_change_message(
self, request, form, formsets)
Construct a change message from a changed object.
def construct_change_message(self, request, form, formsets): """ Construct a change message from a changed object. """ change_message = [] if form.changed_data: change_message.append(_('Changed %s.') % get_text_list(form.changed_data, _('and'))) if formsets: for formset in formsets: for added_object in formset.new_objects: change_message.append(_('Added %(name)s "%(object)s".') % {'name': force_text(added_object._meta.verbose_name), 'object': force_text(added_object)}) for changed_object, changed_fields in formset.changed_objects: change_message.append(_('Changed %(list)s for %(name)s "%(object)s".') % {'list': get_text_list(changed_fields, _('and')), 'name': force_text(changed_object._meta.verbose_name), 'object': force_text(changed_object)}) for deleted_object in formset.deleted_objects: change_message.append(_('Deleted %(name)s "%(object)s".') % {'name': force_text(deleted_object._meta.verbose_name), 'object': force_text(deleted_object)}) change_message = ' '.join(change_message) return change_message or _('No fields changed.')
def delete_model(
self, request, obj)
Given a model instance delete it from the database.
def delete_model(self, request, obj): """ Given a model instance delete it from the database. """ obj.delete()
def delete_view(
self, *args, **kwargs)
The 'delete' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def formfield_for_choice_field(
self, db_field, request=None, **kwargs)
Get a form Field for a database Field that has declared choices.
def formfield_for_choice_field(self, db_field, request=None, **kwargs): """ Get a form Field for a database Field that has declared choices. """ # If the field is named as a radio_field, use a RadioSelect if db_field.name in self.radio_fields: # Avoid stomping on custom widget/choices arguments. if 'widget' not in kwargs: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) if 'choices' not in kwargs: kwargs['choices'] = db_field.get_choices( include_blank=db_field.blank, blank_choice=[('', _('None'))] ) return db_field.formfield(**kwargs)
def formfield_for_dbfield(
self, db_field, **kwargs)
Hook for specifying the form Field instance for a given database Field instance.
If kwargs are given, they're passed to the form Field's constructor.
def formfield_for_dbfield(self, db_field, **kwargs): """ Hook for specifying the form Field instance for a given database Field instance. If kwargs are given, they're passed to the form Field's constructor. """ request = kwargs.pop("request", None) # If the field specifies choices, we don't need to look for special # admin widgets - we just need to use a select widget of some kind. if db_field.choices: return self.formfield_for_choice_field(db_field, request, **kwargs) # ForeignKey or ManyToManyFields if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)): # Combine the field kwargs with any options for formfield_overrides. # Make sure the passed in **kwargs override anything in # formfield_overrides because **kwargs is more specific, and should # always win. if db_field.__class__ in self.formfield_overrides: kwargs = dict(self.formfield_overrides[db_field.__class__], **kwargs) # Get the correct formfield. if isinstance(db_field, models.ForeignKey): formfield = self.formfield_for_foreignkey(db_field, request, **kwargs) elif isinstance(db_field, models.ManyToManyField): formfield = self.formfield_for_manytomany(db_field, request, **kwargs) # For non-raw_id fields, wrap the widget with a wrapper that adds # extra HTML -- the "add other" interface -- to the end of the # rendered output. formfield can be None if it came from a # OneToOneField with parent_link=True or a M2M intermediary. if formfield and db_field.name not in self.raw_id_fields: related_modeladmin = self.admin_site._registry.get( db_field.rel.to) can_add_related = bool(related_modeladmin and related_modeladmin.has_add_permission(request)) formfield.widget = widgets.RelatedFieldWidgetWrapper( formfield.widget, db_field.rel, self.admin_site, can_add_related=can_add_related) return formfield # If we've got overrides for the formfield defined, use 'em. **kwargs # passed to formfield_for_dbfield override the defaults. for klass in db_field.__class__.mro(): if klass in self.formfield_overrides: kwargs = dict(copy.deepcopy(self.formfield_overrides[klass]), **kwargs) return db_field.formfield(**kwargs) # For any other type of field, just call its formfield() method. return db_field.formfield(**kwargs)
def formfield_for_foreignkey(
self, db_field, request=None, **kwargs)
Get a form Field for a ForeignKey.
def formfield_for_foreignkey(self, db_field, request=None, **kwargs): """ Get a form Field for a ForeignKey. """ db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel, self.admin_site, using=db) elif db_field.name in self.radio_fields: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) kwargs['empty_label'] = _('None') if db_field.blank else None if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def formfield_for_manytomany(
self, db_field, request=None, **kwargs)
Get a form Field for a ManyToManyField.
def formfield_for_manytomany(self, db_field, request=None, **kwargs): """ Get a form Field for a ManyToManyField. """ # If it uses an intermediary model that isn't auto created, don't show # a field in admin. if not db_field.rel.through._meta.auto_created: return None db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel, self.admin_site, using=db) kwargs['help_text'] = '' elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)): kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical)) if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def get_action(
self, action)
Return a given action from a parameter, which can either be a callable, or the name of a method on the ModelAdmin. Return is a tuple of (callable, name, description).
def get_action(self, action): """ Return a given action from a parameter, which can either be a callable, or the name of a method on the ModelAdmin. Return is a tuple of (callable, name, description). """ # If the action is a callable, just use it. if callable(action): func = action action = action.__name__ # Next, look for a method. Grab it off self.__class__ to get an unbound # method instead of a bound one; this ensures that the calling # conventions are the same for functions and methods. elif hasattr(self.__class__, action): func = getattr(self.__class__, action) # Finally, look for a named method on the admin site else: try: func = self.admin_site.get_action(action) except KeyError: return None if hasattr(func, 'short_description'): description = func.short_description else: description = capfirst(action.replace('_', ' ')) return func, action, description
def get_action_choices(
self, request, default_choices=[(u'', u'---------')])
Return a list of choices for use in a form object. Each choice is a tuple (name, description).
def get_action_choices(self, request, default_choices=BLANK_CHOICE_DASH): """ Return a list of choices for use in a form object. Each choice is a tuple (name, description). """ choices = [] + default_choices for func, name, description in six.itervalues(self.get_actions(request)): choice = (name, description % model_format_dict(self.opts)) choices.append(choice) return choices
def get_actions(
self, request)
Return a dictionary mapping the names of all actions for this ModelAdmin to a tuple of (callable, name, description) for each action.
def get_actions(self, request): """ Return a dictionary mapping the names of all actions for this ModelAdmin to a tuple of (callable, name, description) for each action. """ # If self.actions is explicitly set to None that means that we don't # want *any* actions enabled on this page. from django.contrib.admin.views.main import _is_changelist_popup if self.actions is None or _is_changelist_popup(request): return SortedDict() actions = [] # Gather actions from the admin site first for (name, func) in self.admin_site.actions: description = getattr(func, 'short_description', name.replace('_', ' ')) actions.append((func, name, description)) # Then gather them from the model admin and all parent classes, # starting with self and working back up. for klass in self.__class__.mro()[::-1]: class_actions = getattr(klass, 'actions', []) # Avoid trying to iterate over None if not class_actions: continue actions.extend([self.get_action(action) for action in class_actions]) # get_action might have returned None, so filter any of those out. actions = filter(None, actions) # Convert the actions into a SortedDict keyed by name. actions = SortedDict([ (name, (func, name, desc)) for func, name, desc in actions ]) return actions
def get_changelist(
self, request, **kwargs)
Returns the ChangeList class for use on the changelist page.
def get_changelist(self, request, **kwargs): """ Returns the ChangeList class for use on the changelist page. """ from django.contrib.admin.views.main import ChangeList return ChangeList
def get_changelist_form(
self, request, **kwargs)
Returns a Form class for use in the Formset on the changelist page.
def get_changelist_form(self, request, **kwargs): """ Returns a Form class for use in the Formset on the changelist page. """ defaults = { "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) if (defaults.get('fields') is None and not modelform_defines_fields(defaults.get('form'))): defaults['fields'] = forms.ALL_FIELDS return modelform_factory(self.model, **defaults)
def get_changelist_formset(
self, request, **kwargs)
Returns a FormSet class for use on the changelist page if list_editable is used.
def get_changelist_formset(self, request, **kwargs): """ Returns a FormSet class for use on the changelist page if list_editable is used. """ defaults = { "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) return modelformset_factory(self.model, self.get_changelist_form(request), extra=0, fields=self.list_editable, **defaults)
def get_field_queryset(
self, db, db_field, request)
If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case).
def get_field_queryset(self, db, db_field, request): """ If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case). """ related_admin = self.admin_site._registry.get(db_field.rel.to, None) if related_admin is not None: ordering = related_admin.get_ordering(request) if ordering is not None and ordering != (): return db_field.rel.to._default_manager.using(db).order_by(*ordering).complex_filter(db_field.rel.limit_choices_to) return None
def get_fieldsets(
self, request, obj=None)
Hook for specifying fieldsets for the add form.
def get_fieldsets(self, request, obj=None): "Hook for specifying fieldsets for the add form." if self.declared_fieldsets: return self.declared_fieldsets form = self.get_form(request, obj, fields=None) fields = list(form.base_fields) + list(self.get_readonly_fields(request, obj)) return [(None, {'fields': fields})]
def get_form(
self, request, obj=None, **kwargs)
Returns a Form class for use in the admin add view. This is used by add_view and change_view.
def get_form(self, request, obj=None, **kwargs): """ Returns a Form class for use in the admin add view. This is used by add_view and change_view. """ if 'fields' in kwargs: fields = kwargs.pop('fields') else: fields = flatten_fieldsets(self.get_fieldsets(request, obj)) if self.exclude is None: exclude = [] else: exclude = list(self.exclude) exclude.extend(self.get_readonly_fields(request, obj)) if self.exclude is None and hasattr(self.form, '_meta') and self.form._meta.exclude: # Take the custom ModelForm's Meta.exclude into account only if the # ModelAdmin doesn't define its own. exclude.extend(self.form._meta.exclude) # if exclude is an empty list we pass None to be consistent with the # default on modelform_factory exclude = exclude or None defaults = { "form": self.form, "fields": fields, "exclude": exclude, "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) if defaults['fields'] is None and not modelform_defines_fields(defaults['form']): defaults['fields'] = forms.ALL_FIELDS try: return modelform_factory(self.model, **defaults) except FieldError as e: raise FieldError('%s. Check fields/fieldsets/exclude attributes of class %s.' % (e, self.__class__.__name__))
def get_formsets(
self, request, obj=None)
def get_formsets(self, request, obj=None): for inline in self.get_inline_instances(request, obj): yield inline.get_formset(request, obj)
def get_inline_instances(
self, request, obj=None)
def get_inline_instances(self, request, obj=None): inline_instances = [] for inline_class in self.inlines: inline = inline_class(self.model, self.admin_site) if request: if not (inline.has_add_permission(request) or inline.has_change_permission(request, obj) or inline.has_delete_permission(request, obj)): continue if not inline.has_add_permission(request): inline.max_num = 0 inline_instances.append(inline) return inline_instances
def get_list_display(
self, request)
Return a sequence containing the fields to be displayed on the changelist.
def get_list_display(self, request): """ Return a sequence containing the fields to be displayed on the changelist. """ return self.list_display
def get_list_display_links(
self, request, list_display)
Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display().
def get_list_display_links(self, request, list_display): """ Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display(). """ if self.list_display_links or not list_display: return self.list_display_links else: # Use only the first item in list_display as link return list(list_display)[:1]
def get_list_filter(
self, request)
Returns a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page.
def get_list_filter(self, request): """ Returns a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page. """ return self.list_filter
def get_model_perms(
self, request)
Returns a dict of all perms for this model. This dict has the keys
add
, change
, and delete
mapping to the True/False for each
of those actions.
def get_model_perms(self, request): """ Returns a dict of all perms for this model. This dict has the keys ``add``, ``change``, and ``delete`` mapping to the True/False for each of those actions. """ return { 'add': self.has_add_permission(request), 'change': self.has_change_permission(request), 'delete': self.has_delete_permission(request), }
def get_object(
self, request, object_id)
Returns an instance matching the primary key provided. None
is
returned if no match is found (or the object_id failed validation
against the primary key field).
def get_object(self, request, object_id): """ Returns an instance matching the primary key provided. ``None`` is returned if no match is found (or the object_id failed validation against the primary key field). """ queryset = self.get_queryset(request) model = queryset.model try: object_id = model._meta.pk.to_python(object_id) return queryset.get(pk=object_id) except (model.DoesNotExist, ValidationError, ValueError): return None
def get_ordering(
self, request)
Hook for specifying field ordering.
def get_ordering(self, request): """ Hook for specifying field ordering. """ return self.ordering or () # otherwise we might try to *None, which is bad ;)
def get_paginator(
self, request, queryset, per_page, orphans=0, allow_empty_first_page=True)
def get_paginator(self, request, queryset, per_page, orphans=0, allow_empty_first_page=True): return self.paginator(queryset, per_page, orphans, allow_empty_first_page)
def get_prepopulated_fields(
self, request, obj=None)
Hook for specifying custom prepopulated fields.
def get_prepopulated_fields(self, request, obj=None): """ Hook for specifying custom prepopulated fields. """ return self.prepopulated_fields
def get_preserved_filters(
self, request)
Returns the preserved filters querystring.
def get_preserved_filters(self, request): """ Returns the preserved filters querystring. """ match = request.resolver_match if self.preserve_filters and match: opts = self.model._meta current_url = '%s:%s' % (match.app_name, match.url_name) changelist_url = 'admin:%s_%s_changelist' % (opts.app_label, opts.model_name) if current_url == changelist_url: preserved_filters = request.GET.urlencode() else: preserved_filters = request.GET.get('_changelist_filters') if preserved_filters: return urlencode({'_changelist_filters': preserved_filters}) return ''
def get_queryset(
self, request)
Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view.
def get_queryset(self, request): """ Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view. """ qs = self.model._default_manager.get_queryset() # TODO: this should be handled by some parameter to the ChangeList. ordering = self.get_ordering(request) if ordering: qs = qs.order_by(*ordering) return qs
def get_readonly_fields(
self, request, obj=None)
Hook for specifying custom readonly fields.
def get_readonly_fields(self, request, obj=None): """ Hook for specifying custom readonly fields. """ return self.readonly_fields
def get_search_results(
self, request, queryset, search_term)
Returns a tuple containing a queryset to implement the search, and a boolean indicating if the results may contain duplicates.
def get_search_results(self, request, queryset, search_term): """ Returns a tuple containing a queryset to implement the search, and a boolean indicating if the results may contain duplicates. """ # Apply keyword searches. def construct_search(field_name): if field_name.startswith('^'): return "%s__istartswith" % field_name[1:] elif field_name.startswith('='): return "%s__iexact" % field_name[1:] elif field_name.startswith('@'): return "%s__search" % field_name[1:] else: return "%s__icontains" % field_name use_distinct = False if self.search_fields and search_term: orm_lookups = [construct_search(str(search_field)) for search_field in self.search_fields] for bit in search_term.split(): or_queries = [models.Q(**{orm_lookup: bit}) for orm_lookup in orm_lookups] queryset = queryset.filter(reduce(operator.or_, or_queries)) if not use_distinct: for search_spec in orm_lookups: if lookup_needs_distinct(self.opts, search_spec): use_distinct = True break return queryset, use_distinct
def get_urls(
self)
def get_urls(self): from django.conf.urls import patterns, url def wrap(view): def wrapper(*args, **kwargs): return self.admin_site.admin_view(view)(*args, **kwargs) return update_wrapper(wrapper, view) info = self.model._meta.app_label, self.model._meta.model_name urlpatterns = patterns('', url(r'^$', wrap(self.changelist_view), name='%s_%s_changelist' % info), url(r'^add/$', wrap(self.add_view), name='%s_%s_add' % info), url(r'^(.+)/history/$', wrap(self.history_view), name='%s_%s_history' % info), url(r'^(.+)/delete/$', wrap(self.delete_view), name='%s_%s_delete' % info), url(r'^(.+)/$', wrap(self.change_view), name='%s_%s_change' % info), ) return urlpatterns
def has_add_permission(
self, request)
Returns True if the given request has permission to add an object. Can be overridden by the user in subclasses.
def has_add_permission(self, request): """ Returns True if the given request has permission to add an object. Can be overridden by the user in subclasses. """ opts = self.opts codename = get_permission_codename('add', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_change_permission(
self, request, obj=None)
Returns True if the given request has permission to change the given
Django model instance, the default implementation doesn't examine the
obj
parameter.
Can be overridden by the user in subclasses. In such case it should
return True if the given request has permission to change the obj
model instance. If obj
is None, this should return True if the given
request has permission to change any object of the given type.
def has_change_permission(self, request, obj=None): """ Returns True if the given request has permission to change the given Django model instance, the default implementation doesn't examine the `obj` parameter. Can be overridden by the user in subclasses. In such case it should return True if the given request has permission to change the `obj` model instance. If `obj` is None, this should return True if the given request has permission to change *any* object of the given type. """ opts = self.opts codename = get_permission_codename('change', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_delete_permission(
self, request, obj=None)
Returns True if the given request has permission to change the given
Django model instance, the default implementation doesn't examine the
obj
parameter.
Can be overridden by the user in subclasses. In such case it should
return True if the given request has permission to delete the obj
model instance. If obj
is None, this should return True if the given
request has permission to delete any object of the given type.
def has_delete_permission(self, request, obj=None): """ Returns True if the given request has permission to change the given Django model instance, the default implementation doesn't examine the `obj` parameter. Can be overridden by the user in subclasses. In such case it should return True if the given request has permission to delete the `obj` model instance. If `obj` is None, this should return True if the given request has permission to delete *any* object of the given type. """ opts = self.opts codename = get_permission_codename('delete', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def history_view(
self, request, object_id, extra_context=None)
The 'history' admin view for this model.
def history_view(self, request, object_id, extra_context=None): "The 'history' admin view for this model." from django.contrib.admin.models import LogEntry # First check if the user can see this history. model = self.model obj = get_object_or_404(model, pk=unquote(object_id)) if not self.has_change_permission(request, obj): raise PermissionDenied # Then get the history for this object. opts = model._meta app_label = opts.app_label action_list = LogEntry.objects.filter( object_id=unquote(object_id), content_type__id__exact=ContentType.objects.get_for_model(model).id ).select_related().order_by('action_time') context = { 'title': _('Change history: %s') % force_text(obj), 'action_list': action_list, 'module_name': capfirst(force_text(opts.verbose_name_plural)), 'object': obj, 'app_label': app_label, 'opts': opts, 'preserved_filters': self.get_preserved_filters(request), } context.update(extra_context or {}) return TemplateResponse(request, self.object_history_template or [ "admin/%s/%s/object_history.html" % (app_label, opts.model_name), "admin/%s/object_history.html" % app_label, "admin/object_history.html" ], context, current_app=self.admin_site.name)
def log_addition(
self, request, object)
Log that an object has been successfully added.
The default implementation creates an admin LogEntry object.
def log_addition(self, request, object): """ Log that an object has been successfully added. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, ADDITION LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=ADDITION )
def log_change(
self, request, object, message)
Log that an object has been successfully changed.
The default implementation creates an admin LogEntry object.
def log_change(self, request, object, message): """ Log that an object has been successfully changed. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, CHANGE LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=CHANGE, change_message=message )
def log_deletion(
self, request, object, object_repr)
Log that an object will be deleted. Note that this method is called before the deletion.
The default implementation creates an admin LogEntry object.
def log_deletion(self, request, object, object_repr): """ Log that an object will be deleted. Note that this method is called before the deletion. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, DELETION LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(self.model).pk, object_id=object.pk, object_repr=object_repr, action_flag=DELETION )
def lookup_allowed(
self, lookup, value)
def lookup_allowed(self, lookup, value): model = self.model # Check FKey lookups that are allowed, so that popups produced by # ForeignKeyRawIdWidget, on the basis of ForeignKey.limit_choices_to, # are allowed to work. for l in model._meta.related_fkey_lookups: for k, v in widgets.url_params_from_lookup_dict(l).items(): if k == lookup and v == value: return True parts = lookup.split(LOOKUP_SEP) # Last term in lookup is a query term (__exact, __startswith etc) # This term can be ignored. if len(parts) > 1 and parts[-1] in QUERY_TERMS: parts.pop() # Special case -- foo__id__exact and foo__id queries are implied # if foo has been specifically included in the lookup list; so # drop __id if it is the last part. However, first we need to find # the pk attribute name. rel_name = None for part in parts[:-1]: try: field, _, _, _ = model._meta.get_field_by_name(part) except FieldDoesNotExist: # Lookups on non-existent fields are ok, since they're ignored # later. return True if hasattr(field, 'rel'): if field.rel is None: # This property or relation doesn't exist, but it's allowed # since it's ignored in ChangeList.get_filters(). return True model = field.rel.to rel_name = field.rel.get_related_field().name elif isinstance(field, RelatedObject): model = field.model rel_name = model._meta.pk.name else: rel_name = None if rel_name and len(parts) > 1 and parts[-1] == rel_name: parts.pop() if len(parts) == 1: return True clean_lookup = LOOKUP_SEP.join(parts) return clean_lookup in self.list_filter or clean_lookup == self.date_hierarchy
def message_user(
self, request, message, level=20, extra_tags='', fail_silently=False)
Send a message to the user. The default implementation posts a message using the django.contrib.messages backend.
Exposes almost the same API as messages.add_message(), but accepts the
positional arguments in a different order to maintain backwards
compatibility. For convenience, it accepts the level
argument as
a string rather than the usual level number.
def message_user(self, request, message, level=messages.INFO, extra_tags='', fail_silently=False): """ Send a message to the user. The default implementation posts a message using the django.contrib.messages backend. Exposes almost the same API as messages.add_message(), but accepts the positional arguments in a different order to maintain backwards compatibility. For convenience, it accepts the `level` argument as a string rather than the usual level number. """ if not isinstance(level, int): # attempt to get the level if passed a string try: level = getattr(messages.constants, level.upper()) except AttributeError: levels = messages.constants.DEFAULT_TAGS.values() levels_repr = ', '.join('`%s`' % l for l in levels) raise ValueError('Bad message level string: `%s`. ' 'Possible values are: %s' % (level, levels_repr)) messages.add_message(request, level, message, extra_tags=extra_tags, fail_silently=fail_silently)
def queryset(
*args, **kwargs)
def wrapped(*args, **kwargs): warnings.warn( "`%s.%s` is deprecated, use `%s` instead." % (self.class_name, self.old_method_name, self.new_method_name), self.deprecation_warning, 2) return f(*args, **kwargs)
def render_change_form(
self, request, context, add=False, change=False, form_url='', obj=None)
def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None): opts = self.model._meta app_label = opts.app_label preserved_filters = self.get_preserved_filters(request) form_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, form_url) context.update({ 'add': add, 'change': change, 'has_add_permission': self.has_add_permission(request), 'has_change_permission': self.has_change_permission(request, obj), 'has_delete_permission': self.has_delete_permission(request, obj), 'has_file_field': True, # FIXME - this should check if form or formsets have a FileField, 'has_absolute_url': hasattr(self.model, 'get_absolute_url'), 'form_url': form_url, 'opts': opts, 'content_type_id': ContentType.objects.get_for_model(self.model).id, 'save_as': self.save_as, 'save_on_top': self.save_on_top, }) if add and self.add_form_template is not None: form_template = self.add_form_template else: form_template = self.change_form_template return TemplateResponse(request, form_template or [ "admin/%s/%s/change_form.html" % (app_label, opts.model_name), "admin/%s/change_form.html" % app_label, "admin/change_form.html" ], context, current_app=self.admin_site.name)
def response_action(
self, request, queryset)
Handle an admin action. This is called if a request is POSTed to the changelist; it returns an HttpResponse if the action was handled, and None otherwise.
def response_action(self, request, queryset): """ Handle an admin action. This is called if a request is POSTed to the changelist; it returns an HttpResponse if the action was handled, and None otherwise. """ # There can be multiple action forms on the page (at the top # and bottom of the change list, for example). Get the action # whose button was pushed. try: action_index = int(request.POST.get('index', 0)) except ValueError: action_index = 0 # Construct the action form. data = request.POST.copy() data.pop(helpers.ACTION_CHECKBOX_NAME, None) data.pop("index", None) # Use the action whose button was pushed try: data.update({'action': data.getlist('action')[action_index]}) except IndexError: # If we didn't get an action from the chosen form that's invalid # POST data, so by deleting action it'll fail the validation check # below. So no need to do anything here pass action_form = self.action_form(data, auto_id=None) action_form.fields['action'].choices = self.get_action_choices(request) # If the form's valid we can handle the action. if action_form.is_valid(): action = action_form.cleaned_data['action'] select_across = action_form.cleaned_data['select_across'] func = self.get_actions(request)[action][0] # Get the list of selected PKs. If nothing's selected, we can't # perform an action on it, so bail. Except we want to perform # the action explicitly on all objects. selected = request.POST.getlist(helpers.ACTION_CHECKBOX_NAME) if not selected and not select_across: # Reminder that something needs to be selected or nothing will happen msg = _("Items must be selected in order to perform " "actions on them. No items have been changed.") self.message_user(request, msg, messages.WARNING) return None if not select_across: # Perform the action only on the selected objects queryset = queryset.filter(pk__in=selected) response = func(self, request, queryset) # Actions may return an HttpResponse-like object, which will be # used as the response from the POST. If not, we'll be a good # little HTTP citizen and redirect back to the changelist page. if isinstance(response, HttpResponseBase): return response else: return HttpResponseRedirect(request.get_full_path()) else: msg = _("No action selected.") self.message_user(request, msg, messages.WARNING) return None
def response_add(
self, request, obj, post_url_continue=None)
Determines the HttpResponse for the add_view stage.
def response_add(self, request, obj, post_url_continue=None): """ Determines the HttpResponse for the add_view stage. """ opts = obj._meta pk_value = obj._get_pk_val() preserved_filters = self.get_preserved_filters(request) msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)} # Here, we distinguish between different save types by checking for # the presence of keys in request.POST. if IS_POPUP_VAR in request.POST: return SimpleTemplateResponse('admin/popup_response.html', { 'pk_value': escape(pk_value), 'obj': escapejs(obj) }) elif "_continue" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) if post_url_continue is None: post_url_continue = reverse('admin:%s_%s_change' % (opts.app_label, opts.model_name), args=(pk_value,), current_app=self.admin_site.name) post_url_continue = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url_continue) return HttpResponseRedirect(post_url_continue) elif "_addanother" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may add another %(name)s below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = request.path redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) else: msg = _('The %(name)s "%(obj)s" was added successfully.') % msg_dict self.message_user(request, msg, messages.SUCCESS) return self.response_post_save_add(request, obj)
def response_change(
self, request, obj)
Determines the HttpResponse for the change_view stage.
def response_change(self, request, obj): """ Determines the HttpResponse for the change_view stage. """ opts = self.model._meta pk_value = obj._get_pk_val() preserved_filters = self.get_preserved_filters(request) msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)} if "_continue" in request.POST: msg = _('The %(name)s "%(obj)s" was changed successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = request.path redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) elif "_saveasnew" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = reverse('admin:%s_%s_change' % (opts.app_label, opts.model_name), args=(pk_value,), current_app=self.admin_site.name) redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) elif "_addanother" in request.POST: msg = _('The %(name)s "%(obj)s" was changed successfully. You may add another %(name)s below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = reverse('admin:%s_%s_add' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) else: msg = _('The %(name)s "%(obj)s" was changed successfully.') % msg_dict self.message_user(request, msg, messages.SUCCESS) return self.response_post_save_change(request, obj)
def response_post_save_add(
self, request, obj)
Figure out where to redirect after the 'Save' button has been pressed when adding a new object.
def response_post_save_add(self, request, obj): """ Figure out where to redirect after the 'Save' button has been pressed when adding a new object. """ opts = self.model._meta if self.has_change_permission(request, None): post_url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url) else: post_url = reverse('admin:index', current_app=self.admin_site.name) return HttpResponseRedirect(post_url)
def response_post_save_change(
self, request, obj)
Figure out where to redirect after the 'Save' button has been pressed when editing an existing object.
def response_post_save_change(self, request, obj): """ Figure out where to redirect after the 'Save' button has been pressed when editing an existing object. """ opts = self.model._meta if self.has_change_permission(request, None): post_url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url) else: post_url = reverse('admin:index', current_app=self.admin_site.name) return HttpResponseRedirect(post_url)
def save_form(
self, request, form, change)
Given a ModelForm return an unsaved instance. change
is True if
the object is being changed, and False if it's being added.
def save_form(self, request, form, change): """ Given a ModelForm return an unsaved instance. ``change`` is True if the object is being changed, and False if it's being added. """ return form.save(commit=False)
def save_formset(
self, request, form, formset, change)
Given an inline formset save it to the database.
def save_formset(self, request, form, formset, change): """ Given an inline formset save it to the database. """ formset.save()
def save_model(
self, request, obj, form, change)
Given a model instance save it to the database.
def save_model(self, request, obj, form, change): """ Given a model instance save it to the database. """ obj.save()
Given the HttpRequest
, the parent ModelForm
instance, the
list of inline formsets and a boolean value based on whether the
parent is being added or changed, save the related objects to the
database. Note that at this point save_form() and save_model() have
already been called.
def to_field_allowed(
self, request, to_field)
Returns True if the model associated with this admin should be allowed to be referenced by the specified field.
def to_field_allowed(self, request, to_field): """ Returns True if the model associated with this admin should be allowed to be referenced by the specified field. """ opts = self.model._meta try: field = opts.get_field(to_field) except FieldDoesNotExist: return False # Always allow referencing the primary key since it's already possible # to get this information from the change view URL. if field.primary_key: return True # Make sure at least one of the models registered for this site # references this field through a FK or a M2M relationship. registered_models = set() for model, admin in self.admin_site._registry.items(): registered_models.add(model) for inline in admin.inlines: registered_models.add(inline.model) for related_object in opts.get_all_related_objects(include_hidden=True): related_model = related_object.model if (any(issubclass(model, related_model) for model in registered_models) and related_object.field.rel.get_related_field() == field): return True return False
def validate(
cls, model)
@classmethod def validate(cls, model): validator = cls.validator_class() validator.validate(cls, model)
class MediaCollectionAdmin
class MediaCollectionAdmin(admin.ModelAdmin): search_fields = ['title', 'code'] ordering = ['code'] inlines = [MediaCollectionIdentifierInline, MediaCollectionRelatedInline]
Ancestors (in MRO)
- MediaCollectionAdmin
- django.contrib.admin.options.ModelAdmin
- django.contrib.admin.options.BaseModelAdmin
- __builtin__.object
Class variables
var action_form
var actions
var actions_on_bottom
var actions_on_top
var actions_selection_counter
var add_form_template
var change_form_template
var change_list_template
var date_hierarchy
var delete_confirmation_template
var delete_selected_confirmation_template
var exclude
var fields
var fieldsets
var filter_horizontal
var filter_vertical
var form
var formfield_overrides
var inlines
var list_display
var list_display_links
var list_editable
var list_filter
var list_max_show_all
var list_per_page
var object_history_template
var ordering
var paginator
var prepopulated_fields
var preserve_filters
var radio_fields
var raw_id_fields
var readonly_fields
var save_as
var save_on_top
var search_fields
var validator_class
Instance variables
var declared_fieldsets
var media
var urls
Methods
def __init__(
self, model, admin_site)
def __init__(self, model, admin_site): self.model = model self.opts = model._meta self.admin_site = admin_site super(ModelAdmin, self).__init__()
def action_checkbox(
self, obj)
A list_display column containing a checkbox widget.
def action_checkbox(self, obj): """ A list_display column containing a checkbox widget. """ return helpers.checkbox.render(helpers.ACTION_CHECKBOX_NAME, force_text(obj.pk))
def add_view(
self, *args, **kwargs)
The 'add' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def change_view(
self, *args, **kwargs)
The 'change' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def changelist_view(
self, *args, **kwargs)
The 'change list' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def construct_change_message(
self, request, form, formsets)
Construct a change message from a changed object.
def construct_change_message(self, request, form, formsets): """ Construct a change message from a changed object. """ change_message = [] if form.changed_data: change_message.append(_('Changed %s.') % get_text_list(form.changed_data, _('and'))) if formsets: for formset in formsets: for added_object in formset.new_objects: change_message.append(_('Added %(name)s "%(object)s".') % {'name': force_text(added_object._meta.verbose_name), 'object': force_text(added_object)}) for changed_object, changed_fields in formset.changed_objects: change_message.append(_('Changed %(list)s for %(name)s "%(object)s".') % {'list': get_text_list(changed_fields, _('and')), 'name': force_text(changed_object._meta.verbose_name), 'object': force_text(changed_object)}) for deleted_object in formset.deleted_objects: change_message.append(_('Deleted %(name)s "%(object)s".') % {'name': force_text(deleted_object._meta.verbose_name), 'object': force_text(deleted_object)}) change_message = ' '.join(change_message) return change_message or _('No fields changed.')
def delete_model(
self, request, obj)
Given a model instance delete it from the database.
def delete_model(self, request, obj): """ Given a model instance delete it from the database. """ obj.delete()
def delete_view(
self, *args, **kwargs)
The 'delete' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def formfield_for_choice_field(
self, db_field, request=None, **kwargs)
Get a form Field for a database Field that has declared choices.
def formfield_for_choice_field(self, db_field, request=None, **kwargs): """ Get a form Field for a database Field that has declared choices. """ # If the field is named as a radio_field, use a RadioSelect if db_field.name in self.radio_fields: # Avoid stomping on custom widget/choices arguments. if 'widget' not in kwargs: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) if 'choices' not in kwargs: kwargs['choices'] = db_field.get_choices( include_blank=db_field.blank, blank_choice=[('', _('None'))] ) return db_field.formfield(**kwargs)
def formfield_for_dbfield(
self, db_field, **kwargs)
Hook for specifying the form Field instance for a given database Field instance.
If kwargs are given, they're passed to the form Field's constructor.
def formfield_for_dbfield(self, db_field, **kwargs): """ Hook for specifying the form Field instance for a given database Field instance. If kwargs are given, they're passed to the form Field's constructor. """ request = kwargs.pop("request", None) # If the field specifies choices, we don't need to look for special # admin widgets - we just need to use a select widget of some kind. if db_field.choices: return self.formfield_for_choice_field(db_field, request, **kwargs) # ForeignKey or ManyToManyFields if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)): # Combine the field kwargs with any options for formfield_overrides. # Make sure the passed in **kwargs override anything in # formfield_overrides because **kwargs is more specific, and should # always win. if db_field.__class__ in self.formfield_overrides: kwargs = dict(self.formfield_overrides[db_field.__class__], **kwargs) # Get the correct formfield. if isinstance(db_field, models.ForeignKey): formfield = self.formfield_for_foreignkey(db_field, request, **kwargs) elif isinstance(db_field, models.ManyToManyField): formfield = self.formfield_for_manytomany(db_field, request, **kwargs) # For non-raw_id fields, wrap the widget with a wrapper that adds # extra HTML -- the "add other" interface -- to the end of the # rendered output. formfield can be None if it came from a # OneToOneField with parent_link=True or a M2M intermediary. if formfield and db_field.name not in self.raw_id_fields: related_modeladmin = self.admin_site._registry.get( db_field.rel.to) can_add_related = bool(related_modeladmin and related_modeladmin.has_add_permission(request)) formfield.widget = widgets.RelatedFieldWidgetWrapper( formfield.widget, db_field.rel, self.admin_site, can_add_related=can_add_related) return formfield # If we've got overrides for the formfield defined, use 'em. **kwargs # passed to formfield_for_dbfield override the defaults. for klass in db_field.__class__.mro(): if klass in self.formfield_overrides: kwargs = dict(copy.deepcopy(self.formfield_overrides[klass]), **kwargs) return db_field.formfield(**kwargs) # For any other type of field, just call its formfield() method. return db_field.formfield(**kwargs)
def formfield_for_foreignkey(
self, db_field, request=None, **kwargs)
Get a form Field for a ForeignKey.
def formfield_for_foreignkey(self, db_field, request=None, **kwargs): """ Get a form Field for a ForeignKey. """ db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel, self.admin_site, using=db) elif db_field.name in self.radio_fields: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) kwargs['empty_label'] = _('None') if db_field.blank else None if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def formfield_for_manytomany(
self, db_field, request=None, **kwargs)
Get a form Field for a ManyToManyField.
def formfield_for_manytomany(self, db_field, request=None, **kwargs): """ Get a form Field for a ManyToManyField. """ # If it uses an intermediary model that isn't auto created, don't show # a field in admin. if not db_field.rel.through._meta.auto_created: return None db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel, self.admin_site, using=db) kwargs['help_text'] = '' elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)): kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical)) if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def get_action(
self, action)
Return a given action from a parameter, which can either be a callable, or the name of a method on the ModelAdmin. Return is a tuple of (callable, name, description).
def get_action(self, action): """ Return a given action from a parameter, which can either be a callable, or the name of a method on the ModelAdmin. Return is a tuple of (callable, name, description). """ # If the action is a callable, just use it. if callable(action): func = action action = action.__name__ # Next, look for a method. Grab it off self.__class__ to get an unbound # method instead of a bound one; this ensures that the calling # conventions are the same for functions and methods. elif hasattr(self.__class__, action): func = getattr(self.__class__, action) # Finally, look for a named method on the admin site else: try: func = self.admin_site.get_action(action) except KeyError: return None if hasattr(func, 'short_description'): description = func.short_description else: description = capfirst(action.replace('_', ' ')) return func, action, description
def get_action_choices(
self, request, default_choices=[(u'', u'---------')])
Return a list of choices for use in a form object. Each choice is a tuple (name, description).
def get_action_choices(self, request, default_choices=BLANK_CHOICE_DASH): """ Return a list of choices for use in a form object. Each choice is a tuple (name, description). """ choices = [] + default_choices for func, name, description in six.itervalues(self.get_actions(request)): choice = (name, description % model_format_dict(self.opts)) choices.append(choice) return choices
def get_actions(
self, request)
Return a dictionary mapping the names of all actions for this ModelAdmin to a tuple of (callable, name, description) for each action.
def get_actions(self, request): """ Return a dictionary mapping the names of all actions for this ModelAdmin to a tuple of (callable, name, description) for each action. """ # If self.actions is explicitly set to None that means that we don't # want *any* actions enabled on this page. from django.contrib.admin.views.main import _is_changelist_popup if self.actions is None or _is_changelist_popup(request): return SortedDict() actions = [] # Gather actions from the admin site first for (name, func) in self.admin_site.actions: description = getattr(func, 'short_description', name.replace('_', ' ')) actions.append((func, name, description)) # Then gather them from the model admin and all parent classes, # starting with self and working back up. for klass in self.__class__.mro()[::-1]: class_actions = getattr(klass, 'actions', []) # Avoid trying to iterate over None if not class_actions: continue actions.extend([self.get_action(action) for action in class_actions]) # get_action might have returned None, so filter any of those out. actions = filter(None, actions) # Convert the actions into a SortedDict keyed by name. actions = SortedDict([ (name, (func, name, desc)) for func, name, desc in actions ]) return actions
def get_changelist(
self, request, **kwargs)
Returns the ChangeList class for use on the changelist page.
def get_changelist(self, request, **kwargs): """ Returns the ChangeList class for use on the changelist page. """ from django.contrib.admin.views.main import ChangeList return ChangeList
def get_changelist_form(
self, request, **kwargs)
Returns a Form class for use in the Formset on the changelist page.
def get_changelist_form(self, request, **kwargs): """ Returns a Form class for use in the Formset on the changelist page. """ defaults = { "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) if (defaults.get('fields') is None and not modelform_defines_fields(defaults.get('form'))): defaults['fields'] = forms.ALL_FIELDS return modelform_factory(self.model, **defaults)
def get_changelist_formset(
self, request, **kwargs)
Returns a FormSet class for use on the changelist page if list_editable is used.
def get_changelist_formset(self, request, **kwargs): """ Returns a FormSet class for use on the changelist page if list_editable is used. """ defaults = { "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) return modelformset_factory(self.model, self.get_changelist_form(request), extra=0, fields=self.list_editable, **defaults)
def get_field_queryset(
self, db, db_field, request)
If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case).
def get_field_queryset(self, db, db_field, request): """ If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case). """ related_admin = self.admin_site._registry.get(db_field.rel.to, None) if related_admin is not None: ordering = related_admin.get_ordering(request) if ordering is not None and ordering != (): return db_field.rel.to._default_manager.using(db).order_by(*ordering).complex_filter(db_field.rel.limit_choices_to) return None
def get_fieldsets(
self, request, obj=None)
Hook for specifying fieldsets for the add form.
def get_fieldsets(self, request, obj=None): "Hook for specifying fieldsets for the add form." if self.declared_fieldsets: return self.declared_fieldsets form = self.get_form(request, obj, fields=None) fields = list(form.base_fields) + list(self.get_readonly_fields(request, obj)) return [(None, {'fields': fields})]
def get_form(
self, request, obj=None, **kwargs)
Returns a Form class for use in the admin add view. This is used by add_view and change_view.
def get_form(self, request, obj=None, **kwargs): """ Returns a Form class for use in the admin add view. This is used by add_view and change_view. """ if 'fields' in kwargs: fields = kwargs.pop('fields') else: fields = flatten_fieldsets(self.get_fieldsets(request, obj)) if self.exclude is None: exclude = [] else: exclude = list(self.exclude) exclude.extend(self.get_readonly_fields(request, obj)) if self.exclude is None and hasattr(self.form, '_meta') and self.form._meta.exclude: # Take the custom ModelForm's Meta.exclude into account only if the # ModelAdmin doesn't define its own. exclude.extend(self.form._meta.exclude) # if exclude is an empty list we pass None to be consistent with the # default on modelform_factory exclude = exclude or None defaults = { "form": self.form, "fields": fields, "exclude": exclude, "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) if defaults['fields'] is None and not modelform_defines_fields(defaults['form']): defaults['fields'] = forms.ALL_FIELDS try: return modelform_factory(self.model, **defaults) except FieldError as e: raise FieldError('%s. Check fields/fieldsets/exclude attributes of class %s.' % (e, self.__class__.__name__))
def get_formsets(
self, request, obj=None)
def get_formsets(self, request, obj=None): for inline in self.get_inline_instances(request, obj): yield inline.get_formset(request, obj)
def get_inline_instances(
self, request, obj=None)
def get_inline_instances(self, request, obj=None): inline_instances = [] for inline_class in self.inlines: inline = inline_class(self.model, self.admin_site) if request: if not (inline.has_add_permission(request) or inline.has_change_permission(request, obj) or inline.has_delete_permission(request, obj)): continue if not inline.has_add_permission(request): inline.max_num = 0 inline_instances.append(inline) return inline_instances
def get_list_display(
self, request)
Return a sequence containing the fields to be displayed on the changelist.
def get_list_display(self, request): """ Return a sequence containing the fields to be displayed on the changelist. """ return self.list_display
def get_list_display_links(
self, request, list_display)
Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display().
def get_list_display_links(self, request, list_display): """ Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display(). """ if self.list_display_links or not list_display: return self.list_display_links else: # Use only the first item in list_display as link return list(list_display)[:1]
def get_list_filter(
self, request)
Returns a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page.
def get_list_filter(self, request): """ Returns a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page. """ return self.list_filter
def get_model_perms(
self, request)
Returns a dict of all perms for this model. This dict has the keys
add
, change
, and delete
mapping to the True/False for each
of those actions.
def get_model_perms(self, request): """ Returns a dict of all perms for this model. This dict has the keys ``add``, ``change``, and ``delete`` mapping to the True/False for each of those actions. """ return { 'add': self.has_add_permission(request), 'change': self.has_change_permission(request), 'delete': self.has_delete_permission(request), }
def get_object(
self, request, object_id)
Returns an instance matching the primary key provided. None
is
returned if no match is found (or the object_id failed validation
against the primary key field).
def get_object(self, request, object_id): """ Returns an instance matching the primary key provided. ``None`` is returned if no match is found (or the object_id failed validation against the primary key field). """ queryset = self.get_queryset(request) model = queryset.model try: object_id = model._meta.pk.to_python(object_id) return queryset.get(pk=object_id) except (model.DoesNotExist, ValidationError, ValueError): return None
def get_ordering(
self, request)
Hook for specifying field ordering.
def get_ordering(self, request): """ Hook for specifying field ordering. """ return self.ordering or () # otherwise we might try to *None, which is bad ;)
def get_paginator(
self, request, queryset, per_page, orphans=0, allow_empty_first_page=True)
def get_paginator(self, request, queryset, per_page, orphans=0, allow_empty_first_page=True): return self.paginator(queryset, per_page, orphans, allow_empty_first_page)
def get_prepopulated_fields(
self, request, obj=None)
Hook for specifying custom prepopulated fields.
def get_prepopulated_fields(self, request, obj=None): """ Hook for specifying custom prepopulated fields. """ return self.prepopulated_fields
def get_preserved_filters(
self, request)
Returns the preserved filters querystring.
def get_preserved_filters(self, request): """ Returns the preserved filters querystring. """ match = request.resolver_match if self.preserve_filters and match: opts = self.model._meta current_url = '%s:%s' % (match.app_name, match.url_name) changelist_url = 'admin:%s_%s_changelist' % (opts.app_label, opts.model_name) if current_url == changelist_url: preserved_filters = request.GET.urlencode() else: preserved_filters = request.GET.get('_changelist_filters') if preserved_filters: return urlencode({'_changelist_filters': preserved_filters}) return ''
def get_queryset(
self, request)
Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view.
def get_queryset(self, request): """ Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view. """ qs = self.model._default_manager.get_queryset() # TODO: this should be handled by some parameter to the ChangeList. ordering = self.get_ordering(request) if ordering: qs = qs.order_by(*ordering) return qs
def get_readonly_fields(
self, request, obj=None)
Hook for specifying custom readonly fields.
def get_readonly_fields(self, request, obj=None): """ Hook for specifying custom readonly fields. """ return self.readonly_fields
def get_search_results(
self, request, queryset, search_term)
Returns a tuple containing a queryset to implement the search, and a boolean indicating if the results may contain duplicates.
def get_search_results(self, request, queryset, search_term): """ Returns a tuple containing a queryset to implement the search, and a boolean indicating if the results may contain duplicates. """ # Apply keyword searches. def construct_search(field_name): if field_name.startswith('^'): return "%s__istartswith" % field_name[1:] elif field_name.startswith('='): return "%s__iexact" % field_name[1:] elif field_name.startswith('@'): return "%s__search" % field_name[1:] else: return "%s__icontains" % field_name use_distinct = False if self.search_fields and search_term: orm_lookups = [construct_search(str(search_field)) for search_field in self.search_fields] for bit in search_term.split(): or_queries = [models.Q(**{orm_lookup: bit}) for orm_lookup in orm_lookups] queryset = queryset.filter(reduce(operator.or_, or_queries)) if not use_distinct: for search_spec in orm_lookups: if lookup_needs_distinct(self.opts, search_spec): use_distinct = True break return queryset, use_distinct
def get_urls(
self)
def get_urls(self): from django.conf.urls import patterns, url def wrap(view): def wrapper(*args, **kwargs): return self.admin_site.admin_view(view)(*args, **kwargs) return update_wrapper(wrapper, view) info = self.model._meta.app_label, self.model._meta.model_name urlpatterns = patterns('', url(r'^$', wrap(self.changelist_view), name='%s_%s_changelist' % info), url(r'^add/$', wrap(self.add_view), name='%s_%s_add' % info), url(r'^(.+)/history/$', wrap(self.history_view), name='%s_%s_history' % info), url(r'^(.+)/delete/$', wrap(self.delete_view), name='%s_%s_delete' % info), url(r'^(.+)/$', wrap(self.change_view), name='%s_%s_change' % info), ) return urlpatterns
def has_add_permission(
self, request)
Returns True if the given request has permission to add an object. Can be overridden by the user in subclasses.
def has_add_permission(self, request): """ Returns True if the given request has permission to add an object. Can be overridden by the user in subclasses. """ opts = self.opts codename = get_permission_codename('add', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_change_permission(
self, request, obj=None)
Returns True if the given request has permission to change the given
Django model instance, the default implementation doesn't examine the
obj
parameter.
Can be overridden by the user in subclasses. In such case it should
return True if the given request has permission to change the obj
model instance. If obj
is None, this should return True if the given
request has permission to change any object of the given type.
def has_change_permission(self, request, obj=None): """ Returns True if the given request has permission to change the given Django model instance, the default implementation doesn't examine the `obj` parameter. Can be overridden by the user in subclasses. In such case it should return True if the given request has permission to change the `obj` model instance. If `obj` is None, this should return True if the given request has permission to change *any* object of the given type. """ opts = self.opts codename = get_permission_codename('change', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_delete_permission(
self, request, obj=None)
Returns True if the given request has permission to change the given
Django model instance, the default implementation doesn't examine the
obj
parameter.
Can be overridden by the user in subclasses. In such case it should
return True if the given request has permission to delete the obj
model instance. If obj
is None, this should return True if the given
request has permission to delete any object of the given type.
def has_delete_permission(self, request, obj=None): """ Returns True if the given request has permission to change the given Django model instance, the default implementation doesn't examine the `obj` parameter. Can be overridden by the user in subclasses. In such case it should return True if the given request has permission to delete the `obj` model instance. If `obj` is None, this should return True if the given request has permission to delete *any* object of the given type. """ opts = self.opts codename = get_permission_codename('delete', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def history_view(
self, request, object_id, extra_context=None)
The 'history' admin view for this model.
def history_view(self, request, object_id, extra_context=None): "The 'history' admin view for this model." from django.contrib.admin.models import LogEntry # First check if the user can see this history. model = self.model obj = get_object_or_404(model, pk=unquote(object_id)) if not self.has_change_permission(request, obj): raise PermissionDenied # Then get the history for this object. opts = model._meta app_label = opts.app_label action_list = LogEntry.objects.filter( object_id=unquote(object_id), content_type__id__exact=ContentType.objects.get_for_model(model).id ).select_related().order_by('action_time') context = { 'title': _('Change history: %s') % force_text(obj), 'action_list': action_list, 'module_name': capfirst(force_text(opts.verbose_name_plural)), 'object': obj, 'app_label': app_label, 'opts': opts, 'preserved_filters': self.get_preserved_filters(request), } context.update(extra_context or {}) return TemplateResponse(request, self.object_history_template or [ "admin/%s/%s/object_history.html" % (app_label, opts.model_name), "admin/%s/object_history.html" % app_label, "admin/object_history.html" ], context, current_app=self.admin_site.name)
def log_addition(
self, request, object)
Log that an object has been successfully added.
The default implementation creates an admin LogEntry object.
def log_addition(self, request, object): """ Log that an object has been successfully added. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, ADDITION LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=ADDITION )
def log_change(
self, request, object, message)
Log that an object has been successfully changed.
The default implementation creates an admin LogEntry object.
def log_change(self, request, object, message): """ Log that an object has been successfully changed. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, CHANGE LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=CHANGE, change_message=message )
def log_deletion(
self, request, object, object_repr)
Log that an object will be deleted. Note that this method is called before the deletion.
The default implementation creates an admin LogEntry object.
def log_deletion(self, request, object, object_repr): """ Log that an object will be deleted. Note that this method is called before the deletion. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, DELETION LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(self.model).pk, object_id=object.pk, object_repr=object_repr, action_flag=DELETION )
def lookup_allowed(
self, lookup, value)
def lookup_allowed(self, lookup, value): model = self.model # Check FKey lookups that are allowed, so that popups produced by # ForeignKeyRawIdWidget, on the basis of ForeignKey.limit_choices_to, # are allowed to work. for l in model._meta.related_fkey_lookups: for k, v in widgets.url_params_from_lookup_dict(l).items(): if k == lookup and v == value: return True parts = lookup.split(LOOKUP_SEP) # Last term in lookup is a query term (__exact, __startswith etc) # This term can be ignored. if len(parts) > 1 and parts[-1] in QUERY_TERMS: parts.pop() # Special case -- foo__id__exact and foo__id queries are implied # if foo has been specifically included in the lookup list; so # drop __id if it is the last part. However, first we need to find # the pk attribute name. rel_name = None for part in parts[:-1]: try: field, _, _, _ = model._meta.get_field_by_name(part) except FieldDoesNotExist: # Lookups on non-existent fields are ok, since they're ignored # later. return True if hasattr(field, 'rel'): if field.rel is None: # This property or relation doesn't exist, but it's allowed # since it's ignored in ChangeList.get_filters(). return True model = field.rel.to rel_name = field.rel.get_related_field().name elif isinstance(field, RelatedObject): model = field.model rel_name = model._meta.pk.name else: rel_name = None if rel_name and len(parts) > 1 and parts[-1] == rel_name: parts.pop() if len(parts) == 1: return True clean_lookup = LOOKUP_SEP.join(parts) return clean_lookup in self.list_filter or clean_lookup == self.date_hierarchy
def message_user(
self, request, message, level=20, extra_tags='', fail_silently=False)
Send a message to the user. The default implementation posts a message using the django.contrib.messages backend.
Exposes almost the same API as messages.add_message(), but accepts the
positional arguments in a different order to maintain backwards
compatibility. For convenience, it accepts the level
argument as
a string rather than the usual level number.
def message_user(self, request, message, level=messages.INFO, extra_tags='', fail_silently=False): """ Send a message to the user. The default implementation posts a message using the django.contrib.messages backend. Exposes almost the same API as messages.add_message(), but accepts the positional arguments in a different order to maintain backwards compatibility. For convenience, it accepts the `level` argument as a string rather than the usual level number. """ if not isinstance(level, int): # attempt to get the level if passed a string try: level = getattr(messages.constants, level.upper()) except AttributeError: levels = messages.constants.DEFAULT_TAGS.values() levels_repr = ', '.join('`%s`' % l for l in levels) raise ValueError('Bad message level string: `%s`. ' 'Possible values are: %s' % (level, levels_repr)) messages.add_message(request, level, message, extra_tags=extra_tags, fail_silently=fail_silently)
def queryset(
*args, **kwargs)
def wrapped(*args, **kwargs): warnings.warn( "`%s.%s` is deprecated, use `%s` instead." % (self.class_name, self.old_method_name, self.new_method_name), self.deprecation_warning, 2) return f(*args, **kwargs)
def render_change_form(
self, request, context, add=False, change=False, form_url='', obj=None)
def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None): opts = self.model._meta app_label = opts.app_label preserved_filters = self.get_preserved_filters(request) form_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, form_url) context.update({ 'add': add, 'change': change, 'has_add_permission': self.has_add_permission(request), 'has_change_permission': self.has_change_permission(request, obj), 'has_delete_permission': self.has_delete_permission(request, obj), 'has_file_field': True, # FIXME - this should check if form or formsets have a FileField, 'has_absolute_url': hasattr(self.model, 'get_absolute_url'), 'form_url': form_url, 'opts': opts, 'content_type_id': ContentType.objects.get_for_model(self.model).id, 'save_as': self.save_as, 'save_on_top': self.save_on_top, }) if add and self.add_form_template is not None: form_template = self.add_form_template else: form_template = self.change_form_template return TemplateResponse(request, form_template or [ "admin/%s/%s/change_form.html" % (app_label, opts.model_name), "admin/%s/change_form.html" % app_label, "admin/change_form.html" ], context, current_app=self.admin_site.name)
def response_action(
self, request, queryset)
Handle an admin action. This is called if a request is POSTed to the changelist; it returns an HttpResponse if the action was handled, and None otherwise.
def response_action(self, request, queryset): """ Handle an admin action. This is called if a request is POSTed to the changelist; it returns an HttpResponse if the action was handled, and None otherwise. """ # There can be multiple action forms on the page (at the top # and bottom of the change list, for example). Get the action # whose button was pushed. try: action_index = int(request.POST.get('index', 0)) except ValueError: action_index = 0 # Construct the action form. data = request.POST.copy() data.pop(helpers.ACTION_CHECKBOX_NAME, None) data.pop("index", None) # Use the action whose button was pushed try: data.update({'action': data.getlist('action')[action_index]}) except IndexError: # If we didn't get an action from the chosen form that's invalid # POST data, so by deleting action it'll fail the validation check # below. So no need to do anything here pass action_form = self.action_form(data, auto_id=None) action_form.fields['action'].choices = self.get_action_choices(request) # If the form's valid we can handle the action. if action_form.is_valid(): action = action_form.cleaned_data['action'] select_across = action_form.cleaned_data['select_across'] func = self.get_actions(request)[action][0] # Get the list of selected PKs. If nothing's selected, we can't # perform an action on it, so bail. Except we want to perform # the action explicitly on all objects. selected = request.POST.getlist(helpers.ACTION_CHECKBOX_NAME) if not selected and not select_across: # Reminder that something needs to be selected or nothing will happen msg = _("Items must be selected in order to perform " "actions on them. No items have been changed.") self.message_user(request, msg, messages.WARNING) return None if not select_across: # Perform the action only on the selected objects queryset = queryset.filter(pk__in=selected) response = func(self, request, queryset) # Actions may return an HttpResponse-like object, which will be # used as the response from the POST. If not, we'll be a good # little HTTP citizen and redirect back to the changelist page. if isinstance(response, HttpResponseBase): return response else: return HttpResponseRedirect(request.get_full_path()) else: msg = _("No action selected.") self.message_user(request, msg, messages.WARNING) return None
def response_add(
self, request, obj, post_url_continue=None)
Determines the HttpResponse for the add_view stage.
def response_add(self, request, obj, post_url_continue=None): """ Determines the HttpResponse for the add_view stage. """ opts = obj._meta pk_value = obj._get_pk_val() preserved_filters = self.get_preserved_filters(request) msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)} # Here, we distinguish between different save types by checking for # the presence of keys in request.POST. if IS_POPUP_VAR in request.POST: return SimpleTemplateResponse('admin/popup_response.html', { 'pk_value': escape(pk_value), 'obj': escapejs(obj) }) elif "_continue" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) if post_url_continue is None: post_url_continue = reverse('admin:%s_%s_change' % (opts.app_label, opts.model_name), args=(pk_value,), current_app=self.admin_site.name) post_url_continue = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url_continue) return HttpResponseRedirect(post_url_continue) elif "_addanother" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may add another %(name)s below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = request.path redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) else: msg = _('The %(name)s "%(obj)s" was added successfully.') % msg_dict self.message_user(request, msg, messages.SUCCESS) return self.response_post_save_add(request, obj)
def response_change(
self, request, obj)
Determines the HttpResponse for the change_view stage.
def response_change(self, request, obj): """ Determines the HttpResponse for the change_view stage. """ opts = self.model._meta pk_value = obj._get_pk_val() preserved_filters = self.get_preserved_filters(request) msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)} if "_continue" in request.POST: msg = _('The %(name)s "%(obj)s" was changed successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = request.path redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) elif "_saveasnew" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = reverse('admin:%s_%s_change' % (opts.app_label, opts.model_name), args=(pk_value,), current_app=self.admin_site.name) redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) elif "_addanother" in request.POST: msg = _('The %(name)s "%(obj)s" was changed successfully. You may add another %(name)s below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = reverse('admin:%s_%s_add' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) else: msg = _('The %(name)s "%(obj)s" was changed successfully.') % msg_dict self.message_user(request, msg, messages.SUCCESS) return self.response_post_save_change(request, obj)
def response_post_save_add(
self, request, obj)
Figure out where to redirect after the 'Save' button has been pressed when adding a new object.
def response_post_save_add(self, request, obj): """ Figure out where to redirect after the 'Save' button has been pressed when adding a new object. """ opts = self.model._meta if self.has_change_permission(request, None): post_url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url) else: post_url = reverse('admin:index', current_app=self.admin_site.name) return HttpResponseRedirect(post_url)
def response_post_save_change(
self, request, obj)
Figure out where to redirect after the 'Save' button has been pressed when editing an existing object.
def response_post_save_change(self, request, obj): """ Figure out where to redirect after the 'Save' button has been pressed when editing an existing object. """ opts = self.model._meta if self.has_change_permission(request, None): post_url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url) else: post_url = reverse('admin:index', current_app=self.admin_site.name) return HttpResponseRedirect(post_url)
def save_form(
self, request, form, change)
Given a ModelForm return an unsaved instance. change
is True if
the object is being changed, and False if it's being added.
def save_form(self, request, form, change): """ Given a ModelForm return an unsaved instance. ``change`` is True if the object is being changed, and False if it's being added. """ return form.save(commit=False)
def save_formset(
self, request, form, formset, change)
Given an inline formset save it to the database.
def save_formset(self, request, form, formset, change): """ Given an inline formset save it to the database. """ formset.save()
def save_model(
self, request, obj, form, change)
Given a model instance save it to the database.
def save_model(self, request, obj, form, change): """ Given a model instance save it to the database. """ obj.save()
Given the HttpRequest
, the parent ModelForm
instance, the
list of inline formsets and a boolean value based on whether the
parent is being added or changed, save the related objects to the
database. Note that at this point save_form() and save_model() have
already been called.
def to_field_allowed(
self, request, to_field)
Returns True if the model associated with this admin should be allowed to be referenced by the specified field.
def to_field_allowed(self, request, to_field): """ Returns True if the model associated with this admin should be allowed to be referenced by the specified field. """ opts = self.model._meta try: field = opts.get_field(to_field) except FieldDoesNotExist: return False # Always allow referencing the primary key since it's already possible # to get this information from the change view URL. if field.primary_key: return True # Make sure at least one of the models registered for this site # references this field through a FK or a M2M relationship. registered_models = set() for model, admin in self.admin_site._registry.items(): registered_models.add(model) for inline in admin.inlines: registered_models.add(inline.model) for related_object in opts.get_all_related_objects(include_hidden=True): related_model = related_object.model if (any(issubclass(model, related_model) for model in registered_models) and related_object.field.rel.get_related_field() == field): return True return False
def validate(
cls, model)
@classmethod def validate(cls, model): validator = cls.validator_class() validator.validate(cls, model)
class MediaCollectionIdentifierInline
class MediaCollectionIdentifierInline(admin.StackedInline): model = MediaCollectionIdentifier max_num = 1
Ancestors (in MRO)
- MediaCollectionIdentifierInline
- django.contrib.admin.options.StackedInline
- django.contrib.admin.options.InlineModelAdmin
- django.contrib.admin.options.BaseModelAdmin
- __builtin__.object
Class variables
var can_delete
var exclude
var extra
var fields
var fieldsets
var filter_horizontal
var filter_vertical
var fk_name
var form
var formfield_overrides
var formset
var max_num
var model
var ordering
var prepopulated_fields
var radio_fields
var raw_id_fields
var readonly_fields
var template
var validator_class
var verbose_name
var verbose_name_plural
Instance variables
var declared_fieldsets
var media
Methods
def __init__(
self, parent_model, admin_site)
def __init__(self, parent_model, admin_site): self.admin_site = admin_site self.parent_model = parent_model self.opts = self.model._meta super(InlineModelAdmin, self).__init__() if self.verbose_name is None: self.verbose_name = self.model._meta.verbose_name if self.verbose_name_plural is None: self.verbose_name_plural = self.model._meta.verbose_name_plural
def formfield_for_choice_field(
self, db_field, request=None, **kwargs)
Get a form Field for a database Field that has declared choices.
def formfield_for_choice_field(self, db_field, request=None, **kwargs): """ Get a form Field for a database Field that has declared choices. """ # If the field is named as a radio_field, use a RadioSelect if db_field.name in self.radio_fields: # Avoid stomping on custom widget/choices arguments. if 'widget' not in kwargs: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) if 'choices' not in kwargs: kwargs['choices'] = db_field.get_choices( include_blank=db_field.blank, blank_choice=[('', _('None'))] ) return db_field.formfield(**kwargs)
def formfield_for_dbfield(
self, db_field, **kwargs)
Hook for specifying the form Field instance for a given database Field instance.
If kwargs are given, they're passed to the form Field's constructor.
def formfield_for_dbfield(self, db_field, **kwargs): """ Hook for specifying the form Field instance for a given database Field instance. If kwargs are given, they're passed to the form Field's constructor. """ request = kwargs.pop("request", None) # If the field specifies choices, we don't need to look for special # admin widgets - we just need to use a select widget of some kind. if db_field.choices: return self.formfield_for_choice_field(db_field, request, **kwargs) # ForeignKey or ManyToManyFields if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)): # Combine the field kwargs with any options for formfield_overrides. # Make sure the passed in **kwargs override anything in # formfield_overrides because **kwargs is more specific, and should # always win. if db_field.__class__ in self.formfield_overrides: kwargs = dict(self.formfield_overrides[db_field.__class__], **kwargs) # Get the correct formfield. if isinstance(db_field, models.ForeignKey): formfield = self.formfield_for_foreignkey(db_field, request, **kwargs) elif isinstance(db_field, models.ManyToManyField): formfield = self.formfield_for_manytomany(db_field, request, **kwargs) # For non-raw_id fields, wrap the widget with a wrapper that adds # extra HTML -- the "add other" interface -- to the end of the # rendered output. formfield can be None if it came from a # OneToOneField with parent_link=True or a M2M intermediary. if formfield and db_field.name not in self.raw_id_fields: related_modeladmin = self.admin_site._registry.get( db_field.rel.to) can_add_related = bool(related_modeladmin and related_modeladmin.has_add_permission(request)) formfield.widget = widgets.RelatedFieldWidgetWrapper( formfield.widget, db_field.rel, self.admin_site, can_add_related=can_add_related) return formfield # If we've got overrides for the formfield defined, use 'em. **kwargs # passed to formfield_for_dbfield override the defaults. for klass in db_field.__class__.mro(): if klass in self.formfield_overrides: kwargs = dict(copy.deepcopy(self.formfield_overrides[klass]), **kwargs) return db_field.formfield(**kwargs) # For any other type of field, just call its formfield() method. return db_field.formfield(**kwargs)
def formfield_for_foreignkey(
self, db_field, request=None, **kwargs)
Get a form Field for a ForeignKey.
def formfield_for_foreignkey(self, db_field, request=None, **kwargs): """ Get a form Field for a ForeignKey. """ db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel, self.admin_site, using=db) elif db_field.name in self.radio_fields: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) kwargs['empty_label'] = _('None') if db_field.blank else None if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def formfield_for_manytomany(
self, db_field, request=None, **kwargs)
Get a form Field for a ManyToManyField.
def formfield_for_manytomany(self, db_field, request=None, **kwargs): """ Get a form Field for a ManyToManyField. """ # If it uses an intermediary model that isn't auto created, don't show # a field in admin. if not db_field.rel.through._meta.auto_created: return None db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel, self.admin_site, using=db) kwargs['help_text'] = '' elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)): kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical)) if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def get_extra(
self, request, obj=None, **kwargs)
Hook for customizing the number of extra inline forms.
def get_extra(self, request, obj=None, **kwargs): """Hook for customizing the number of extra inline forms.""" return self.extra
def get_field_queryset(
self, db, db_field, request)
If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case).
def get_field_queryset(self, db, db_field, request): """ If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case). """ related_admin = self.admin_site._registry.get(db_field.rel.to, None) if related_admin is not None: ordering = related_admin.get_ordering(request) if ordering is not None and ordering != (): return db_field.rel.to._default_manager.using(db).order_by(*ordering).complex_filter(db_field.rel.limit_choices_to) return None
def get_fieldsets(
self, request, obj=None)
def get_fieldsets(self, request, obj=None): if self.declared_fieldsets: return self.declared_fieldsets form = self.get_formset(request, obj, fields=None).form fields = list(form.base_fields) + list(self.get_readonly_fields(request, obj)) return [(None, {'fields': fields})]
def get_formset(
self, request, obj=None, **kwargs)
Returns a BaseInlineFormSet class for use in admin add/change views.
def get_formset(self, request, obj=None, **kwargs): """Returns a BaseInlineFormSet class for use in admin add/change views.""" if 'fields' in kwargs: fields = kwargs.pop('fields') else: fields = flatten_fieldsets(self.get_fieldsets(request, obj)) if self.exclude is None: exclude = [] else: exclude = list(self.exclude) exclude.extend(self.get_readonly_fields(request, obj)) if self.exclude is None and hasattr(self.form, '_meta') and self.form._meta.exclude: # Take the custom ModelForm's Meta.exclude into account only if the # InlineModelAdmin doesn't define its own. exclude.extend(self.form._meta.exclude) # If exclude is an empty list we use None, since that's the actual # default. exclude = exclude or None can_delete = self.can_delete and self.has_delete_permission(request, obj) defaults = { "form": self.form, "formset": self.formset, "fk_name": self.fk_name, "fields": fields, "exclude": exclude, "formfield_callback": partial(self.formfield_for_dbfield, request=request), "extra": self.get_extra(request, obj, **kwargs), "max_num": self.get_max_num(request, obj, **kwargs), "can_delete": can_delete, } defaults.update(kwargs) base_model_form = defaults['form'] class DeleteProtectedModelForm(base_model_form): def hand_clean_DELETE(self): """ We don't validate the 'DELETE' field itself because on templates it's not rendered using the field information, but just using a generic "deletion_field" of the InlineModelAdmin. """ if self.cleaned_data.get(DELETION_FIELD_NAME, False): using = router.db_for_write(self._meta.model) collector = NestedObjects(using=using) collector.collect([self.instance]) if collector.protected: objs = [] for p in collector.protected: objs.append( # Translators: Model verbose name and instance representation, suitable to be an item in a list _('%(class_name)s %(instance)s') % { 'class_name': p._meta.verbose_name, 'instance': p} ) params = {'class_name': self._meta.model._meta.verbose_name, 'instance': self.instance, 'related_objects': get_text_list(objs, _('and'))} msg = _("Deleting %(class_name)s %(instance)s would require " "deleting the following protected related objects: " "%(related_objects)s") raise ValidationError(msg, code='deleting_protected', params=params) def is_valid(self): result = super(DeleteProtectedModelForm, self).is_valid() self.hand_clean_DELETE() return result defaults['form'] = DeleteProtectedModelForm if defaults['fields'] is None and not modelform_defines_fields(defaults['form']): defaults['fields'] = forms.ALL_FIELDS return inlineformset_factory(self.parent_model, self.model, **defaults)
def get_max_num(
self, request, obj=None, **kwargs)
Hook for customizing the max number of extra inline forms.
def get_max_num(self, request, obj=None, **kwargs): """Hook for customizing the max number of extra inline forms.""" return self.max_num
def get_ordering(
self, request)
Hook for specifying field ordering.
def get_ordering(self, request): """ Hook for specifying field ordering. """ return self.ordering or () # otherwise we might try to *None, which is bad ;)
def get_prepopulated_fields(
self, request, obj=None)
Hook for specifying custom prepopulated fields.
def get_prepopulated_fields(self, request, obj=None): """ Hook for specifying custom prepopulated fields. """ return self.prepopulated_fields
def get_queryset(
self, request)
def get_queryset(self, request): queryset = super(InlineModelAdmin, self).get_queryset(request) if not self.has_change_permission(request): queryset = queryset.none() return queryset
def get_readonly_fields(
self, request, obj=None)
Hook for specifying custom readonly fields.
def get_readonly_fields(self, request, obj=None): """ Hook for specifying custom readonly fields. """ return self.readonly_fields
def has_add_permission(
self, request)
def has_add_permission(self, request): if self.opts.auto_created: # We're checking the rights to an auto-created intermediate model, # which doesn't have its own individual permissions. The user needs # to have the change permission for the related model in order to # be able to do anything with the intermediate model. return self.has_change_permission(request) return super(InlineModelAdmin, self).has_add_permission(request)
def has_change_permission(
self, request, obj=None)
def has_change_permission(self, request, obj=None): opts = self.opts if opts.auto_created: # The model was auto-created as intermediary for a # ManyToMany-relationship, find the target model for field in opts.fields: if field.rel and field.rel.to != self.parent_model: opts = field.rel.to._meta break codename = get_permission_codename('change', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_delete_permission(
self, request, obj=None)
def has_delete_permission(self, request, obj=None): if self.opts.auto_created: # We're checking the rights to an auto-created intermediate model, # which doesn't have its own individual permissions. The user needs # to have the change permission for the related model in order to # be able to do anything with the intermediate model. return self.has_change_permission(request, obj) return super(InlineModelAdmin, self).has_delete_permission(request, obj)
def lookup_allowed(
self, lookup, value)
def lookup_allowed(self, lookup, value): model = self.model # Check FKey lookups that are allowed, so that popups produced by # ForeignKeyRawIdWidget, on the basis of ForeignKey.limit_choices_to, # are allowed to work. for l in model._meta.related_fkey_lookups: for k, v in widgets.url_params_from_lookup_dict(l).items(): if k == lookup and v == value: return True parts = lookup.split(LOOKUP_SEP) # Last term in lookup is a query term (__exact, __startswith etc) # This term can be ignored. if len(parts) > 1 and parts[-1] in QUERY_TERMS: parts.pop() # Special case -- foo__id__exact and foo__id queries are implied # if foo has been specifically included in the lookup list; so # drop __id if it is the last part. However, first we need to find # the pk attribute name. rel_name = None for part in parts[:-1]: try: field, _, _, _ = model._meta.get_field_by_name(part) except FieldDoesNotExist: # Lookups on non-existent fields are ok, since they're ignored # later. return True if hasattr(field, 'rel'): if field.rel is None: # This property or relation doesn't exist, but it's allowed # since it's ignored in ChangeList.get_filters(). return True model = field.rel.to rel_name = field.rel.get_related_field().name elif isinstance(field, RelatedObject): model = field.model rel_name = model._meta.pk.name else: rel_name = None if rel_name and len(parts) > 1 and parts[-1] == rel_name: parts.pop() if len(parts) == 1: return True clean_lookup = LOOKUP_SEP.join(parts) return clean_lookup in self.list_filter or clean_lookup == self.date_hierarchy
def queryset(
*args, **kwargs)
def wrapped(*args, **kwargs): warnings.warn( "`%s.%s` is deprecated, use `%s` instead." % (self.class_name, self.old_method_name, self.new_method_name), self.deprecation_warning, 2) return f(*args, **kwargs)
def to_field_allowed(
self, request, to_field)
Returns True if the model associated with this admin should be allowed to be referenced by the specified field.
def to_field_allowed(self, request, to_field): """ Returns True if the model associated with this admin should be allowed to be referenced by the specified field. """ opts = self.model._meta try: field = opts.get_field(to_field) except FieldDoesNotExist: return False # Always allow referencing the primary key since it's already possible # to get this information from the change view URL. if field.primary_key: return True # Make sure at least one of the models registered for this site # references this field through a FK or a M2M relationship. registered_models = set() for model, admin in self.admin_site._registry.items(): registered_models.add(model) for inline in admin.inlines: registered_models.add(inline.model) for related_object in opts.get_all_related_objects(include_hidden=True): related_model = related_object.model if (any(issubclass(model, related_model) for model in registered_models) and related_object.field.rel.get_related_field() == field): return True return False
def validate(
cls, model)
@classmethod def validate(cls, model): validator = cls.validator_class() validator.validate(cls, model)
class MediaCollectionRelatedInline
class MediaCollectionRelatedInline(admin.StackedInline): model = MediaCollectionRelated
Ancestors (in MRO)
- MediaCollectionRelatedInline
- django.contrib.admin.options.StackedInline
- django.contrib.admin.options.InlineModelAdmin
- django.contrib.admin.options.BaseModelAdmin
- __builtin__.object
Class variables
var can_delete
var exclude
var extra
var fields
var fieldsets
var filter_horizontal
var filter_vertical
var fk_name
var form
var formfield_overrides
var formset
var max_num
var model
var ordering
var prepopulated_fields
var radio_fields
var raw_id_fields
var readonly_fields
var template
var validator_class
var verbose_name
var verbose_name_plural
Instance variables
var declared_fieldsets
var media
Methods
def __init__(
self, parent_model, admin_site)
def __init__(self, parent_model, admin_site): self.admin_site = admin_site self.parent_model = parent_model self.opts = self.model._meta super(InlineModelAdmin, self).__init__() if self.verbose_name is None: self.verbose_name = self.model._meta.verbose_name if self.verbose_name_plural is None: self.verbose_name_plural = self.model._meta.verbose_name_plural
def formfield_for_choice_field(
self, db_field, request=None, **kwargs)
Get a form Field for a database Field that has declared choices.
def formfield_for_choice_field(self, db_field, request=None, **kwargs): """ Get a form Field for a database Field that has declared choices. """ # If the field is named as a radio_field, use a RadioSelect if db_field.name in self.radio_fields: # Avoid stomping on custom widget/choices arguments. if 'widget' not in kwargs: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) if 'choices' not in kwargs: kwargs['choices'] = db_field.get_choices( include_blank=db_field.blank, blank_choice=[('', _('None'))] ) return db_field.formfield(**kwargs)
def formfield_for_dbfield(
self, db_field, **kwargs)
Hook for specifying the form Field instance for a given database Field instance.
If kwargs are given, they're passed to the form Field's constructor.
def formfield_for_dbfield(self, db_field, **kwargs): """ Hook for specifying the form Field instance for a given database Field instance. If kwargs are given, they're passed to the form Field's constructor. """ request = kwargs.pop("request", None) # If the field specifies choices, we don't need to look for special # admin widgets - we just need to use a select widget of some kind. if db_field.choices: return self.formfield_for_choice_field(db_field, request, **kwargs) # ForeignKey or ManyToManyFields if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)): # Combine the field kwargs with any options for formfield_overrides. # Make sure the passed in **kwargs override anything in # formfield_overrides because **kwargs is more specific, and should # always win. if db_field.__class__ in self.formfield_overrides: kwargs = dict(self.formfield_overrides[db_field.__class__], **kwargs) # Get the correct formfield. if isinstance(db_field, models.ForeignKey): formfield = self.formfield_for_foreignkey(db_field, request, **kwargs) elif isinstance(db_field, models.ManyToManyField): formfield = self.formfield_for_manytomany(db_field, request, **kwargs) # For non-raw_id fields, wrap the widget with a wrapper that adds # extra HTML -- the "add other" interface -- to the end of the # rendered output. formfield can be None if it came from a # OneToOneField with parent_link=True or a M2M intermediary. if formfield and db_field.name not in self.raw_id_fields: related_modeladmin = self.admin_site._registry.get( db_field.rel.to) can_add_related = bool(related_modeladmin and related_modeladmin.has_add_permission(request)) formfield.widget = widgets.RelatedFieldWidgetWrapper( formfield.widget, db_field.rel, self.admin_site, can_add_related=can_add_related) return formfield # If we've got overrides for the formfield defined, use 'em. **kwargs # passed to formfield_for_dbfield override the defaults. for klass in db_field.__class__.mro(): if klass in self.formfield_overrides: kwargs = dict(copy.deepcopy(self.formfield_overrides[klass]), **kwargs) return db_field.formfield(**kwargs) # For any other type of field, just call its formfield() method. return db_field.formfield(**kwargs)
def formfield_for_foreignkey(
self, db_field, request=None, **kwargs)
Get a form Field for a ForeignKey.
def formfield_for_foreignkey(self, db_field, request=None, **kwargs): """ Get a form Field for a ForeignKey. """ db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel, self.admin_site, using=db) elif db_field.name in self.radio_fields: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) kwargs['empty_label'] = _('None') if db_field.blank else None if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def formfield_for_manytomany(
self, db_field, request=None, **kwargs)
Get a form Field for a ManyToManyField.
def formfield_for_manytomany(self, db_field, request=None, **kwargs): """ Get a form Field for a ManyToManyField. """ # If it uses an intermediary model that isn't auto created, don't show # a field in admin. if not db_field.rel.through._meta.auto_created: return None db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel, self.admin_site, using=db) kwargs['help_text'] = '' elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)): kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical)) if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def get_extra(
self, request, obj=None, **kwargs)
Hook for customizing the number of extra inline forms.
def get_extra(self, request, obj=None, **kwargs): """Hook for customizing the number of extra inline forms.""" return self.extra
def get_field_queryset(
self, db, db_field, request)
If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case).
def get_field_queryset(self, db, db_field, request): """ If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case). """ related_admin = self.admin_site._registry.get(db_field.rel.to, None) if related_admin is not None: ordering = related_admin.get_ordering(request) if ordering is not None and ordering != (): return db_field.rel.to._default_manager.using(db).order_by(*ordering).complex_filter(db_field.rel.limit_choices_to) return None
def get_fieldsets(
self, request, obj=None)
def get_fieldsets(self, request, obj=None): if self.declared_fieldsets: return self.declared_fieldsets form = self.get_formset(request, obj, fields=None).form fields = list(form.base_fields) + list(self.get_readonly_fields(request, obj)) return [(None, {'fields': fields})]
def get_formset(
self, request, obj=None, **kwargs)
Returns a BaseInlineFormSet class for use in admin add/change views.
def get_formset(self, request, obj=None, **kwargs): """Returns a BaseInlineFormSet class for use in admin add/change views.""" if 'fields' in kwargs: fields = kwargs.pop('fields') else: fields = flatten_fieldsets(self.get_fieldsets(request, obj)) if self.exclude is None: exclude = [] else: exclude = list(self.exclude) exclude.extend(self.get_readonly_fields(request, obj)) if self.exclude is None and hasattr(self.form, '_meta') and self.form._meta.exclude: # Take the custom ModelForm's Meta.exclude into account only if the # InlineModelAdmin doesn't define its own. exclude.extend(self.form._meta.exclude) # If exclude is an empty list we use None, since that's the actual # default. exclude = exclude or None can_delete = self.can_delete and self.has_delete_permission(request, obj) defaults = { "form": self.form, "formset": self.formset, "fk_name": self.fk_name, "fields": fields, "exclude": exclude, "formfield_callback": partial(self.formfield_for_dbfield, request=request), "extra": self.get_extra(request, obj, **kwargs), "max_num": self.get_max_num(request, obj, **kwargs), "can_delete": can_delete, } defaults.update(kwargs) base_model_form = defaults['form'] class DeleteProtectedModelForm(base_model_form): def hand_clean_DELETE(self): """ We don't validate the 'DELETE' field itself because on templates it's not rendered using the field information, but just using a generic "deletion_field" of the InlineModelAdmin. """ if self.cleaned_data.get(DELETION_FIELD_NAME, False): using = router.db_for_write(self._meta.model) collector = NestedObjects(using=using) collector.collect([self.instance]) if collector.protected: objs = [] for p in collector.protected: objs.append( # Translators: Model verbose name and instance representation, suitable to be an item in a list _('%(class_name)s %(instance)s') % { 'class_name': p._meta.verbose_name, 'instance': p} ) params = {'class_name': self._meta.model._meta.verbose_name, 'instance': self.instance, 'related_objects': get_text_list(objs, _('and'))} msg = _("Deleting %(class_name)s %(instance)s would require " "deleting the following protected related objects: " "%(related_objects)s") raise ValidationError(msg, code='deleting_protected', params=params) def is_valid(self): result = super(DeleteProtectedModelForm, self).is_valid() self.hand_clean_DELETE() return result defaults['form'] = DeleteProtectedModelForm if defaults['fields'] is None and not modelform_defines_fields(defaults['form']): defaults['fields'] = forms.ALL_FIELDS return inlineformset_factory(self.parent_model, self.model, **defaults)
def get_max_num(
self, request, obj=None, **kwargs)
Hook for customizing the max number of extra inline forms.
def get_max_num(self, request, obj=None, **kwargs): """Hook for customizing the max number of extra inline forms.""" return self.max_num
def get_ordering(
self, request)
Hook for specifying field ordering.
def get_ordering(self, request): """ Hook for specifying field ordering. """ return self.ordering or () # otherwise we might try to *None, which is bad ;)
def get_prepopulated_fields(
self, request, obj=None)
Hook for specifying custom prepopulated fields.
def get_prepopulated_fields(self, request, obj=None): """ Hook for specifying custom prepopulated fields. """ return self.prepopulated_fields
def get_queryset(
self, request)
def get_queryset(self, request): queryset = super(InlineModelAdmin, self).get_queryset(request) if not self.has_change_permission(request): queryset = queryset.none() return queryset
def get_readonly_fields(
self, request, obj=None)
Hook for specifying custom readonly fields.
def get_readonly_fields(self, request, obj=None): """ Hook for specifying custom readonly fields. """ return self.readonly_fields
def has_add_permission(
self, request)
def has_add_permission(self, request): if self.opts.auto_created: # We're checking the rights to an auto-created intermediate model, # which doesn't have its own individual permissions. The user needs # to have the change permission for the related model in order to # be able to do anything with the intermediate model. return self.has_change_permission(request) return super(InlineModelAdmin, self).has_add_permission(request)
def has_change_permission(
self, request, obj=None)
def has_change_permission(self, request, obj=None): opts = self.opts if opts.auto_created: # The model was auto-created as intermediary for a # ManyToMany-relationship, find the target model for field in opts.fields: if field.rel and field.rel.to != self.parent_model: opts = field.rel.to._meta break codename = get_permission_codename('change', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_delete_permission(
self, request, obj=None)
def has_delete_permission(self, request, obj=None): if self.opts.auto_created: # We're checking the rights to an auto-created intermediate model, # which doesn't have its own individual permissions. The user needs # to have the change permission for the related model in order to # be able to do anything with the intermediate model. return self.has_change_permission(request, obj) return super(InlineModelAdmin, self).has_delete_permission(request, obj)
def lookup_allowed(
self, lookup, value)
def lookup_allowed(self, lookup, value): model = self.model # Check FKey lookups that are allowed, so that popups produced by # ForeignKeyRawIdWidget, on the basis of ForeignKey.limit_choices_to, # are allowed to work. for l in model._meta.related_fkey_lookups: for k, v in widgets.url_params_from_lookup_dict(l).items(): if k == lookup and v == value: return True parts = lookup.split(LOOKUP_SEP) # Last term in lookup is a query term (__exact, __startswith etc) # This term can be ignored. if len(parts) > 1 and parts[-1] in QUERY_TERMS: parts.pop() # Special case -- foo__id__exact and foo__id queries are implied # if foo has been specifically included in the lookup list; so # drop __id if it is the last part. However, first we need to find # the pk attribute name. rel_name = None for part in parts[:-1]: try: field, _, _, _ = model._meta.get_field_by_name(part) except FieldDoesNotExist: # Lookups on non-existent fields are ok, since they're ignored # later. return True if hasattr(field, 'rel'): if field.rel is None: # This property or relation doesn't exist, but it's allowed # since it's ignored in ChangeList.get_filters(). return True model = field.rel.to rel_name = field.rel.get_related_field().name elif isinstance(field, RelatedObject): model = field.model rel_name = model._meta.pk.name else: rel_name = None if rel_name and len(parts) > 1 and parts[-1] == rel_name: parts.pop() if len(parts) == 1: return True clean_lookup = LOOKUP_SEP.join(parts) return clean_lookup in self.list_filter or clean_lookup == self.date_hierarchy
def queryset(
*args, **kwargs)
def wrapped(*args, **kwargs): warnings.warn( "`%s.%s` is deprecated, use `%s` instead." % (self.class_name, self.old_method_name, self.new_method_name), self.deprecation_warning, 2) return f(*args, **kwargs)
def to_field_allowed(
self, request, to_field)
Returns True if the model associated with this admin should be allowed to be referenced by the specified field.
def to_field_allowed(self, request, to_field): """ Returns True if the model associated with this admin should be allowed to be referenced by the specified field. """ opts = self.model._meta try: field = opts.get_field(to_field) except FieldDoesNotExist: return False # Always allow referencing the primary key since it's already possible # to get this information from the change view URL. if field.primary_key: return True # Make sure at least one of the models registered for this site # references this field through a FK or a M2M relationship. registered_models = set() for model, admin in self.admin_site._registry.items(): registered_models.add(model) for inline in admin.inlines: registered_models.add(inline.model) for related_object in opts.get_all_related_objects(include_hidden=True): related_model = related_object.model if (any(issubclass(model, related_model) for model in registered_models) and related_object.field.rel.get_related_field() == field): return True return False
def validate(
cls, model)
@classmethod def validate(cls, model): validator = cls.validator_class() validator.validate(cls, model)
class MediaCorpusAdmin
class MediaCorpusAdmin(admin.ModelAdmin): search_fields = ['title', 'code'] ordering = ['code'] filter_horizontal = ['children']
Ancestors (in MRO)
- MediaCorpusAdmin
- django.contrib.admin.options.ModelAdmin
- django.contrib.admin.options.BaseModelAdmin
- __builtin__.object
Class variables
var action_form
var actions
var actions_on_bottom
var actions_on_top
var actions_selection_counter
var add_form_template
var change_form_template
var change_list_template
var date_hierarchy
var delete_confirmation_template
var delete_selected_confirmation_template
var exclude
var fields
var fieldsets
var filter_horizontal
var filter_vertical
var form
var formfield_overrides
var inlines
var list_display
var list_display_links
var list_editable
var list_filter
var list_max_show_all
var list_per_page
var object_history_template
var ordering
var paginator
var prepopulated_fields
var preserve_filters
var radio_fields
var raw_id_fields
var readonly_fields
var save_as
var save_on_top
var search_fields
var validator_class
Instance variables
var declared_fieldsets
var media
var urls
Methods
def __init__(
self, model, admin_site)
def __init__(self, model, admin_site): self.model = model self.opts = model._meta self.admin_site = admin_site super(ModelAdmin, self).__init__()
def action_checkbox(
self, obj)
A list_display column containing a checkbox widget.
def action_checkbox(self, obj): """ A list_display column containing a checkbox widget. """ return helpers.checkbox.render(helpers.ACTION_CHECKBOX_NAME, force_text(obj.pk))
def add_view(
self, *args, **kwargs)
The 'add' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def change_view(
self, *args, **kwargs)
The 'change' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def changelist_view(
self, *args, **kwargs)
The 'change list' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def construct_change_message(
self, request, form, formsets)
Construct a change message from a changed object.
def construct_change_message(self, request, form, formsets): """ Construct a change message from a changed object. """ change_message = [] if form.changed_data: change_message.append(_('Changed %s.') % get_text_list(form.changed_data, _('and'))) if formsets: for formset in formsets: for added_object in formset.new_objects: change_message.append(_('Added %(name)s "%(object)s".') % {'name': force_text(added_object._meta.verbose_name), 'object': force_text(added_object)}) for changed_object, changed_fields in formset.changed_objects: change_message.append(_('Changed %(list)s for %(name)s "%(object)s".') % {'list': get_text_list(changed_fields, _('and')), 'name': force_text(changed_object._meta.verbose_name), 'object': force_text(changed_object)}) for deleted_object in formset.deleted_objects: change_message.append(_('Deleted %(name)s "%(object)s".') % {'name': force_text(deleted_object._meta.verbose_name), 'object': force_text(deleted_object)}) change_message = ' '.join(change_message) return change_message or _('No fields changed.')
def delete_model(
self, request, obj)
Given a model instance delete it from the database.
def delete_model(self, request, obj): """ Given a model instance delete it from the database. """ obj.delete()
def delete_view(
self, *args, **kwargs)
The 'delete' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def formfield_for_choice_field(
self, db_field, request=None, **kwargs)
Get a form Field for a database Field that has declared choices.
def formfield_for_choice_field(self, db_field, request=None, **kwargs): """ Get a form Field for a database Field that has declared choices. """ # If the field is named as a radio_field, use a RadioSelect if db_field.name in self.radio_fields: # Avoid stomping on custom widget/choices arguments. if 'widget' not in kwargs: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) if 'choices' not in kwargs: kwargs['choices'] = db_field.get_choices( include_blank=db_field.blank, blank_choice=[('', _('None'))] ) return db_field.formfield(**kwargs)
def formfield_for_dbfield(
self, db_field, **kwargs)
Hook for specifying the form Field instance for a given database Field instance.
If kwargs are given, they're passed to the form Field's constructor.
def formfield_for_dbfield(self, db_field, **kwargs): """ Hook for specifying the form Field instance for a given database Field instance. If kwargs are given, they're passed to the form Field's constructor. """ request = kwargs.pop("request", None) # If the field specifies choices, we don't need to look for special # admin widgets - we just need to use a select widget of some kind. if db_field.choices: return self.formfield_for_choice_field(db_field, request, **kwargs) # ForeignKey or ManyToManyFields if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)): # Combine the field kwargs with any options for formfield_overrides. # Make sure the passed in **kwargs override anything in # formfield_overrides because **kwargs is more specific, and should # always win. if db_field.__class__ in self.formfield_overrides: kwargs = dict(self.formfield_overrides[db_field.__class__], **kwargs) # Get the correct formfield. if isinstance(db_field, models.ForeignKey): formfield = self.formfield_for_foreignkey(db_field, request, **kwargs) elif isinstance(db_field, models.ManyToManyField): formfield = self.formfield_for_manytomany(db_field, request, **kwargs) # For non-raw_id fields, wrap the widget with a wrapper that adds # extra HTML -- the "add other" interface -- to the end of the # rendered output. formfield can be None if it came from a # OneToOneField with parent_link=True or a M2M intermediary. if formfield and db_field.name not in self.raw_id_fields: related_modeladmin = self.admin_site._registry.get( db_field.rel.to) can_add_related = bool(related_modeladmin and related_modeladmin.has_add_permission(request)) formfield.widget = widgets.RelatedFieldWidgetWrapper( formfield.widget, db_field.rel, self.admin_site, can_add_related=can_add_related) return formfield # If we've got overrides for the formfield defined, use 'em. **kwargs # passed to formfield_for_dbfield override the defaults. for klass in db_field.__class__.mro(): if klass in self.formfield_overrides: kwargs = dict(copy.deepcopy(self.formfield_overrides[klass]), **kwargs) return db_field.formfield(**kwargs) # For any other type of field, just call its formfield() method. return db_field.formfield(**kwargs)
def formfield_for_foreignkey(
self, db_field, request=None, **kwargs)
Get a form Field for a ForeignKey.
def formfield_for_foreignkey(self, db_field, request=None, **kwargs): """ Get a form Field for a ForeignKey. """ db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel, self.admin_site, using=db) elif db_field.name in self.radio_fields: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) kwargs['empty_label'] = _('None') if db_field.blank else None if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def formfield_for_manytomany(
self, db_field, request=None, **kwargs)
Get a form Field for a ManyToManyField.
def formfield_for_manytomany(self, db_field, request=None, **kwargs): """ Get a form Field for a ManyToManyField. """ # If it uses an intermediary model that isn't auto created, don't show # a field in admin. if not db_field.rel.through._meta.auto_created: return None db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel, self.admin_site, using=db) kwargs['help_text'] = '' elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)): kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical)) if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def get_action(
self, action)
Return a given action from a parameter, which can either be a callable, or the name of a method on the ModelAdmin. Return is a tuple of (callable, name, description).
def get_action(self, action): """ Return a given action from a parameter, which can either be a callable, or the name of a method on the ModelAdmin. Return is a tuple of (callable, name, description). """ # If the action is a callable, just use it. if callable(action): func = action action = action.__name__ # Next, look for a method. Grab it off self.__class__ to get an unbound # method instead of a bound one; this ensures that the calling # conventions are the same for functions and methods. elif hasattr(self.__class__, action): func = getattr(self.__class__, action) # Finally, look for a named method on the admin site else: try: func = self.admin_site.get_action(action) except KeyError: return None if hasattr(func, 'short_description'): description = func.short_description else: description = capfirst(action.replace('_', ' ')) return func, action, description
def get_action_choices(
self, request, default_choices=[(u'', u'---------')])
Return a list of choices for use in a form object. Each choice is a tuple (name, description).
def get_action_choices(self, request, default_choices=BLANK_CHOICE_DASH): """ Return a list of choices for use in a form object. Each choice is a tuple (name, description). """ choices = [] + default_choices for func, name, description in six.itervalues(self.get_actions(request)): choice = (name, description % model_format_dict(self.opts)) choices.append(choice) return choices
def get_actions(
self, request)
Return a dictionary mapping the names of all actions for this ModelAdmin to a tuple of (callable, name, description) for each action.
def get_actions(self, request): """ Return a dictionary mapping the names of all actions for this ModelAdmin to a tuple of (callable, name, description) for each action. """ # If self.actions is explicitly set to None that means that we don't # want *any* actions enabled on this page. from django.contrib.admin.views.main import _is_changelist_popup if self.actions is None or _is_changelist_popup(request): return SortedDict() actions = [] # Gather actions from the admin site first for (name, func) in self.admin_site.actions: description = getattr(func, 'short_description', name.replace('_', ' ')) actions.append((func, name, description)) # Then gather them from the model admin and all parent classes, # starting with self and working back up. for klass in self.__class__.mro()[::-1]: class_actions = getattr(klass, 'actions', []) # Avoid trying to iterate over None if not class_actions: continue actions.extend([self.get_action(action) for action in class_actions]) # get_action might have returned None, so filter any of those out. actions = filter(None, actions) # Convert the actions into a SortedDict keyed by name. actions = SortedDict([ (name, (func, name, desc)) for func, name, desc in actions ]) return actions
def get_changelist(
self, request, **kwargs)
Returns the ChangeList class for use on the changelist page.
def get_changelist(self, request, **kwargs): """ Returns the ChangeList class for use on the changelist page. """ from django.contrib.admin.views.main import ChangeList return ChangeList
def get_changelist_form(
self, request, **kwargs)
Returns a Form class for use in the Formset on the changelist page.
def get_changelist_form(self, request, **kwargs): """ Returns a Form class for use in the Formset on the changelist page. """ defaults = { "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) if (defaults.get('fields') is None and not modelform_defines_fields(defaults.get('form'))): defaults['fields'] = forms.ALL_FIELDS return modelform_factory(self.model, **defaults)
def get_changelist_formset(
self, request, **kwargs)
Returns a FormSet class for use on the changelist page if list_editable is used.
def get_changelist_formset(self, request, **kwargs): """ Returns a FormSet class for use on the changelist page if list_editable is used. """ defaults = { "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) return modelformset_factory(self.model, self.get_changelist_form(request), extra=0, fields=self.list_editable, **defaults)
def get_field_queryset(
self, db, db_field, request)
If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case).
def get_field_queryset(self, db, db_field, request): """ If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case). """ related_admin = self.admin_site._registry.get(db_field.rel.to, None) if related_admin is not None: ordering = related_admin.get_ordering(request) if ordering is not None and ordering != (): return db_field.rel.to._default_manager.using(db).order_by(*ordering).complex_filter(db_field.rel.limit_choices_to) return None
def get_fieldsets(
self, request, obj=None)
Hook for specifying fieldsets for the add form.
def get_fieldsets(self, request, obj=None): "Hook for specifying fieldsets for the add form." if self.declared_fieldsets: return self.declared_fieldsets form = self.get_form(request, obj, fields=None) fields = list(form.base_fields) + list(self.get_readonly_fields(request, obj)) return [(None, {'fields': fields})]
def get_form(
self, request, obj=None, **kwargs)
Returns a Form class for use in the admin add view. This is used by add_view and change_view.
def get_form(self, request, obj=None, **kwargs): """ Returns a Form class for use in the admin add view. This is used by add_view and change_view. """ if 'fields' in kwargs: fields = kwargs.pop('fields') else: fields = flatten_fieldsets(self.get_fieldsets(request, obj)) if self.exclude is None: exclude = [] else: exclude = list(self.exclude) exclude.extend(self.get_readonly_fields(request, obj)) if self.exclude is None and hasattr(self.form, '_meta') and self.form._meta.exclude: # Take the custom ModelForm's Meta.exclude into account only if the # ModelAdmin doesn't define its own. exclude.extend(self.form._meta.exclude) # if exclude is an empty list we pass None to be consistent with the # default on modelform_factory exclude = exclude or None defaults = { "form": self.form, "fields": fields, "exclude": exclude, "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) if defaults['fields'] is None and not modelform_defines_fields(defaults['form']): defaults['fields'] = forms.ALL_FIELDS try: return modelform_factory(self.model, **defaults) except FieldError as e: raise FieldError('%s. Check fields/fieldsets/exclude attributes of class %s.' % (e, self.__class__.__name__))
def get_formsets(
self, request, obj=None)
def get_formsets(self, request, obj=None): for inline in self.get_inline_instances(request, obj): yield inline.get_formset(request, obj)
def get_inline_instances(
self, request, obj=None)
def get_inline_instances(self, request, obj=None): inline_instances = [] for inline_class in self.inlines: inline = inline_class(self.model, self.admin_site) if request: if not (inline.has_add_permission(request) or inline.has_change_permission(request, obj) or inline.has_delete_permission(request, obj)): continue if not inline.has_add_permission(request): inline.max_num = 0 inline_instances.append(inline) return inline_instances
def get_list_display(
self, request)
Return a sequence containing the fields to be displayed on the changelist.
def get_list_display(self, request): """ Return a sequence containing the fields to be displayed on the changelist. """ return self.list_display
def get_list_display_links(
self, request, list_display)
Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display().
def get_list_display_links(self, request, list_display): """ Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display(). """ if self.list_display_links or not list_display: return self.list_display_links else: # Use only the first item in list_display as link return list(list_display)[:1]
def get_list_filter(
self, request)
Returns a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page.
def get_list_filter(self, request): """ Returns a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page. """ return self.list_filter
def get_model_perms(
self, request)
Returns a dict of all perms for this model. This dict has the keys
add
, change
, and delete
mapping to the True/False for each
of those actions.
def get_model_perms(self, request): """ Returns a dict of all perms for this model. This dict has the keys ``add``, ``change``, and ``delete`` mapping to the True/False for each of those actions. """ return { 'add': self.has_add_permission(request), 'change': self.has_change_permission(request), 'delete': self.has_delete_permission(request), }
def get_object(
self, request, object_id)
Returns an instance matching the primary key provided. None
is
returned if no match is found (or the object_id failed validation
against the primary key field).
def get_object(self, request, object_id): """ Returns an instance matching the primary key provided. ``None`` is returned if no match is found (or the object_id failed validation against the primary key field). """ queryset = self.get_queryset(request) model = queryset.model try: object_id = model._meta.pk.to_python(object_id) return queryset.get(pk=object_id) except (model.DoesNotExist, ValidationError, ValueError): return None
def get_ordering(
self, request)
Hook for specifying field ordering.
def get_ordering(self, request): """ Hook for specifying field ordering. """ return self.ordering or () # otherwise we might try to *None, which is bad ;)
def get_paginator(
self, request, queryset, per_page, orphans=0, allow_empty_first_page=True)
def get_paginator(self, request, queryset, per_page, orphans=0, allow_empty_first_page=True): return self.paginator(queryset, per_page, orphans, allow_empty_first_page)
def get_prepopulated_fields(
self, request, obj=None)
Hook for specifying custom prepopulated fields.
def get_prepopulated_fields(self, request, obj=None): """ Hook for specifying custom prepopulated fields. """ return self.prepopulated_fields
def get_preserved_filters(
self, request)
Returns the preserved filters querystring.
def get_preserved_filters(self, request): """ Returns the preserved filters querystring. """ match = request.resolver_match if self.preserve_filters and match: opts = self.model._meta current_url = '%s:%s' % (match.app_name, match.url_name) changelist_url = 'admin:%s_%s_changelist' % (opts.app_label, opts.model_name) if current_url == changelist_url: preserved_filters = request.GET.urlencode() else: preserved_filters = request.GET.get('_changelist_filters') if preserved_filters: return urlencode({'_changelist_filters': preserved_filters}) return ''
def get_queryset(
self, request)
Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view.
def get_queryset(self, request): """ Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view. """ qs = self.model._default_manager.get_queryset() # TODO: this should be handled by some parameter to the ChangeList. ordering = self.get_ordering(request) if ordering: qs = qs.order_by(*ordering) return qs
def get_readonly_fields(
self, request, obj=None)
Hook for specifying custom readonly fields.
def get_readonly_fields(self, request, obj=None): """ Hook for specifying custom readonly fields. """ return self.readonly_fields
def get_search_results(
self, request, queryset, search_term)
Returns a tuple containing a queryset to implement the search, and a boolean indicating if the results may contain duplicates.
def get_search_results(self, request, queryset, search_term): """ Returns a tuple containing a queryset to implement the search, and a boolean indicating if the results may contain duplicates. """ # Apply keyword searches. def construct_search(field_name): if field_name.startswith('^'): return "%s__istartswith" % field_name[1:] elif field_name.startswith('='): return "%s__iexact" % field_name[1:] elif field_name.startswith('@'): return "%s__search" % field_name[1:] else: return "%s__icontains" % field_name use_distinct = False if self.search_fields and search_term: orm_lookups = [construct_search(str(search_field)) for search_field in self.search_fields] for bit in search_term.split(): or_queries = [models.Q(**{orm_lookup: bit}) for orm_lookup in orm_lookups] queryset = queryset.filter(reduce(operator.or_, or_queries)) if not use_distinct: for search_spec in orm_lookups: if lookup_needs_distinct(self.opts, search_spec): use_distinct = True break return queryset, use_distinct
def get_urls(
self)
def get_urls(self): from django.conf.urls import patterns, url def wrap(view): def wrapper(*args, **kwargs): return self.admin_site.admin_view(view)(*args, **kwargs) return update_wrapper(wrapper, view) info = self.model._meta.app_label, self.model._meta.model_name urlpatterns = patterns('', url(r'^$', wrap(self.changelist_view), name='%s_%s_changelist' % info), url(r'^add/$', wrap(self.add_view), name='%s_%s_add' % info), url(r'^(.+)/history/$', wrap(self.history_view), name='%s_%s_history' % info), url(r'^(.+)/delete/$', wrap(self.delete_view), name='%s_%s_delete' % info), url(r'^(.+)/$', wrap(self.change_view), name='%s_%s_change' % info), ) return urlpatterns
def has_add_permission(
self, request)
Returns True if the given request has permission to add an object. Can be overridden by the user in subclasses.
def has_add_permission(self, request): """ Returns True if the given request has permission to add an object. Can be overridden by the user in subclasses. """ opts = self.opts codename = get_permission_codename('add', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_change_permission(
self, request, obj=None)
Returns True if the given request has permission to change the given
Django model instance, the default implementation doesn't examine the
obj
parameter.
Can be overridden by the user in subclasses. In such case it should
return True if the given request has permission to change the obj
model instance. If obj
is None, this should return True if the given
request has permission to change any object of the given type.
def has_change_permission(self, request, obj=None): """ Returns True if the given request has permission to change the given Django model instance, the default implementation doesn't examine the `obj` parameter. Can be overridden by the user in subclasses. In such case it should return True if the given request has permission to change the `obj` model instance. If `obj` is None, this should return True if the given request has permission to change *any* object of the given type. """ opts = self.opts codename = get_permission_codename('change', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_delete_permission(
self, request, obj=None)
Returns True if the given request has permission to change the given
Django model instance, the default implementation doesn't examine the
obj
parameter.
Can be overridden by the user in subclasses. In such case it should
return True if the given request has permission to delete the obj
model instance. If obj
is None, this should return True if the given
request has permission to delete any object of the given type.
def has_delete_permission(self, request, obj=None): """ Returns True if the given request has permission to change the given Django model instance, the default implementation doesn't examine the `obj` parameter. Can be overridden by the user in subclasses. In such case it should return True if the given request has permission to delete the `obj` model instance. If `obj` is None, this should return True if the given request has permission to delete *any* object of the given type. """ opts = self.opts codename = get_permission_codename('delete', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def history_view(
self, request, object_id, extra_context=None)
The 'history' admin view for this model.
def history_view(self, request, object_id, extra_context=None): "The 'history' admin view for this model." from django.contrib.admin.models import LogEntry # First check if the user can see this history. model = self.model obj = get_object_or_404(model, pk=unquote(object_id)) if not self.has_change_permission(request, obj): raise PermissionDenied # Then get the history for this object. opts = model._meta app_label = opts.app_label action_list = LogEntry.objects.filter( object_id=unquote(object_id), content_type__id__exact=ContentType.objects.get_for_model(model).id ).select_related().order_by('action_time') context = { 'title': _('Change history: %s') % force_text(obj), 'action_list': action_list, 'module_name': capfirst(force_text(opts.verbose_name_plural)), 'object': obj, 'app_label': app_label, 'opts': opts, 'preserved_filters': self.get_preserved_filters(request), } context.update(extra_context or {}) return TemplateResponse(request, self.object_history_template or [ "admin/%s/%s/object_history.html" % (app_label, opts.model_name), "admin/%s/object_history.html" % app_label, "admin/object_history.html" ], context, current_app=self.admin_site.name)
def log_addition(
self, request, object)
Log that an object has been successfully added.
The default implementation creates an admin LogEntry object.
def log_addition(self, request, object): """ Log that an object has been successfully added. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, ADDITION LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=ADDITION )
def log_change(
self, request, object, message)
Log that an object has been successfully changed.
The default implementation creates an admin LogEntry object.
def log_change(self, request, object, message): """ Log that an object has been successfully changed. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, CHANGE LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=CHANGE, change_message=message )
def log_deletion(
self, request, object, object_repr)
Log that an object will be deleted. Note that this method is called before the deletion.
The default implementation creates an admin LogEntry object.
def log_deletion(self, request, object, object_repr): """ Log that an object will be deleted. Note that this method is called before the deletion. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, DELETION LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(self.model).pk, object_id=object.pk, object_repr=object_repr, action_flag=DELETION )
def lookup_allowed(
self, lookup, value)
def lookup_allowed(self, lookup, value): model = self.model # Check FKey lookups that are allowed, so that popups produced by # ForeignKeyRawIdWidget, on the basis of ForeignKey.limit_choices_to, # are allowed to work. for l in model._meta.related_fkey_lookups: for k, v in widgets.url_params_from_lookup_dict(l).items(): if k == lookup and v == value: return True parts = lookup.split(LOOKUP_SEP) # Last term in lookup is a query term (__exact, __startswith etc) # This term can be ignored. if len(parts) > 1 and parts[-1] in QUERY_TERMS: parts.pop() # Special case -- foo__id__exact and foo__id queries are implied # if foo has been specifically included in the lookup list; so # drop __id if it is the last part. However, first we need to find # the pk attribute name. rel_name = None for part in parts[:-1]: try: field, _, _, _ = model._meta.get_field_by_name(part) except FieldDoesNotExist: # Lookups on non-existent fields are ok, since they're ignored # later. return True if hasattr(field, 'rel'): if field.rel is None: # This property or relation doesn't exist, but it's allowed # since it's ignored in ChangeList.get_filters(). return True model = field.rel.to rel_name = field.rel.get_related_field().name elif isinstance(field, RelatedObject): model = field.model rel_name = model._meta.pk.name else: rel_name = None if rel_name and len(parts) > 1 and parts[-1] == rel_name: parts.pop() if len(parts) == 1: return True clean_lookup = LOOKUP_SEP.join(parts) return clean_lookup in self.list_filter or clean_lookup == self.date_hierarchy
def message_user(
self, request, message, level=20, extra_tags='', fail_silently=False)
Send a message to the user. The default implementation posts a message using the django.contrib.messages backend.
Exposes almost the same API as messages.add_message(), but accepts the
positional arguments in a different order to maintain backwards
compatibility. For convenience, it accepts the level
argument as
a string rather than the usual level number.
def message_user(self, request, message, level=messages.INFO, extra_tags='', fail_silently=False): """ Send a message to the user. The default implementation posts a message using the django.contrib.messages backend. Exposes almost the same API as messages.add_message(), but accepts the positional arguments in a different order to maintain backwards compatibility. For convenience, it accepts the `level` argument as a string rather than the usual level number. """ if not isinstance(level, int): # attempt to get the level if passed a string try: level = getattr(messages.constants, level.upper()) except AttributeError: levels = messages.constants.DEFAULT_TAGS.values() levels_repr = ', '.join('`%s`' % l for l in levels) raise ValueError('Bad message level string: `%s`. ' 'Possible values are: %s' % (level, levels_repr)) messages.add_message(request, level, message, extra_tags=extra_tags, fail_silently=fail_silently)
def queryset(
*args, **kwargs)
def wrapped(*args, **kwargs): warnings.warn( "`%s.%s` is deprecated, use `%s` instead." % (self.class_name, self.old_method_name, self.new_method_name), self.deprecation_warning, 2) return f(*args, **kwargs)
def render_change_form(
self, request, context, add=False, change=False, form_url='', obj=None)
def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None): opts = self.model._meta app_label = opts.app_label preserved_filters = self.get_preserved_filters(request) form_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, form_url) context.update({ 'add': add, 'change': change, 'has_add_permission': self.has_add_permission(request), 'has_change_permission': self.has_change_permission(request, obj), 'has_delete_permission': self.has_delete_permission(request, obj), 'has_file_field': True, # FIXME - this should check if form or formsets have a FileField, 'has_absolute_url': hasattr(self.model, 'get_absolute_url'), 'form_url': form_url, 'opts': opts, 'content_type_id': ContentType.objects.get_for_model(self.model).id, 'save_as': self.save_as, 'save_on_top': self.save_on_top, }) if add and self.add_form_template is not None: form_template = self.add_form_template else: form_template = self.change_form_template return TemplateResponse(request, form_template or [ "admin/%s/%s/change_form.html" % (app_label, opts.model_name), "admin/%s/change_form.html" % app_label, "admin/change_form.html" ], context, current_app=self.admin_site.name)
def response_action(
self, request, queryset)
Handle an admin action. This is called if a request is POSTed to the changelist; it returns an HttpResponse if the action was handled, and None otherwise.
def response_action(self, request, queryset): """ Handle an admin action. This is called if a request is POSTed to the changelist; it returns an HttpResponse if the action was handled, and None otherwise. """ # There can be multiple action forms on the page (at the top # and bottom of the change list, for example). Get the action # whose button was pushed. try: action_index = int(request.POST.get('index', 0)) except ValueError: action_index = 0 # Construct the action form. data = request.POST.copy() data.pop(helpers.ACTION_CHECKBOX_NAME, None) data.pop("index", None) # Use the action whose button was pushed try: data.update({'action': data.getlist('action')[action_index]}) except IndexError: # If we didn't get an action from the chosen form that's invalid # POST data, so by deleting action it'll fail the validation check # below. So no need to do anything here pass action_form = self.action_form(data, auto_id=None) action_form.fields['action'].choices = self.get_action_choices(request) # If the form's valid we can handle the action. if action_form.is_valid(): action = action_form.cleaned_data['action'] select_across = action_form.cleaned_data['select_across'] func = self.get_actions(request)[action][0] # Get the list of selected PKs. If nothing's selected, we can't # perform an action on it, so bail. Except we want to perform # the action explicitly on all objects. selected = request.POST.getlist(helpers.ACTION_CHECKBOX_NAME) if not selected and not select_across: # Reminder that something needs to be selected or nothing will happen msg = _("Items must be selected in order to perform " "actions on them. No items have been changed.") self.message_user(request, msg, messages.WARNING) return None if not select_across: # Perform the action only on the selected objects queryset = queryset.filter(pk__in=selected) response = func(self, request, queryset) # Actions may return an HttpResponse-like object, which will be # used as the response from the POST. If not, we'll be a good # little HTTP citizen and redirect back to the changelist page. if isinstance(response, HttpResponseBase): return response else: return HttpResponseRedirect(request.get_full_path()) else: msg = _("No action selected.") self.message_user(request, msg, messages.WARNING) return None
def response_add(
self, request, obj, post_url_continue=None)
Determines the HttpResponse for the add_view stage.
def response_add(self, request, obj, post_url_continue=None): """ Determines the HttpResponse for the add_view stage. """ opts = obj._meta pk_value = obj._get_pk_val() preserved_filters = self.get_preserved_filters(request) msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)} # Here, we distinguish between different save types by checking for # the presence of keys in request.POST. if IS_POPUP_VAR in request.POST: return SimpleTemplateResponse('admin/popup_response.html', { 'pk_value': escape(pk_value), 'obj': escapejs(obj) }) elif "_continue" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) if post_url_continue is None: post_url_continue = reverse('admin:%s_%s_change' % (opts.app_label, opts.model_name), args=(pk_value,), current_app=self.admin_site.name) post_url_continue = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url_continue) return HttpResponseRedirect(post_url_continue) elif "_addanother" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may add another %(name)s below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = request.path redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) else: msg = _('The %(name)s "%(obj)s" was added successfully.') % msg_dict self.message_user(request, msg, messages.SUCCESS) return self.response_post_save_add(request, obj)
def response_change(
self, request, obj)
Determines the HttpResponse for the change_view stage.
def response_change(self, request, obj): """ Determines the HttpResponse for the change_view stage. """ opts = self.model._meta pk_value = obj._get_pk_val() preserved_filters = self.get_preserved_filters(request) msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)} if "_continue" in request.POST: msg = _('The %(name)s "%(obj)s" was changed successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = request.path redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) elif "_saveasnew" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = reverse('admin:%s_%s_change' % (opts.app_label, opts.model_name), args=(pk_value,), current_app=self.admin_site.name) redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) elif "_addanother" in request.POST: msg = _('The %(name)s "%(obj)s" was changed successfully. You may add another %(name)s below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = reverse('admin:%s_%s_add' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) else: msg = _('The %(name)s "%(obj)s" was changed successfully.') % msg_dict self.message_user(request, msg, messages.SUCCESS) return self.response_post_save_change(request, obj)
def response_post_save_add(
self, request, obj)
Figure out where to redirect after the 'Save' button has been pressed when adding a new object.
def response_post_save_add(self, request, obj): """ Figure out where to redirect after the 'Save' button has been pressed when adding a new object. """ opts = self.model._meta if self.has_change_permission(request, None): post_url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url) else: post_url = reverse('admin:index', current_app=self.admin_site.name) return HttpResponseRedirect(post_url)
def response_post_save_change(
self, request, obj)
Figure out where to redirect after the 'Save' button has been pressed when editing an existing object.
def response_post_save_change(self, request, obj): """ Figure out where to redirect after the 'Save' button has been pressed when editing an existing object. """ opts = self.model._meta if self.has_change_permission(request, None): post_url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url) else: post_url = reverse('admin:index', current_app=self.admin_site.name) return HttpResponseRedirect(post_url)
def save_form(
self, request, form, change)
Given a ModelForm return an unsaved instance. change
is True if
the object is being changed, and False if it's being added.
def save_form(self, request, form, change): """ Given a ModelForm return an unsaved instance. ``change`` is True if the object is being changed, and False if it's being added. """ return form.save(commit=False)
def save_formset(
self, request, form, formset, change)
Given an inline formset save it to the database.
def save_formset(self, request, form, formset, change): """ Given an inline formset save it to the database. """ formset.save()
def save_model(
self, request, obj, form, change)
Given a model instance save it to the database.
def save_model(self, request, obj, form, change): """ Given a model instance save it to the database. """ obj.save()
Given the HttpRequest
, the parent ModelForm
instance, the
list of inline formsets and a boolean value based on whether the
parent is being added or changed, save the related objects to the
database. Note that at this point save_form() and save_model() have
already been called.
def to_field_allowed(
self, request, to_field)
Returns True if the model associated with this admin should be allowed to be referenced by the specified field.
def to_field_allowed(self, request, to_field): """ Returns True if the model associated with this admin should be allowed to be referenced by the specified field. """ opts = self.model._meta try: field = opts.get_field(to_field) except FieldDoesNotExist: return False # Always allow referencing the primary key since it's already possible # to get this information from the change view URL. if field.primary_key: return True # Make sure at least one of the models registered for this site # references this field through a FK or a M2M relationship. registered_models = set() for model, admin in self.admin_site._registry.items(): registered_models.add(model) for inline in admin.inlines: registered_models.add(inline.model) for related_object in opts.get_all_related_objects(include_hidden=True): related_model = related_object.model if (any(issubclass(model, related_model) for model in registered_models) and related_object.field.rel.get_related_field() == field): return True return False
def validate(
cls, model)
@classmethod def validate(cls, model): validator = cls.validator_class() validator.validate(cls, model)
class MediaFondsAdmin
class MediaFondsAdmin(admin.ModelAdmin): search_fields = ['title', 'code'] ordering = ['code'] filter_horizontal = ['children']
Ancestors (in MRO)
- MediaFondsAdmin
- django.contrib.admin.options.ModelAdmin
- django.contrib.admin.options.BaseModelAdmin
- __builtin__.object
Class variables
var action_form
var actions
var actions_on_bottom
var actions_on_top
var actions_selection_counter
var add_form_template
var change_form_template
var change_list_template
var date_hierarchy
var delete_confirmation_template
var delete_selected_confirmation_template
var exclude
var fields
var fieldsets
var filter_horizontal
var filter_vertical
var form
var formfield_overrides
var inlines
var list_display
var list_display_links
var list_editable
var list_filter
var list_max_show_all
var list_per_page
var object_history_template
var ordering
var paginator
var prepopulated_fields
var preserve_filters
var radio_fields
var raw_id_fields
var readonly_fields
var save_as
var save_on_top
var search_fields
var validator_class
Instance variables
var declared_fieldsets
var media
var urls
Methods
def __init__(
self, model, admin_site)
def __init__(self, model, admin_site): self.model = model self.opts = model._meta self.admin_site = admin_site super(ModelAdmin, self).__init__()
def action_checkbox(
self, obj)
A list_display column containing a checkbox widget.
def action_checkbox(self, obj): """ A list_display column containing a checkbox widget. """ return helpers.checkbox.render(helpers.ACTION_CHECKBOX_NAME, force_text(obj.pk))
def add_view(
self, *args, **kwargs)
The 'add' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def change_view(
self, *args, **kwargs)
The 'change' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def changelist_view(
self, *args, **kwargs)
The 'change list' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def construct_change_message(
self, request, form, formsets)
Construct a change message from a changed object.
def construct_change_message(self, request, form, formsets): """ Construct a change message from a changed object. """ change_message = [] if form.changed_data: change_message.append(_('Changed %s.') % get_text_list(form.changed_data, _('and'))) if formsets: for formset in formsets: for added_object in formset.new_objects: change_message.append(_('Added %(name)s "%(object)s".') % {'name': force_text(added_object._meta.verbose_name), 'object': force_text(added_object)}) for changed_object, changed_fields in formset.changed_objects: change_message.append(_('Changed %(list)s for %(name)s "%(object)s".') % {'list': get_text_list(changed_fields, _('and')), 'name': force_text(changed_object._meta.verbose_name), 'object': force_text(changed_object)}) for deleted_object in formset.deleted_objects: change_message.append(_('Deleted %(name)s "%(object)s".') % {'name': force_text(deleted_object._meta.verbose_name), 'object': force_text(deleted_object)}) change_message = ' '.join(change_message) return change_message or _('No fields changed.')
def delete_model(
self, request, obj)
Given a model instance delete it from the database.
def delete_model(self, request, obj): """ Given a model instance delete it from the database. """ obj.delete()
def delete_view(
self, *args, **kwargs)
The 'delete' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def formfield_for_choice_field(
self, db_field, request=None, **kwargs)
Get a form Field for a database Field that has declared choices.
def formfield_for_choice_field(self, db_field, request=None, **kwargs): """ Get a form Field for a database Field that has declared choices. """ # If the field is named as a radio_field, use a RadioSelect if db_field.name in self.radio_fields: # Avoid stomping on custom widget/choices arguments. if 'widget' not in kwargs: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) if 'choices' not in kwargs: kwargs['choices'] = db_field.get_choices( include_blank=db_field.blank, blank_choice=[('', _('None'))] ) return db_field.formfield(**kwargs)
def formfield_for_dbfield(
self, db_field, **kwargs)
Hook for specifying the form Field instance for a given database Field instance.
If kwargs are given, they're passed to the form Field's constructor.
def formfield_for_dbfield(self, db_field, **kwargs): """ Hook for specifying the form Field instance for a given database Field instance. If kwargs are given, they're passed to the form Field's constructor. """ request = kwargs.pop("request", None) # If the field specifies choices, we don't need to look for special # admin widgets - we just need to use a select widget of some kind. if db_field.choices: return self.formfield_for_choice_field(db_field, request, **kwargs) # ForeignKey or ManyToManyFields if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)): # Combine the field kwargs with any options for formfield_overrides. # Make sure the passed in **kwargs override anything in # formfield_overrides because **kwargs is more specific, and should # always win. if db_field.__class__ in self.formfield_overrides: kwargs = dict(self.formfield_overrides[db_field.__class__], **kwargs) # Get the correct formfield. if isinstance(db_field, models.ForeignKey): formfield = self.formfield_for_foreignkey(db_field, request, **kwargs) elif isinstance(db_field, models.ManyToManyField): formfield = self.formfield_for_manytomany(db_field, request, **kwargs) # For non-raw_id fields, wrap the widget with a wrapper that adds # extra HTML -- the "add other" interface -- to the end of the # rendered output. formfield can be None if it came from a # OneToOneField with parent_link=True or a M2M intermediary. if formfield and db_field.name not in self.raw_id_fields: related_modeladmin = self.admin_site._registry.get( db_field.rel.to) can_add_related = bool(related_modeladmin and related_modeladmin.has_add_permission(request)) formfield.widget = widgets.RelatedFieldWidgetWrapper( formfield.widget, db_field.rel, self.admin_site, can_add_related=can_add_related) return formfield # If we've got overrides for the formfield defined, use 'em. **kwargs # passed to formfield_for_dbfield override the defaults. for klass in db_field.__class__.mro(): if klass in self.formfield_overrides: kwargs = dict(copy.deepcopy(self.formfield_overrides[klass]), **kwargs) return db_field.formfield(**kwargs) # For any other type of field, just call its formfield() method. return db_field.formfield(**kwargs)
def formfield_for_foreignkey(
self, db_field, request=None, **kwargs)
Get a form Field for a ForeignKey.
def formfield_for_foreignkey(self, db_field, request=None, **kwargs): """ Get a form Field for a ForeignKey. """ db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel, self.admin_site, using=db) elif db_field.name in self.radio_fields: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) kwargs['empty_label'] = _('None') if db_field.blank else None if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def formfield_for_manytomany(
self, db_field, request=None, **kwargs)
Get a form Field for a ManyToManyField.
def formfield_for_manytomany(self, db_field, request=None, **kwargs): """ Get a form Field for a ManyToManyField. """ # If it uses an intermediary model that isn't auto created, don't show # a field in admin. if not db_field.rel.through._meta.auto_created: return None db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel, self.admin_site, using=db) kwargs['help_text'] = '' elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)): kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical)) if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def get_action(
self, action)
Return a given action from a parameter, which can either be a callable, or the name of a method on the ModelAdmin. Return is a tuple of (callable, name, description).
def get_action(self, action): """ Return a given action from a parameter, which can either be a callable, or the name of a method on the ModelAdmin. Return is a tuple of (callable, name, description). """ # If the action is a callable, just use it. if callable(action): func = action action = action.__name__ # Next, look for a method. Grab it off self.__class__ to get an unbound # method instead of a bound one; this ensures that the calling # conventions are the same for functions and methods. elif hasattr(self.__class__, action): func = getattr(self.__class__, action) # Finally, look for a named method on the admin site else: try: func = self.admin_site.get_action(action) except KeyError: return None if hasattr(func, 'short_description'): description = func.short_description else: description = capfirst(action.replace('_', ' ')) return func, action, description
def get_action_choices(
self, request, default_choices=[(u'', u'---------')])
Return a list of choices for use in a form object. Each choice is a tuple (name, description).
def get_action_choices(self, request, default_choices=BLANK_CHOICE_DASH): """ Return a list of choices for use in a form object. Each choice is a tuple (name, description). """ choices = [] + default_choices for func, name, description in six.itervalues(self.get_actions(request)): choice = (name, description % model_format_dict(self.opts)) choices.append(choice) return choices
def get_actions(
self, request)
Return a dictionary mapping the names of all actions for this ModelAdmin to a tuple of (callable, name, description) for each action.
def get_actions(self, request): """ Return a dictionary mapping the names of all actions for this ModelAdmin to a tuple of (callable, name, description) for each action. """ # If self.actions is explicitly set to None that means that we don't # want *any* actions enabled on this page. from django.contrib.admin.views.main import _is_changelist_popup if self.actions is None or _is_changelist_popup(request): return SortedDict() actions = [] # Gather actions from the admin site first for (name, func) in self.admin_site.actions: description = getattr(func, 'short_description', name.replace('_', ' ')) actions.append((func, name, description)) # Then gather them from the model admin and all parent classes, # starting with self and working back up. for klass in self.__class__.mro()[::-1]: class_actions = getattr(klass, 'actions', []) # Avoid trying to iterate over None if not class_actions: continue actions.extend([self.get_action(action) for action in class_actions]) # get_action might have returned None, so filter any of those out. actions = filter(None, actions) # Convert the actions into a SortedDict keyed by name. actions = SortedDict([ (name, (func, name, desc)) for func, name, desc in actions ]) return actions
def get_changelist(
self, request, **kwargs)
Returns the ChangeList class for use on the changelist page.
def get_changelist(self, request, **kwargs): """ Returns the ChangeList class for use on the changelist page. """ from django.contrib.admin.views.main import ChangeList return ChangeList
def get_changelist_form(
self, request, **kwargs)
Returns a Form class for use in the Formset on the changelist page.
def get_changelist_form(self, request, **kwargs): """ Returns a Form class for use in the Formset on the changelist page. """ defaults = { "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) if (defaults.get('fields') is None and not modelform_defines_fields(defaults.get('form'))): defaults['fields'] = forms.ALL_FIELDS return modelform_factory(self.model, **defaults)
def get_changelist_formset(
self, request, **kwargs)
Returns a FormSet class for use on the changelist page if list_editable is used.
def get_changelist_formset(self, request, **kwargs): """ Returns a FormSet class for use on the changelist page if list_editable is used. """ defaults = { "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) return modelformset_factory(self.model, self.get_changelist_form(request), extra=0, fields=self.list_editable, **defaults)
def get_field_queryset(
self, db, db_field, request)
If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case).
def get_field_queryset(self, db, db_field, request): """ If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case). """ related_admin = self.admin_site._registry.get(db_field.rel.to, None) if related_admin is not None: ordering = related_admin.get_ordering(request) if ordering is not None and ordering != (): return db_field.rel.to._default_manager.using(db).order_by(*ordering).complex_filter(db_field.rel.limit_choices_to) return None
def get_fieldsets(
self, request, obj=None)
Hook for specifying fieldsets for the add form.
def get_fieldsets(self, request, obj=None): "Hook for specifying fieldsets for the add form." if self.declared_fieldsets: return self.declared_fieldsets form = self.get_form(request, obj, fields=None) fields = list(form.base_fields) + list(self.get_readonly_fields(request, obj)) return [(None, {'fields': fields})]
def get_form(
self, request, obj=None, **kwargs)
Returns a Form class for use in the admin add view. This is used by add_view and change_view.
def get_form(self, request, obj=None, **kwargs): """ Returns a Form class for use in the admin add view. This is used by add_view and change_view. """ if 'fields' in kwargs: fields = kwargs.pop('fields') else: fields = flatten_fieldsets(self.get_fieldsets(request, obj)) if self.exclude is None: exclude = [] else: exclude = list(self.exclude) exclude.extend(self.get_readonly_fields(request, obj)) if self.exclude is None and hasattr(self.form, '_meta') and self.form._meta.exclude: # Take the custom ModelForm's Meta.exclude into account only if the # ModelAdmin doesn't define its own. exclude.extend(self.form._meta.exclude) # if exclude is an empty list we pass None to be consistent with the # default on modelform_factory exclude = exclude or None defaults = { "form": self.form, "fields": fields, "exclude": exclude, "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) if defaults['fields'] is None and not modelform_defines_fields(defaults['form']): defaults['fields'] = forms.ALL_FIELDS try: return modelform_factory(self.model, **defaults) except FieldError as e: raise FieldError('%s. Check fields/fieldsets/exclude attributes of class %s.' % (e, self.__class__.__name__))
def get_formsets(
self, request, obj=None)
def get_formsets(self, request, obj=None): for inline in self.get_inline_instances(request, obj): yield inline.get_formset(request, obj)
def get_inline_instances(
self, request, obj=None)
def get_inline_instances(self, request, obj=None): inline_instances = [] for inline_class in self.inlines: inline = inline_class(self.model, self.admin_site) if request: if not (inline.has_add_permission(request) or inline.has_change_permission(request, obj) or inline.has_delete_permission(request, obj)): continue if not inline.has_add_permission(request): inline.max_num = 0 inline_instances.append(inline) return inline_instances
def get_list_display(
self, request)
Return a sequence containing the fields to be displayed on the changelist.
def get_list_display(self, request): """ Return a sequence containing the fields to be displayed on the changelist. """ return self.list_display
def get_list_display_links(
self, request, list_display)
Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display().
def get_list_display_links(self, request, list_display): """ Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display(). """ if self.list_display_links or not list_display: return self.list_display_links else: # Use only the first item in list_display as link return list(list_display)[:1]
def get_list_filter(
self, request)
Returns a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page.
def get_list_filter(self, request): """ Returns a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page. """ return self.list_filter
def get_model_perms(
self, request)
Returns a dict of all perms for this model. This dict has the keys
add
, change
, and delete
mapping to the True/False for each
of those actions.
def get_model_perms(self, request): """ Returns a dict of all perms for this model. This dict has the keys ``add``, ``change``, and ``delete`` mapping to the True/False for each of those actions. """ return { 'add': self.has_add_permission(request), 'change': self.has_change_permission(request), 'delete': self.has_delete_permission(request), }
def get_object(
self, request, object_id)
Returns an instance matching the primary key provided. None
is
returned if no match is found (or the object_id failed validation
against the primary key field).
def get_object(self, request, object_id): """ Returns an instance matching the primary key provided. ``None`` is returned if no match is found (or the object_id failed validation against the primary key field). """ queryset = self.get_queryset(request) model = queryset.model try: object_id = model._meta.pk.to_python(object_id) return queryset.get(pk=object_id) except (model.DoesNotExist, ValidationError, ValueError): return None
def get_ordering(
self, request)
Hook for specifying field ordering.
def get_ordering(self, request): """ Hook for specifying field ordering. """ return self.ordering or () # otherwise we might try to *None, which is bad ;)
def get_paginator(
self, request, queryset, per_page, orphans=0, allow_empty_first_page=True)
def get_paginator(self, request, queryset, per_page, orphans=0, allow_empty_first_page=True): return self.paginator(queryset, per_page, orphans, allow_empty_first_page)
def get_prepopulated_fields(
self, request, obj=None)
Hook for specifying custom prepopulated fields.
def get_prepopulated_fields(self, request, obj=None): """ Hook for specifying custom prepopulated fields. """ return self.prepopulated_fields
def get_preserved_filters(
self, request)
Returns the preserved filters querystring.
def get_preserved_filters(self, request): """ Returns the preserved filters querystring. """ match = request.resolver_match if self.preserve_filters and match: opts = self.model._meta current_url = '%s:%s' % (match.app_name, match.url_name) changelist_url = 'admin:%s_%s_changelist' % (opts.app_label, opts.model_name) if current_url == changelist_url: preserved_filters = request.GET.urlencode() else: preserved_filters = request.GET.get('_changelist_filters') if preserved_filters: return urlencode({'_changelist_filters': preserved_filters}) return ''
def get_queryset(
self, request)
Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view.
def get_queryset(self, request): """ Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view. """ qs = self.model._default_manager.get_queryset() # TODO: this should be handled by some parameter to the ChangeList. ordering = self.get_ordering(request) if ordering: qs = qs.order_by(*ordering) return qs
def get_readonly_fields(
self, request, obj=None)
Hook for specifying custom readonly fields.
def get_readonly_fields(self, request, obj=None): """ Hook for specifying custom readonly fields. """ return self.readonly_fields
def get_search_results(
self, request, queryset, search_term)
Returns a tuple containing a queryset to implement the search, and a boolean indicating if the results may contain duplicates.
def get_search_results(self, request, queryset, search_term): """ Returns a tuple containing a queryset to implement the search, and a boolean indicating if the results may contain duplicates. """ # Apply keyword searches. def construct_search(field_name): if field_name.startswith('^'): return "%s__istartswith" % field_name[1:] elif field_name.startswith('='): return "%s__iexact" % field_name[1:] elif field_name.startswith('@'): return "%s__search" % field_name[1:] else: return "%s__icontains" % field_name use_distinct = False if self.search_fields and search_term: orm_lookups = [construct_search(str(search_field)) for search_field in self.search_fields] for bit in search_term.split(): or_queries = [models.Q(**{orm_lookup: bit}) for orm_lookup in orm_lookups] queryset = queryset.filter(reduce(operator.or_, or_queries)) if not use_distinct: for search_spec in orm_lookups: if lookup_needs_distinct(self.opts, search_spec): use_distinct = True break return queryset, use_distinct
def get_urls(
self)
def get_urls(self): from django.conf.urls import patterns, url def wrap(view): def wrapper(*args, **kwargs): return self.admin_site.admin_view(view)(*args, **kwargs) return update_wrapper(wrapper, view) info = self.model._meta.app_label, self.model._meta.model_name urlpatterns = patterns('', url(r'^$', wrap(self.changelist_view), name='%s_%s_changelist' % info), url(r'^add/$', wrap(self.add_view), name='%s_%s_add' % info), url(r'^(.+)/history/$', wrap(self.history_view), name='%s_%s_history' % info), url(r'^(.+)/delete/$', wrap(self.delete_view), name='%s_%s_delete' % info), url(r'^(.+)/$', wrap(self.change_view), name='%s_%s_change' % info), ) return urlpatterns
def has_add_permission(
self, request)
Returns True if the given request has permission to add an object. Can be overridden by the user in subclasses.
def has_add_permission(self, request): """ Returns True if the given request has permission to add an object. Can be overridden by the user in subclasses. """ opts = self.opts codename = get_permission_codename('add', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_change_permission(
self, request, obj=None)
Returns True if the given request has permission to change the given
Django model instance, the default implementation doesn't examine the
obj
parameter.
Can be overridden by the user in subclasses. In such case it should
return True if the given request has permission to change the obj
model instance. If obj
is None, this should return True if the given
request has permission to change any object of the given type.
def has_change_permission(self, request, obj=None): """ Returns True if the given request has permission to change the given Django model instance, the default implementation doesn't examine the `obj` parameter. Can be overridden by the user in subclasses. In such case it should return True if the given request has permission to change the `obj` model instance. If `obj` is None, this should return True if the given request has permission to change *any* object of the given type. """ opts = self.opts codename = get_permission_codename('change', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_delete_permission(
self, request, obj=None)
Returns True if the given request has permission to change the given
Django model instance, the default implementation doesn't examine the
obj
parameter.
Can be overridden by the user in subclasses. In such case it should
return True if the given request has permission to delete the obj
model instance. If obj
is None, this should return True if the given
request has permission to delete any object of the given type.
def has_delete_permission(self, request, obj=None): """ Returns True if the given request has permission to change the given Django model instance, the default implementation doesn't examine the `obj` parameter. Can be overridden by the user in subclasses. In such case it should return True if the given request has permission to delete the `obj` model instance. If `obj` is None, this should return True if the given request has permission to delete *any* object of the given type. """ opts = self.opts codename = get_permission_codename('delete', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def history_view(
self, request, object_id, extra_context=None)
The 'history' admin view for this model.
def history_view(self, request, object_id, extra_context=None): "The 'history' admin view for this model." from django.contrib.admin.models import LogEntry # First check if the user can see this history. model = self.model obj = get_object_or_404(model, pk=unquote(object_id)) if not self.has_change_permission(request, obj): raise PermissionDenied # Then get the history for this object. opts = model._meta app_label = opts.app_label action_list = LogEntry.objects.filter( object_id=unquote(object_id), content_type__id__exact=ContentType.objects.get_for_model(model).id ).select_related().order_by('action_time') context = { 'title': _('Change history: %s') % force_text(obj), 'action_list': action_list, 'module_name': capfirst(force_text(opts.verbose_name_plural)), 'object': obj, 'app_label': app_label, 'opts': opts, 'preserved_filters': self.get_preserved_filters(request), } context.update(extra_context or {}) return TemplateResponse(request, self.object_history_template or [ "admin/%s/%s/object_history.html" % (app_label, opts.model_name), "admin/%s/object_history.html" % app_label, "admin/object_history.html" ], context, current_app=self.admin_site.name)
def log_addition(
self, request, object)
Log that an object has been successfully added.
The default implementation creates an admin LogEntry object.
def log_addition(self, request, object): """ Log that an object has been successfully added. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, ADDITION LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=ADDITION )
def log_change(
self, request, object, message)
Log that an object has been successfully changed.
The default implementation creates an admin LogEntry object.
def log_change(self, request, object, message): """ Log that an object has been successfully changed. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, CHANGE LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=CHANGE, change_message=message )
def log_deletion(
self, request, object, object_repr)
Log that an object will be deleted. Note that this method is called before the deletion.
The default implementation creates an admin LogEntry object.
def log_deletion(self, request, object, object_repr): """ Log that an object will be deleted. Note that this method is called before the deletion. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, DELETION LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(self.model).pk, object_id=object.pk, object_repr=object_repr, action_flag=DELETION )
def lookup_allowed(
self, lookup, value)
def lookup_allowed(self, lookup, value): model = self.model # Check FKey lookups that are allowed, so that popups produced by # ForeignKeyRawIdWidget, on the basis of ForeignKey.limit_choices_to, # are allowed to work. for l in model._meta.related_fkey_lookups: for k, v in widgets.url_params_from_lookup_dict(l).items(): if k == lookup and v == value: return True parts = lookup.split(LOOKUP_SEP) # Last term in lookup is a query term (__exact, __startswith etc) # This term can be ignored. if len(parts) > 1 and parts[-1] in QUERY_TERMS: parts.pop() # Special case -- foo__id__exact and foo__id queries are implied # if foo has been specifically included in the lookup list; so # drop __id if it is the last part. However, first we need to find # the pk attribute name. rel_name = None for part in parts[:-1]: try: field, _, _, _ = model._meta.get_field_by_name(part) except FieldDoesNotExist: # Lookups on non-existent fields are ok, since they're ignored # later. return True if hasattr(field, 'rel'): if field.rel is None: # This property or relation doesn't exist, but it's allowed # since it's ignored in ChangeList.get_filters(). return True model = field.rel.to rel_name = field.rel.get_related_field().name elif isinstance(field, RelatedObject): model = field.model rel_name = model._meta.pk.name else: rel_name = None if rel_name and len(parts) > 1 and parts[-1] == rel_name: parts.pop() if len(parts) == 1: return True clean_lookup = LOOKUP_SEP.join(parts) return clean_lookup in self.list_filter or clean_lookup == self.date_hierarchy
def message_user(
self, request, message, level=20, extra_tags='', fail_silently=False)
Send a message to the user. The default implementation posts a message using the django.contrib.messages backend.
Exposes almost the same API as messages.add_message(), but accepts the
positional arguments in a different order to maintain backwards
compatibility. For convenience, it accepts the level
argument as
a string rather than the usual level number.
def message_user(self, request, message, level=messages.INFO, extra_tags='', fail_silently=False): """ Send a message to the user. The default implementation posts a message using the django.contrib.messages backend. Exposes almost the same API as messages.add_message(), but accepts the positional arguments in a different order to maintain backwards compatibility. For convenience, it accepts the `level` argument as a string rather than the usual level number. """ if not isinstance(level, int): # attempt to get the level if passed a string try: level = getattr(messages.constants, level.upper()) except AttributeError: levels = messages.constants.DEFAULT_TAGS.values() levels_repr = ', '.join('`%s`' % l for l in levels) raise ValueError('Bad message level string: `%s`. ' 'Possible values are: %s' % (level, levels_repr)) messages.add_message(request, level, message, extra_tags=extra_tags, fail_silently=fail_silently)
def queryset(
*args, **kwargs)
def wrapped(*args, **kwargs): warnings.warn( "`%s.%s` is deprecated, use `%s` instead." % (self.class_name, self.old_method_name, self.new_method_name), self.deprecation_warning, 2) return f(*args, **kwargs)
def render_change_form(
self, request, context, add=False, change=False, form_url='', obj=None)
def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None): opts = self.model._meta app_label = opts.app_label preserved_filters = self.get_preserved_filters(request) form_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, form_url) context.update({ 'add': add, 'change': change, 'has_add_permission': self.has_add_permission(request), 'has_change_permission': self.has_change_permission(request, obj), 'has_delete_permission': self.has_delete_permission(request, obj), 'has_file_field': True, # FIXME - this should check if form or formsets have a FileField, 'has_absolute_url': hasattr(self.model, 'get_absolute_url'), 'form_url': form_url, 'opts': opts, 'content_type_id': ContentType.objects.get_for_model(self.model).id, 'save_as': self.save_as, 'save_on_top': self.save_on_top, }) if add and self.add_form_template is not None: form_template = self.add_form_template else: form_template = self.change_form_template return TemplateResponse(request, form_template or [ "admin/%s/%s/change_form.html" % (app_label, opts.model_name), "admin/%s/change_form.html" % app_label, "admin/change_form.html" ], context, current_app=self.admin_site.name)
def response_action(
self, request, queryset)
Handle an admin action. This is called if a request is POSTed to the changelist; it returns an HttpResponse if the action was handled, and None otherwise.
def response_action(self, request, queryset): """ Handle an admin action. This is called if a request is POSTed to the changelist; it returns an HttpResponse if the action was handled, and None otherwise. """ # There can be multiple action forms on the page (at the top # and bottom of the change list, for example). Get the action # whose button was pushed. try: action_index = int(request.POST.get('index', 0)) except ValueError: action_index = 0 # Construct the action form. data = request.POST.copy() data.pop(helpers.ACTION_CHECKBOX_NAME, None) data.pop("index", None) # Use the action whose button was pushed try: data.update({'action': data.getlist('action')[action_index]}) except IndexError: # If we didn't get an action from the chosen form that's invalid # POST data, so by deleting action it'll fail the validation check # below. So no need to do anything here pass action_form = self.action_form(data, auto_id=None) action_form.fields['action'].choices = self.get_action_choices(request) # If the form's valid we can handle the action. if action_form.is_valid(): action = action_form.cleaned_data['action'] select_across = action_form.cleaned_data['select_across'] func = self.get_actions(request)[action][0] # Get the list of selected PKs. If nothing's selected, we can't # perform an action on it, so bail. Except we want to perform # the action explicitly on all objects. selected = request.POST.getlist(helpers.ACTION_CHECKBOX_NAME) if not selected and not select_across: # Reminder that something needs to be selected or nothing will happen msg = _("Items must be selected in order to perform " "actions on them. No items have been changed.") self.message_user(request, msg, messages.WARNING) return None if not select_across: # Perform the action only on the selected objects queryset = queryset.filter(pk__in=selected) response = func(self, request, queryset) # Actions may return an HttpResponse-like object, which will be # used as the response from the POST. If not, we'll be a good # little HTTP citizen and redirect back to the changelist page. if isinstance(response, HttpResponseBase): return response else: return HttpResponseRedirect(request.get_full_path()) else: msg = _("No action selected.") self.message_user(request, msg, messages.WARNING) return None
def response_add(
self, request, obj, post_url_continue=None)
Determines the HttpResponse for the add_view stage.
def response_add(self, request, obj, post_url_continue=None): """ Determines the HttpResponse for the add_view stage. """ opts = obj._meta pk_value = obj._get_pk_val() preserved_filters = self.get_preserved_filters(request) msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)} # Here, we distinguish between different save types by checking for # the presence of keys in request.POST. if IS_POPUP_VAR in request.POST: return SimpleTemplateResponse('admin/popup_response.html', { 'pk_value': escape(pk_value), 'obj': escapejs(obj) }) elif "_continue" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) if post_url_continue is None: post_url_continue = reverse('admin:%s_%s_change' % (opts.app_label, opts.model_name), args=(pk_value,), current_app=self.admin_site.name) post_url_continue = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url_continue) return HttpResponseRedirect(post_url_continue) elif "_addanother" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may add another %(name)s below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = request.path redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) else: msg = _('The %(name)s "%(obj)s" was added successfully.') % msg_dict self.message_user(request, msg, messages.SUCCESS) return self.response_post_save_add(request, obj)
def response_change(
self, request, obj)
Determines the HttpResponse for the change_view stage.
def response_change(self, request, obj): """ Determines the HttpResponse for the change_view stage. """ opts = self.model._meta pk_value = obj._get_pk_val() preserved_filters = self.get_preserved_filters(request) msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)} if "_continue" in request.POST: msg = _('The %(name)s "%(obj)s" was changed successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = request.path redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) elif "_saveasnew" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = reverse('admin:%s_%s_change' % (opts.app_label, opts.model_name), args=(pk_value,), current_app=self.admin_site.name) redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) elif "_addanother" in request.POST: msg = _('The %(name)s "%(obj)s" was changed successfully. You may add another %(name)s below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = reverse('admin:%s_%s_add' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) else: msg = _('The %(name)s "%(obj)s" was changed successfully.') % msg_dict self.message_user(request, msg, messages.SUCCESS) return self.response_post_save_change(request, obj)
def response_post_save_add(
self, request, obj)
Figure out where to redirect after the 'Save' button has been pressed when adding a new object.
def response_post_save_add(self, request, obj): """ Figure out where to redirect after the 'Save' button has been pressed when adding a new object. """ opts = self.model._meta if self.has_change_permission(request, None): post_url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url) else: post_url = reverse('admin:index', current_app=self.admin_site.name) return HttpResponseRedirect(post_url)
def response_post_save_change(
self, request, obj)
Figure out where to redirect after the 'Save' button has been pressed when editing an existing object.
def response_post_save_change(self, request, obj): """ Figure out where to redirect after the 'Save' button has been pressed when editing an existing object. """ opts = self.model._meta if self.has_change_permission(request, None): post_url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url) else: post_url = reverse('admin:index', current_app=self.admin_site.name) return HttpResponseRedirect(post_url)
def save_form(
self, request, form, change)
Given a ModelForm return an unsaved instance. change
is True if
the object is being changed, and False if it's being added.
def save_form(self, request, form, change): """ Given a ModelForm return an unsaved instance. ``change`` is True if the object is being changed, and False if it's being added. """ return form.save(commit=False)
def save_formset(
self, request, form, formset, change)
Given an inline formset save it to the database.
def save_formset(self, request, form, formset, change): """ Given an inline formset save it to the database. """ formset.save()
def save_model(
self, request, obj, form, change)
Given a model instance save it to the database.
def save_model(self, request, obj, form, change): """ Given a model instance save it to the database. """ obj.save()
Given the HttpRequest
, the parent ModelForm
instance, the
list of inline formsets and a boolean value based on whether the
parent is being added or changed, save the related objects to the
database. Note that at this point save_form() and save_model() have
already been called.
def to_field_allowed(
self, request, to_field)
Returns True if the model associated with this admin should be allowed to be referenced by the specified field.
def to_field_allowed(self, request, to_field): """ Returns True if the model associated with this admin should be allowed to be referenced by the specified field. """ opts = self.model._meta try: field = opts.get_field(to_field) except FieldDoesNotExist: return False # Always allow referencing the primary key since it's already possible # to get this information from the change view URL. if field.primary_key: return True # Make sure at least one of the models registered for this site # references this field through a FK or a M2M relationship. registered_models = set() for model, admin in self.admin_site._registry.items(): registered_models.add(model) for inline in admin.inlines: registered_models.add(inline.model) for related_object in opts.get_all_related_objects(include_hidden=True): related_model = related_object.model if (any(issubclass(model, related_model) for model in registered_models) and related_object.field.rel.get_related_field() == field): return True return False
def validate(
cls, model)
@classmethod def validate(cls, model): validator = cls.validator_class() validator.validate(cls, model)
class MediaItemAdmin
class MediaItemAdmin(admin.ModelAdmin): search_fields = ['title', 'code'] ordering = ['code'] exclude = ('copied_from_item', ) inlines = [MediaItemIdentifierInline, MediaItemRelatedInline, MediaItemTranscodedInline, MediaItemMarkerInline]
Ancestors (in MRO)
- MediaItemAdmin
- django.contrib.admin.options.ModelAdmin
- django.contrib.admin.options.BaseModelAdmin
- __builtin__.object
Class variables
var action_form
var actions
var actions_on_bottom
var actions_on_top
var actions_selection_counter
var add_form_template
var change_form_template
var change_list_template
var date_hierarchy
var delete_confirmation_template
var delete_selected_confirmation_template
var exclude
var fields
var fieldsets
var filter_horizontal
var filter_vertical
var form
var formfield_overrides
var inlines
var list_display
var list_display_links
var list_editable
var list_filter
var list_max_show_all
var list_per_page
var object_history_template
var ordering
var paginator
var prepopulated_fields
var preserve_filters
var radio_fields
var raw_id_fields
var readonly_fields
var save_as
var save_on_top
var search_fields
var validator_class
Instance variables
var declared_fieldsets
var media
var urls
Methods
def __init__(
self, model, admin_site)
def __init__(self, model, admin_site): self.model = model self.opts = model._meta self.admin_site = admin_site super(ModelAdmin, self).__init__()
def action_checkbox(
self, obj)
A list_display column containing a checkbox widget.
def action_checkbox(self, obj): """ A list_display column containing a checkbox widget. """ return helpers.checkbox.render(helpers.ACTION_CHECKBOX_NAME, force_text(obj.pk))
def add_view(
self, *args, **kwargs)
The 'add' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def change_view(
self, *args, **kwargs)
The 'change' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def changelist_view(
self, *args, **kwargs)
The 'change list' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def construct_change_message(
self, request, form, formsets)
Construct a change message from a changed object.
def construct_change_message(self, request, form, formsets): """ Construct a change message from a changed object. """ change_message = [] if form.changed_data: change_message.append(_('Changed %s.') % get_text_list(form.changed_data, _('and'))) if formsets: for formset in formsets: for added_object in formset.new_objects: change_message.append(_('Added %(name)s "%(object)s".') % {'name': force_text(added_object._meta.verbose_name), 'object': force_text(added_object)}) for changed_object, changed_fields in formset.changed_objects: change_message.append(_('Changed %(list)s for %(name)s "%(object)s".') % {'list': get_text_list(changed_fields, _('and')), 'name': force_text(changed_object._meta.verbose_name), 'object': force_text(changed_object)}) for deleted_object in formset.deleted_objects: change_message.append(_('Deleted %(name)s "%(object)s".') % {'name': force_text(deleted_object._meta.verbose_name), 'object': force_text(deleted_object)}) change_message = ' '.join(change_message) return change_message or _('No fields changed.')
def delete_model(
self, request, obj)
Given a model instance delete it from the database.
def delete_model(self, request, obj): """ Given a model instance delete it from the database. """ obj.delete()
def delete_view(
self, *args, **kwargs)
The 'delete' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def formfield_for_choice_field(
self, db_field, request=None, **kwargs)
Get a form Field for a database Field that has declared choices.
def formfield_for_choice_field(self, db_field, request=None, **kwargs): """ Get a form Field for a database Field that has declared choices. """ # If the field is named as a radio_field, use a RadioSelect if db_field.name in self.radio_fields: # Avoid stomping on custom widget/choices arguments. if 'widget' not in kwargs: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) if 'choices' not in kwargs: kwargs['choices'] = db_field.get_choices( include_blank=db_field.blank, blank_choice=[('', _('None'))] ) return db_field.formfield(**kwargs)
def formfield_for_dbfield(
self, db_field, **kwargs)
Hook for specifying the form Field instance for a given database Field instance.
If kwargs are given, they're passed to the form Field's constructor.
def formfield_for_dbfield(self, db_field, **kwargs): """ Hook for specifying the form Field instance for a given database Field instance. If kwargs are given, they're passed to the form Field's constructor. """ request = kwargs.pop("request", None) # If the field specifies choices, we don't need to look for special # admin widgets - we just need to use a select widget of some kind. if db_field.choices: return self.formfield_for_choice_field(db_field, request, **kwargs) # ForeignKey or ManyToManyFields if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)): # Combine the field kwargs with any options for formfield_overrides. # Make sure the passed in **kwargs override anything in # formfield_overrides because **kwargs is more specific, and should # always win. if db_field.__class__ in self.formfield_overrides: kwargs = dict(self.formfield_overrides[db_field.__class__], **kwargs) # Get the correct formfield. if isinstance(db_field, models.ForeignKey): formfield = self.formfield_for_foreignkey(db_field, request, **kwargs) elif isinstance(db_field, models.ManyToManyField): formfield = self.formfield_for_manytomany(db_field, request, **kwargs) # For non-raw_id fields, wrap the widget with a wrapper that adds # extra HTML -- the "add other" interface -- to the end of the # rendered output. formfield can be None if it came from a # OneToOneField with parent_link=True or a M2M intermediary. if formfield and db_field.name not in self.raw_id_fields: related_modeladmin = self.admin_site._registry.get( db_field.rel.to) can_add_related = bool(related_modeladmin and related_modeladmin.has_add_permission(request)) formfield.widget = widgets.RelatedFieldWidgetWrapper( formfield.widget, db_field.rel, self.admin_site, can_add_related=can_add_related) return formfield # If we've got overrides for the formfield defined, use 'em. **kwargs # passed to formfield_for_dbfield override the defaults. for klass in db_field.__class__.mro(): if klass in self.formfield_overrides: kwargs = dict(copy.deepcopy(self.formfield_overrides[klass]), **kwargs) return db_field.formfield(**kwargs) # For any other type of field, just call its formfield() method. return db_field.formfield(**kwargs)
def formfield_for_foreignkey(
self, db_field, request=None, **kwargs)
Get a form Field for a ForeignKey.
def formfield_for_foreignkey(self, db_field, request=None, **kwargs): """ Get a form Field for a ForeignKey. """ db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel, self.admin_site, using=db) elif db_field.name in self.radio_fields: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) kwargs['empty_label'] = _('None') if db_field.blank else None if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def formfield_for_manytomany(
self, db_field, request=None, **kwargs)
Get a form Field for a ManyToManyField.
def formfield_for_manytomany(self, db_field, request=None, **kwargs): """ Get a form Field for a ManyToManyField. """ # If it uses an intermediary model that isn't auto created, don't show # a field in admin. if not db_field.rel.through._meta.auto_created: return None db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel, self.admin_site, using=db) kwargs['help_text'] = '' elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)): kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical)) if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def get_action(
self, action)
Return a given action from a parameter, which can either be a callable, or the name of a method on the ModelAdmin. Return is a tuple of (callable, name, description).
def get_action(self, action): """ Return a given action from a parameter, which can either be a callable, or the name of a method on the ModelAdmin. Return is a tuple of (callable, name, description). """ # If the action is a callable, just use it. if callable(action): func = action action = action.__name__ # Next, look for a method. Grab it off self.__class__ to get an unbound # method instead of a bound one; this ensures that the calling # conventions are the same for functions and methods. elif hasattr(self.__class__, action): func = getattr(self.__class__, action) # Finally, look for a named method on the admin site else: try: func = self.admin_site.get_action(action) except KeyError: return None if hasattr(func, 'short_description'): description = func.short_description else: description = capfirst(action.replace('_', ' ')) return func, action, description
def get_action_choices(
self, request, default_choices=[(u'', u'---------')])
Return a list of choices for use in a form object. Each choice is a tuple (name, description).
def get_action_choices(self, request, default_choices=BLANK_CHOICE_DASH): """ Return a list of choices for use in a form object. Each choice is a tuple (name, description). """ choices = [] + default_choices for func, name, description in six.itervalues(self.get_actions(request)): choice = (name, description % model_format_dict(self.opts)) choices.append(choice) return choices
def get_actions(
self, request)
Return a dictionary mapping the names of all actions for this ModelAdmin to a tuple of (callable, name, description) for each action.
def get_actions(self, request): """ Return a dictionary mapping the names of all actions for this ModelAdmin to a tuple of (callable, name, description) for each action. """ # If self.actions is explicitly set to None that means that we don't # want *any* actions enabled on this page. from django.contrib.admin.views.main import _is_changelist_popup if self.actions is None or _is_changelist_popup(request): return SortedDict() actions = [] # Gather actions from the admin site first for (name, func) in self.admin_site.actions: description = getattr(func, 'short_description', name.replace('_', ' ')) actions.append((func, name, description)) # Then gather them from the model admin and all parent classes, # starting with self and working back up. for klass in self.__class__.mro()[::-1]: class_actions = getattr(klass, 'actions', []) # Avoid trying to iterate over None if not class_actions: continue actions.extend([self.get_action(action) for action in class_actions]) # get_action might have returned None, so filter any of those out. actions = filter(None, actions) # Convert the actions into a SortedDict keyed by name. actions = SortedDict([ (name, (func, name, desc)) for func, name, desc in actions ]) return actions
def get_changelist(
self, request, **kwargs)
Returns the ChangeList class for use on the changelist page.
def get_changelist(self, request, **kwargs): """ Returns the ChangeList class for use on the changelist page. """ from django.contrib.admin.views.main import ChangeList return ChangeList
def get_changelist_form(
self, request, **kwargs)
Returns a Form class for use in the Formset on the changelist page.
def get_changelist_form(self, request, **kwargs): """ Returns a Form class for use in the Formset on the changelist page. """ defaults = { "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) if (defaults.get('fields') is None and not modelform_defines_fields(defaults.get('form'))): defaults['fields'] = forms.ALL_FIELDS return modelform_factory(self.model, **defaults)
def get_changelist_formset(
self, request, **kwargs)
Returns a FormSet class for use on the changelist page if list_editable is used.
def get_changelist_formset(self, request, **kwargs): """ Returns a FormSet class for use on the changelist page if list_editable is used. """ defaults = { "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) return modelformset_factory(self.model, self.get_changelist_form(request), extra=0, fields=self.list_editable, **defaults)
def get_field_queryset(
self, db, db_field, request)
If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case).
def get_field_queryset(self, db, db_field, request): """ If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case). """ related_admin = self.admin_site._registry.get(db_field.rel.to, None) if related_admin is not None: ordering = related_admin.get_ordering(request) if ordering is not None and ordering != (): return db_field.rel.to._default_manager.using(db).order_by(*ordering).complex_filter(db_field.rel.limit_choices_to) return None
def get_fieldsets(
self, request, obj=None)
Hook for specifying fieldsets for the add form.
def get_fieldsets(self, request, obj=None): "Hook for specifying fieldsets for the add form." if self.declared_fieldsets: return self.declared_fieldsets form = self.get_form(request, obj, fields=None) fields = list(form.base_fields) + list(self.get_readonly_fields(request, obj)) return [(None, {'fields': fields})]
def get_form(
self, request, obj=None, **kwargs)
Returns a Form class for use in the admin add view. This is used by add_view and change_view.
def get_form(self, request, obj=None, **kwargs): """ Returns a Form class for use in the admin add view. This is used by add_view and change_view. """ if 'fields' in kwargs: fields = kwargs.pop('fields') else: fields = flatten_fieldsets(self.get_fieldsets(request, obj)) if self.exclude is None: exclude = [] else: exclude = list(self.exclude) exclude.extend(self.get_readonly_fields(request, obj)) if self.exclude is None and hasattr(self.form, '_meta') and self.form._meta.exclude: # Take the custom ModelForm's Meta.exclude into account only if the # ModelAdmin doesn't define its own. exclude.extend(self.form._meta.exclude) # if exclude is an empty list we pass None to be consistent with the # default on modelform_factory exclude = exclude or None defaults = { "form": self.form, "fields": fields, "exclude": exclude, "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) if defaults['fields'] is None and not modelform_defines_fields(defaults['form']): defaults['fields'] = forms.ALL_FIELDS try: return modelform_factory(self.model, **defaults) except FieldError as e: raise FieldError('%s. Check fields/fieldsets/exclude attributes of class %s.' % (e, self.__class__.__name__))
def get_formsets(
self, request, obj=None)
def get_formsets(self, request, obj=None): for inline in self.get_inline_instances(request, obj): yield inline.get_formset(request, obj)
def get_inline_instances(
self, request, obj=None)
def get_inline_instances(self, request, obj=None): inline_instances = [] for inline_class in self.inlines: inline = inline_class(self.model, self.admin_site) if request: if not (inline.has_add_permission(request) or inline.has_change_permission(request, obj) or inline.has_delete_permission(request, obj)): continue if not inline.has_add_permission(request): inline.max_num = 0 inline_instances.append(inline) return inline_instances
def get_list_display(
self, request)
Return a sequence containing the fields to be displayed on the changelist.
def get_list_display(self, request): """ Return a sequence containing the fields to be displayed on the changelist. """ return self.list_display
def get_list_display_links(
self, request, list_display)
Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display().
def get_list_display_links(self, request, list_display): """ Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display(). """ if self.list_display_links or not list_display: return self.list_display_links else: # Use only the first item in list_display as link return list(list_display)[:1]
def get_list_filter(
self, request)
Returns a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page.
def get_list_filter(self, request): """ Returns a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page. """ return self.list_filter
def get_model_perms(
self, request)
Returns a dict of all perms for this model. This dict has the keys
add
, change
, and delete
mapping to the True/False for each
of those actions.
def get_model_perms(self, request): """ Returns a dict of all perms for this model. This dict has the keys ``add``, ``change``, and ``delete`` mapping to the True/False for each of those actions. """ return { 'add': self.has_add_permission(request), 'change': self.has_change_permission(request), 'delete': self.has_delete_permission(request), }
def get_object(
self, request, object_id)
Returns an instance matching the primary key provided. None
is
returned if no match is found (or the object_id failed validation
against the primary key field).
def get_object(self, request, object_id): """ Returns an instance matching the primary key provided. ``None`` is returned if no match is found (or the object_id failed validation against the primary key field). """ queryset = self.get_queryset(request) model = queryset.model try: object_id = model._meta.pk.to_python(object_id) return queryset.get(pk=object_id) except (model.DoesNotExist, ValidationError, ValueError): return None
def get_ordering(
self, request)
Hook for specifying field ordering.
def get_ordering(self, request): """ Hook for specifying field ordering. """ return self.ordering or () # otherwise we might try to *None, which is bad ;)
def get_paginator(
self, request, queryset, per_page, orphans=0, allow_empty_first_page=True)
def get_paginator(self, request, queryset, per_page, orphans=0, allow_empty_first_page=True): return self.paginator(queryset, per_page, orphans, allow_empty_first_page)
def get_prepopulated_fields(
self, request, obj=None)
Hook for specifying custom prepopulated fields.
def get_prepopulated_fields(self, request, obj=None): """ Hook for specifying custom prepopulated fields. """ return self.prepopulated_fields
def get_preserved_filters(
self, request)
Returns the preserved filters querystring.
def get_preserved_filters(self, request): """ Returns the preserved filters querystring. """ match = request.resolver_match if self.preserve_filters and match: opts = self.model._meta current_url = '%s:%s' % (match.app_name, match.url_name) changelist_url = 'admin:%s_%s_changelist' % (opts.app_label, opts.model_name) if current_url == changelist_url: preserved_filters = request.GET.urlencode() else: preserved_filters = request.GET.get('_changelist_filters') if preserved_filters: return urlencode({'_changelist_filters': preserved_filters}) return ''
def get_queryset(
self, request)
Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view.
def get_queryset(self, request): """ Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view. """ qs = self.model._default_manager.get_queryset() # TODO: this should be handled by some parameter to the ChangeList. ordering = self.get_ordering(request) if ordering: qs = qs.order_by(*ordering) return qs
def get_readonly_fields(
self, request, obj=None)
Hook for specifying custom readonly fields.
def get_readonly_fields(self, request, obj=None): """ Hook for specifying custom readonly fields. """ return self.readonly_fields
def get_search_results(
self, request, queryset, search_term)
Returns a tuple containing a queryset to implement the search, and a boolean indicating if the results may contain duplicates.
def get_search_results(self, request, queryset, search_term): """ Returns a tuple containing a queryset to implement the search, and a boolean indicating if the results may contain duplicates. """ # Apply keyword searches. def construct_search(field_name): if field_name.startswith('^'): return "%s__istartswith" % field_name[1:] elif field_name.startswith('='): return "%s__iexact" % field_name[1:] elif field_name.startswith('@'): return "%s__search" % field_name[1:] else: return "%s__icontains" % field_name use_distinct = False if self.search_fields and search_term: orm_lookups = [construct_search(str(search_field)) for search_field in self.search_fields] for bit in search_term.split(): or_queries = [models.Q(**{orm_lookup: bit}) for orm_lookup in orm_lookups] queryset = queryset.filter(reduce(operator.or_, or_queries)) if not use_distinct: for search_spec in orm_lookups: if lookup_needs_distinct(self.opts, search_spec): use_distinct = True break return queryset, use_distinct
def get_urls(
self)
def get_urls(self): from django.conf.urls import patterns, url def wrap(view): def wrapper(*args, **kwargs): return self.admin_site.admin_view(view)(*args, **kwargs) return update_wrapper(wrapper, view) info = self.model._meta.app_label, self.model._meta.model_name urlpatterns = patterns('', url(r'^$', wrap(self.changelist_view), name='%s_%s_changelist' % info), url(r'^add/$', wrap(self.add_view), name='%s_%s_add' % info), url(r'^(.+)/history/$', wrap(self.history_view), name='%s_%s_history' % info), url(r'^(.+)/delete/$', wrap(self.delete_view), name='%s_%s_delete' % info), url(r'^(.+)/$', wrap(self.change_view), name='%s_%s_change' % info), ) return urlpatterns
def has_add_permission(
self, request)
Returns True if the given request has permission to add an object. Can be overridden by the user in subclasses.
def has_add_permission(self, request): """ Returns True if the given request has permission to add an object. Can be overridden by the user in subclasses. """ opts = self.opts codename = get_permission_codename('add', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_change_permission(
self, request, obj=None)
Returns True if the given request has permission to change the given
Django model instance, the default implementation doesn't examine the
obj
parameter.
Can be overridden by the user in subclasses. In such case it should
return True if the given request has permission to change the obj
model instance. If obj
is None, this should return True if the given
request has permission to change any object of the given type.
def has_change_permission(self, request, obj=None): """ Returns True if the given request has permission to change the given Django model instance, the default implementation doesn't examine the `obj` parameter. Can be overridden by the user in subclasses. In such case it should return True if the given request has permission to change the `obj` model instance. If `obj` is None, this should return True if the given request has permission to change *any* object of the given type. """ opts = self.opts codename = get_permission_codename('change', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_delete_permission(
self, request, obj=None)
Returns True if the given request has permission to change the given
Django model instance, the default implementation doesn't examine the
obj
parameter.
Can be overridden by the user in subclasses. In such case it should
return True if the given request has permission to delete the obj
model instance. If obj
is None, this should return True if the given
request has permission to delete any object of the given type.
def has_delete_permission(self, request, obj=None): """ Returns True if the given request has permission to change the given Django model instance, the default implementation doesn't examine the `obj` parameter. Can be overridden by the user in subclasses. In such case it should return True if the given request has permission to delete the `obj` model instance. If `obj` is None, this should return True if the given request has permission to delete *any* object of the given type. """ opts = self.opts codename = get_permission_codename('delete', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def history_view(
self, request, object_id, extra_context=None)
The 'history' admin view for this model.
def history_view(self, request, object_id, extra_context=None): "The 'history' admin view for this model." from django.contrib.admin.models import LogEntry # First check if the user can see this history. model = self.model obj = get_object_or_404(model, pk=unquote(object_id)) if not self.has_change_permission(request, obj): raise PermissionDenied # Then get the history for this object. opts = model._meta app_label = opts.app_label action_list = LogEntry.objects.filter( object_id=unquote(object_id), content_type__id__exact=ContentType.objects.get_for_model(model).id ).select_related().order_by('action_time') context = { 'title': _('Change history: %s') % force_text(obj), 'action_list': action_list, 'module_name': capfirst(force_text(opts.verbose_name_plural)), 'object': obj, 'app_label': app_label, 'opts': opts, 'preserved_filters': self.get_preserved_filters(request), } context.update(extra_context or {}) return TemplateResponse(request, self.object_history_template or [ "admin/%s/%s/object_history.html" % (app_label, opts.model_name), "admin/%s/object_history.html" % app_label, "admin/object_history.html" ], context, current_app=self.admin_site.name)
def log_addition(
self, request, object)
Log that an object has been successfully added.
The default implementation creates an admin LogEntry object.
def log_addition(self, request, object): """ Log that an object has been successfully added. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, ADDITION LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=ADDITION )
def log_change(
self, request, object, message)
Log that an object has been successfully changed.
The default implementation creates an admin LogEntry object.
def log_change(self, request, object, message): """ Log that an object has been successfully changed. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, CHANGE LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=CHANGE, change_message=message )
def log_deletion(
self, request, object, object_repr)
Log that an object will be deleted. Note that this method is called before the deletion.
The default implementation creates an admin LogEntry object.
def log_deletion(self, request, object, object_repr): """ Log that an object will be deleted. Note that this method is called before the deletion. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, DELETION LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(self.model).pk, object_id=object.pk, object_repr=object_repr, action_flag=DELETION )
def lookup_allowed(
self, lookup, value)
def lookup_allowed(self, lookup, value): model = self.model # Check FKey lookups that are allowed, so that popups produced by # ForeignKeyRawIdWidget, on the basis of ForeignKey.limit_choices_to, # are allowed to work. for l in model._meta.related_fkey_lookups: for k, v in widgets.url_params_from_lookup_dict(l).items(): if k == lookup and v == value: return True parts = lookup.split(LOOKUP_SEP) # Last term in lookup is a query term (__exact, __startswith etc) # This term can be ignored. if len(parts) > 1 and parts[-1] in QUERY_TERMS: parts.pop() # Special case -- foo__id__exact and foo__id queries are implied # if foo has been specifically included in the lookup list; so # drop __id if it is the last part. However, first we need to find # the pk attribute name. rel_name = None for part in parts[:-1]: try: field, _, _, _ = model._meta.get_field_by_name(part) except FieldDoesNotExist: # Lookups on non-existent fields are ok, since they're ignored # later. return True if hasattr(field, 'rel'): if field.rel is None: # This property or relation doesn't exist, but it's allowed # since it's ignored in ChangeList.get_filters(). return True model = field.rel.to rel_name = field.rel.get_related_field().name elif isinstance(field, RelatedObject): model = field.model rel_name = model._meta.pk.name else: rel_name = None if rel_name and len(parts) > 1 and parts[-1] == rel_name: parts.pop() if len(parts) == 1: return True clean_lookup = LOOKUP_SEP.join(parts) return clean_lookup in self.list_filter or clean_lookup == self.date_hierarchy
def message_user(
self, request, message, level=20, extra_tags='', fail_silently=False)
Send a message to the user. The default implementation posts a message using the django.contrib.messages backend.
Exposes almost the same API as messages.add_message(), but accepts the
positional arguments in a different order to maintain backwards
compatibility. For convenience, it accepts the level
argument as
a string rather than the usual level number.
def message_user(self, request, message, level=messages.INFO, extra_tags='', fail_silently=False): """ Send a message to the user. The default implementation posts a message using the django.contrib.messages backend. Exposes almost the same API as messages.add_message(), but accepts the positional arguments in a different order to maintain backwards compatibility. For convenience, it accepts the `level` argument as a string rather than the usual level number. """ if not isinstance(level, int): # attempt to get the level if passed a string try: level = getattr(messages.constants, level.upper()) except AttributeError: levels = messages.constants.DEFAULT_TAGS.values() levels_repr = ', '.join('`%s`' % l for l in levels) raise ValueError('Bad message level string: `%s`. ' 'Possible values are: %s' % (level, levels_repr)) messages.add_message(request, level, message, extra_tags=extra_tags, fail_silently=fail_silently)
def queryset(
*args, **kwargs)
def wrapped(*args, **kwargs): warnings.warn( "`%s.%s` is deprecated, use `%s` instead." % (self.class_name, self.old_method_name, self.new_method_name), self.deprecation_warning, 2) return f(*args, **kwargs)
def render_change_form(
self, request, context, add=False, change=False, form_url='', obj=None)
def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None): opts = self.model._meta app_label = opts.app_label preserved_filters = self.get_preserved_filters(request) form_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, form_url) context.update({ 'add': add, 'change': change, 'has_add_permission': self.has_add_permission(request), 'has_change_permission': self.has_change_permission(request, obj), 'has_delete_permission': self.has_delete_permission(request, obj), 'has_file_field': True, # FIXME - this should check if form or formsets have a FileField, 'has_absolute_url': hasattr(self.model, 'get_absolute_url'), 'form_url': form_url, 'opts': opts, 'content_type_id': ContentType.objects.get_for_model(self.model).id, 'save_as': self.save_as, 'save_on_top': self.save_on_top, }) if add and self.add_form_template is not None: form_template = self.add_form_template else: form_template = self.change_form_template return TemplateResponse(request, form_template or [ "admin/%s/%s/change_form.html" % (app_label, opts.model_name), "admin/%s/change_form.html" % app_label, "admin/change_form.html" ], context, current_app=self.admin_site.name)
def response_action(
self, request, queryset)
Handle an admin action. This is called if a request is POSTed to the changelist; it returns an HttpResponse if the action was handled, and None otherwise.
def response_action(self, request, queryset): """ Handle an admin action. This is called if a request is POSTed to the changelist; it returns an HttpResponse if the action was handled, and None otherwise. """ # There can be multiple action forms on the page (at the top # and bottom of the change list, for example). Get the action # whose button was pushed. try: action_index = int(request.POST.get('index', 0)) except ValueError: action_index = 0 # Construct the action form. data = request.POST.copy() data.pop(helpers.ACTION_CHECKBOX_NAME, None) data.pop("index", None) # Use the action whose button was pushed try: data.update({'action': data.getlist('action')[action_index]}) except IndexError: # If we didn't get an action from the chosen form that's invalid # POST data, so by deleting action it'll fail the validation check # below. So no need to do anything here pass action_form = self.action_form(data, auto_id=None) action_form.fields['action'].choices = self.get_action_choices(request) # If the form's valid we can handle the action. if action_form.is_valid(): action = action_form.cleaned_data['action'] select_across = action_form.cleaned_data['select_across'] func = self.get_actions(request)[action][0] # Get the list of selected PKs. If nothing's selected, we can't # perform an action on it, so bail. Except we want to perform # the action explicitly on all objects. selected = request.POST.getlist(helpers.ACTION_CHECKBOX_NAME) if not selected and not select_across: # Reminder that something needs to be selected or nothing will happen msg = _("Items must be selected in order to perform " "actions on them. No items have been changed.") self.message_user(request, msg, messages.WARNING) return None if not select_across: # Perform the action only on the selected objects queryset = queryset.filter(pk__in=selected) response = func(self, request, queryset) # Actions may return an HttpResponse-like object, which will be # used as the response from the POST. If not, we'll be a good # little HTTP citizen and redirect back to the changelist page. if isinstance(response, HttpResponseBase): return response else: return HttpResponseRedirect(request.get_full_path()) else: msg = _("No action selected.") self.message_user(request, msg, messages.WARNING) return None
def response_add(
self, request, obj, post_url_continue=None)
Determines the HttpResponse for the add_view stage.
def response_add(self, request, obj, post_url_continue=None): """ Determines the HttpResponse for the add_view stage. """ opts = obj._meta pk_value = obj._get_pk_val() preserved_filters = self.get_preserved_filters(request) msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)} # Here, we distinguish between different save types by checking for # the presence of keys in request.POST. if IS_POPUP_VAR in request.POST: return SimpleTemplateResponse('admin/popup_response.html', { 'pk_value': escape(pk_value), 'obj': escapejs(obj) }) elif "_continue" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) if post_url_continue is None: post_url_continue = reverse('admin:%s_%s_change' % (opts.app_label, opts.model_name), args=(pk_value,), current_app=self.admin_site.name) post_url_continue = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url_continue) return HttpResponseRedirect(post_url_continue) elif "_addanother" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may add another %(name)s below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = request.path redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) else: msg = _('The %(name)s "%(obj)s" was added successfully.') % msg_dict self.message_user(request, msg, messages.SUCCESS) return self.response_post_save_add(request, obj)
def response_change(
self, request, obj)
Determines the HttpResponse for the change_view stage.
def response_change(self, request, obj): """ Determines the HttpResponse for the change_view stage. """ opts = self.model._meta pk_value = obj._get_pk_val() preserved_filters = self.get_preserved_filters(request) msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)} if "_continue" in request.POST: msg = _('The %(name)s "%(obj)s" was changed successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = request.path redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) elif "_saveasnew" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = reverse('admin:%s_%s_change' % (opts.app_label, opts.model_name), args=(pk_value,), current_app=self.admin_site.name) redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) elif "_addanother" in request.POST: msg = _('The %(name)s "%(obj)s" was changed successfully. You may add another %(name)s below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = reverse('admin:%s_%s_add' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) else: msg = _('The %(name)s "%(obj)s" was changed successfully.') % msg_dict self.message_user(request, msg, messages.SUCCESS) return self.response_post_save_change(request, obj)
def response_post_save_add(
self, request, obj)
Figure out where to redirect after the 'Save' button has been pressed when adding a new object.
def response_post_save_add(self, request, obj): """ Figure out where to redirect after the 'Save' button has been pressed when adding a new object. """ opts = self.model._meta if self.has_change_permission(request, None): post_url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url) else: post_url = reverse('admin:index', current_app=self.admin_site.name) return HttpResponseRedirect(post_url)
def response_post_save_change(
self, request, obj)
Figure out where to redirect after the 'Save' button has been pressed when editing an existing object.
def response_post_save_change(self, request, obj): """ Figure out where to redirect after the 'Save' button has been pressed when editing an existing object. """ opts = self.model._meta if self.has_change_permission(request, None): post_url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url) else: post_url = reverse('admin:index', current_app=self.admin_site.name) return HttpResponseRedirect(post_url)
def save_form(
self, request, form, change)
Given a ModelForm return an unsaved instance. change
is True if
the object is being changed, and False if it's being added.
def save_form(self, request, form, change): """ Given a ModelForm return an unsaved instance. ``change`` is True if the object is being changed, and False if it's being added. """ return form.save(commit=False)
def save_formset(
self, request, form, formset, change)
Given an inline formset save it to the database.
def save_formset(self, request, form, formset, change): """ Given an inline formset save it to the database. """ formset.save()
def save_model(
self, request, obj, form, change)
Given a model instance save it to the database.
def save_model(self, request, obj, form, change): """ Given a model instance save it to the database. """ obj.save()
Given the HttpRequest
, the parent ModelForm
instance, the
list of inline formsets and a boolean value based on whether the
parent is being added or changed, save the related objects to the
database. Note that at this point save_form() and save_model() have
already been called.
def to_field_allowed(
self, request, to_field)
Returns True if the model associated with this admin should be allowed to be referenced by the specified field.
def to_field_allowed(self, request, to_field): """ Returns True if the model associated with this admin should be allowed to be referenced by the specified field. """ opts = self.model._meta try: field = opts.get_field(to_field) except FieldDoesNotExist: return False # Always allow referencing the primary key since it's already possible # to get this information from the change view URL. if field.primary_key: return True # Make sure at least one of the models registered for this site # references this field through a FK or a M2M relationship. registered_models = set() for model, admin in self.admin_site._registry.items(): registered_models.add(model) for inline in admin.inlines: registered_models.add(inline.model) for related_object in opts.get_all_related_objects(include_hidden=True): related_model = related_object.model if (any(issubclass(model, related_model) for model in registered_models) and related_object.field.rel.get_related_field() == field): return True return False
def validate(
cls, model)
@classmethod def validate(cls, model): validator = cls.validator_class() validator.validate(cls, model)
class MediaItemIdentifierInline
class MediaItemIdentifierInline(admin.StackedInline): model = MediaItemIdentifier max_num = 1
Ancestors (in MRO)
- MediaItemIdentifierInline
- django.contrib.admin.options.StackedInline
- django.contrib.admin.options.InlineModelAdmin
- django.contrib.admin.options.BaseModelAdmin
- __builtin__.object
Class variables
var can_delete
var exclude
var extra
var fields
var fieldsets
var filter_horizontal
var filter_vertical
var fk_name
var form
var formfield_overrides
var formset
var max_num
var model
var ordering
var prepopulated_fields
var radio_fields
var raw_id_fields
var readonly_fields
var template
var validator_class
var verbose_name
var verbose_name_plural
Instance variables
var declared_fieldsets
var media
Methods
def __init__(
self, parent_model, admin_site)
def __init__(self, parent_model, admin_site): self.admin_site = admin_site self.parent_model = parent_model self.opts = self.model._meta super(InlineModelAdmin, self).__init__() if self.verbose_name is None: self.verbose_name = self.model._meta.verbose_name if self.verbose_name_plural is None: self.verbose_name_plural = self.model._meta.verbose_name_plural
def formfield_for_choice_field(
self, db_field, request=None, **kwargs)
Get a form Field for a database Field that has declared choices.
def formfield_for_choice_field(self, db_field, request=None, **kwargs): """ Get a form Field for a database Field that has declared choices. """ # If the field is named as a radio_field, use a RadioSelect if db_field.name in self.radio_fields: # Avoid stomping on custom widget/choices arguments. if 'widget' not in kwargs: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) if 'choices' not in kwargs: kwargs['choices'] = db_field.get_choices( include_blank=db_field.blank, blank_choice=[('', _('None'))] ) return db_field.formfield(**kwargs)
def formfield_for_dbfield(
self, db_field, **kwargs)
Hook for specifying the form Field instance for a given database Field instance.
If kwargs are given, they're passed to the form Field's constructor.
def formfield_for_dbfield(self, db_field, **kwargs): """ Hook for specifying the form Field instance for a given database Field instance. If kwargs are given, they're passed to the form Field's constructor. """ request = kwargs.pop("request", None) # If the field specifies choices, we don't need to look for special # admin widgets - we just need to use a select widget of some kind. if db_field.choices: return self.formfield_for_choice_field(db_field, request, **kwargs) # ForeignKey or ManyToManyFields if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)): # Combine the field kwargs with any options for formfield_overrides. # Make sure the passed in **kwargs override anything in # formfield_overrides because **kwargs is more specific, and should # always win. if db_field.__class__ in self.formfield_overrides: kwargs = dict(self.formfield_overrides[db_field.__class__], **kwargs) # Get the correct formfield. if isinstance(db_field, models.ForeignKey): formfield = self.formfield_for_foreignkey(db_field, request, **kwargs) elif isinstance(db_field, models.ManyToManyField): formfield = self.formfield_for_manytomany(db_field, request, **kwargs) # For non-raw_id fields, wrap the widget with a wrapper that adds # extra HTML -- the "add other" interface -- to the end of the # rendered output. formfield can be None if it came from a # OneToOneField with parent_link=True or a M2M intermediary. if formfield and db_field.name not in self.raw_id_fields: related_modeladmin = self.admin_site._registry.get( db_field.rel.to) can_add_related = bool(related_modeladmin and related_modeladmin.has_add_permission(request)) formfield.widget = widgets.RelatedFieldWidgetWrapper( formfield.widget, db_field.rel, self.admin_site, can_add_related=can_add_related) return formfield # If we've got overrides for the formfield defined, use 'em. **kwargs # passed to formfield_for_dbfield override the defaults. for klass in db_field.__class__.mro(): if klass in self.formfield_overrides: kwargs = dict(copy.deepcopy(self.formfield_overrides[klass]), **kwargs) return db_field.formfield(**kwargs) # For any other type of field, just call its formfield() method. return db_field.formfield(**kwargs)
def formfield_for_foreignkey(
self, db_field, request=None, **kwargs)
Get a form Field for a ForeignKey.
def formfield_for_foreignkey(self, db_field, request=None, **kwargs): """ Get a form Field for a ForeignKey. """ db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel, self.admin_site, using=db) elif db_field.name in self.radio_fields: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) kwargs['empty_label'] = _('None') if db_field.blank else None if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def formfield_for_manytomany(
self, db_field, request=None, **kwargs)
Get a form Field for a ManyToManyField.
def formfield_for_manytomany(self, db_field, request=None, **kwargs): """ Get a form Field for a ManyToManyField. """ # If it uses an intermediary model that isn't auto created, don't show # a field in admin. if not db_field.rel.through._meta.auto_created: return None db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel, self.admin_site, using=db) kwargs['help_text'] = '' elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)): kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical)) if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def get_extra(
self, request, obj=None, **kwargs)
Hook for customizing the number of extra inline forms.
def get_extra(self, request, obj=None, **kwargs): """Hook for customizing the number of extra inline forms.""" return self.extra
def get_field_queryset(
self, db, db_field, request)
If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case).
def get_field_queryset(self, db, db_field, request): """ If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case). """ related_admin = self.admin_site._registry.get(db_field.rel.to, None) if related_admin is not None: ordering = related_admin.get_ordering(request) if ordering is not None and ordering != (): return db_field.rel.to._default_manager.using(db).order_by(*ordering).complex_filter(db_field.rel.limit_choices_to) return None
def get_fieldsets(
self, request, obj=None)
def get_fieldsets(self, request, obj=None): if self.declared_fieldsets: return self.declared_fieldsets form = self.get_formset(request, obj, fields=None).form fields = list(form.base_fields) + list(self.get_readonly_fields(request, obj)) return [(None, {'fields': fields})]
def get_formset(
self, request, obj=None, **kwargs)
Returns a BaseInlineFormSet class for use in admin add/change views.
def get_formset(self, request, obj=None, **kwargs): """Returns a BaseInlineFormSet class for use in admin add/change views.""" if 'fields' in kwargs: fields = kwargs.pop('fields') else: fields = flatten_fieldsets(self.get_fieldsets(request, obj)) if self.exclude is None: exclude = [] else: exclude = list(self.exclude) exclude.extend(self.get_readonly_fields(request, obj)) if self.exclude is None and hasattr(self.form, '_meta') and self.form._meta.exclude: # Take the custom ModelForm's Meta.exclude into account only if the # InlineModelAdmin doesn't define its own. exclude.extend(self.form._meta.exclude) # If exclude is an empty list we use None, since that's the actual # default. exclude = exclude or None can_delete = self.can_delete and self.has_delete_permission(request, obj) defaults = { "form": self.form, "formset": self.formset, "fk_name": self.fk_name, "fields": fields, "exclude": exclude, "formfield_callback": partial(self.formfield_for_dbfield, request=request), "extra": self.get_extra(request, obj, **kwargs), "max_num": self.get_max_num(request, obj, **kwargs), "can_delete": can_delete, } defaults.update(kwargs) base_model_form = defaults['form'] class DeleteProtectedModelForm(base_model_form): def hand_clean_DELETE(self): """ We don't validate the 'DELETE' field itself because on templates it's not rendered using the field information, but just using a generic "deletion_field" of the InlineModelAdmin. """ if self.cleaned_data.get(DELETION_FIELD_NAME, False): using = router.db_for_write(self._meta.model) collector = NestedObjects(using=using) collector.collect([self.instance]) if collector.protected: objs = [] for p in collector.protected: objs.append( # Translators: Model verbose name and instance representation, suitable to be an item in a list _('%(class_name)s %(instance)s') % { 'class_name': p._meta.verbose_name, 'instance': p} ) params = {'class_name': self._meta.model._meta.verbose_name, 'instance': self.instance, 'related_objects': get_text_list(objs, _('and'))} msg = _("Deleting %(class_name)s %(instance)s would require " "deleting the following protected related objects: " "%(related_objects)s") raise ValidationError(msg, code='deleting_protected', params=params) def is_valid(self): result = super(DeleteProtectedModelForm, self).is_valid() self.hand_clean_DELETE() return result defaults['form'] = DeleteProtectedModelForm if defaults['fields'] is None and not modelform_defines_fields(defaults['form']): defaults['fields'] = forms.ALL_FIELDS return inlineformset_factory(self.parent_model, self.model, **defaults)
def get_max_num(
self, request, obj=None, **kwargs)
Hook for customizing the max number of extra inline forms.
def get_max_num(self, request, obj=None, **kwargs): """Hook for customizing the max number of extra inline forms.""" return self.max_num
def get_ordering(
self, request)
Hook for specifying field ordering.
def get_ordering(self, request): """ Hook for specifying field ordering. """ return self.ordering or () # otherwise we might try to *None, which is bad ;)
def get_prepopulated_fields(
self, request, obj=None)
Hook for specifying custom prepopulated fields.
def get_prepopulated_fields(self, request, obj=None): """ Hook for specifying custom prepopulated fields. """ return self.prepopulated_fields
def get_queryset(
self, request)
def get_queryset(self, request): queryset = super(InlineModelAdmin, self).get_queryset(request) if not self.has_change_permission(request): queryset = queryset.none() return queryset
def get_readonly_fields(
self, request, obj=None)
Hook for specifying custom readonly fields.
def get_readonly_fields(self, request, obj=None): """ Hook for specifying custom readonly fields. """ return self.readonly_fields
def has_add_permission(
self, request)
def has_add_permission(self, request): if self.opts.auto_created: # We're checking the rights to an auto-created intermediate model, # which doesn't have its own individual permissions. The user needs # to have the change permission for the related model in order to # be able to do anything with the intermediate model. return self.has_change_permission(request) return super(InlineModelAdmin, self).has_add_permission(request)
def has_change_permission(
self, request, obj=None)
def has_change_permission(self, request, obj=None): opts = self.opts if opts.auto_created: # The model was auto-created as intermediary for a # ManyToMany-relationship, find the target model for field in opts.fields: if field.rel and field.rel.to != self.parent_model: opts = field.rel.to._meta break codename = get_permission_codename('change', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_delete_permission(
self, request, obj=None)
def has_delete_permission(self, request, obj=None): if self.opts.auto_created: # We're checking the rights to an auto-created intermediate model, # which doesn't have its own individual permissions. The user needs # to have the change permission for the related model in order to # be able to do anything with the intermediate model. return self.has_change_permission(request, obj) return super(InlineModelAdmin, self).has_delete_permission(request, obj)
def lookup_allowed(
self, lookup, value)
def lookup_allowed(self, lookup, value): model = self.model # Check FKey lookups that are allowed, so that popups produced by # ForeignKeyRawIdWidget, on the basis of ForeignKey.limit_choices_to, # are allowed to work. for l in model._meta.related_fkey_lookups: for k, v in widgets.url_params_from_lookup_dict(l).items(): if k == lookup and v == value: return True parts = lookup.split(LOOKUP_SEP) # Last term in lookup is a query term (__exact, __startswith etc) # This term can be ignored. if len(parts) > 1 and parts[-1] in QUERY_TERMS: parts.pop() # Special case -- foo__id__exact and foo__id queries are implied # if foo has been specifically included in the lookup list; so # drop __id if it is the last part. However, first we need to find # the pk attribute name. rel_name = None for part in parts[:-1]: try: field, _, _, _ = model._meta.get_field_by_name(part) except FieldDoesNotExist: # Lookups on non-existent fields are ok, since they're ignored # later. return True if hasattr(field, 'rel'): if field.rel is None: # This property or relation doesn't exist, but it's allowed # since it's ignored in ChangeList.get_filters(). return True model = field.rel.to rel_name = field.rel.get_related_field().name elif isinstance(field, RelatedObject): model = field.model rel_name = model._meta.pk.name else: rel_name = None if rel_name and len(parts) > 1 and parts[-1] == rel_name: parts.pop() if len(parts) == 1: return True clean_lookup = LOOKUP_SEP.join(parts) return clean_lookup in self.list_filter or clean_lookup == self.date_hierarchy
def queryset(
*args, **kwargs)
def wrapped(*args, **kwargs): warnings.warn( "`%s.%s` is deprecated, use `%s` instead." % (self.class_name, self.old_method_name, self.new_method_name), self.deprecation_warning, 2) return f(*args, **kwargs)
def to_field_allowed(
self, request, to_field)
Returns True if the model associated with this admin should be allowed to be referenced by the specified field.
def to_field_allowed(self, request, to_field): """ Returns True if the model associated with this admin should be allowed to be referenced by the specified field. """ opts = self.model._meta try: field = opts.get_field(to_field) except FieldDoesNotExist: return False # Always allow referencing the primary key since it's already possible # to get this information from the change view URL. if field.primary_key: return True # Make sure at least one of the models registered for this site # references this field through a FK or a M2M relationship. registered_models = set() for model, admin in self.admin_site._registry.items(): registered_models.add(model) for inline in admin.inlines: registered_models.add(inline.model) for related_object in opts.get_all_related_objects(include_hidden=True): related_model = related_object.model if (any(issubclass(model, related_model) for model in registered_models) and related_object.field.rel.get_related_field() == field): return True return False
def validate(
cls, model)
@classmethod def validate(cls, model): validator = cls.validator_class() validator.validate(cls, model)
class MediaItemMarkerInline
class MediaItemMarkerInline(admin.StackedInline): model = MediaItemMarker
Ancestors (in MRO)
- MediaItemMarkerInline
- django.contrib.admin.options.StackedInline
- django.contrib.admin.options.InlineModelAdmin
- django.contrib.admin.options.BaseModelAdmin
- __builtin__.object
Class variables
var can_delete
var exclude
var extra
var fields
var fieldsets
var filter_horizontal
var filter_vertical
var fk_name
var form
var formfield_overrides
var formset
var max_num
var model
var ordering
var prepopulated_fields
var radio_fields
var raw_id_fields
var readonly_fields
var template
var validator_class
var verbose_name
var verbose_name_plural
Instance variables
var declared_fieldsets
var media
Methods
def __init__(
self, parent_model, admin_site)
def __init__(self, parent_model, admin_site): self.admin_site = admin_site self.parent_model = parent_model self.opts = self.model._meta super(InlineModelAdmin, self).__init__() if self.verbose_name is None: self.verbose_name = self.model._meta.verbose_name if self.verbose_name_plural is None: self.verbose_name_plural = self.model._meta.verbose_name_plural
def formfield_for_choice_field(
self, db_field, request=None, **kwargs)
Get a form Field for a database Field that has declared choices.
def formfield_for_choice_field(self, db_field, request=None, **kwargs): """ Get a form Field for a database Field that has declared choices. """ # If the field is named as a radio_field, use a RadioSelect if db_field.name in self.radio_fields: # Avoid stomping on custom widget/choices arguments. if 'widget' not in kwargs: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) if 'choices' not in kwargs: kwargs['choices'] = db_field.get_choices( include_blank=db_field.blank, blank_choice=[('', _('None'))] ) return db_field.formfield(**kwargs)
def formfield_for_dbfield(
self, db_field, **kwargs)
Hook for specifying the form Field instance for a given database Field instance.
If kwargs are given, they're passed to the form Field's constructor.
def formfield_for_dbfield(self, db_field, **kwargs): """ Hook for specifying the form Field instance for a given database Field instance. If kwargs are given, they're passed to the form Field's constructor. """ request = kwargs.pop("request", None) # If the field specifies choices, we don't need to look for special # admin widgets - we just need to use a select widget of some kind. if db_field.choices: return self.formfield_for_choice_field(db_field, request, **kwargs) # ForeignKey or ManyToManyFields if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)): # Combine the field kwargs with any options for formfield_overrides. # Make sure the passed in **kwargs override anything in # formfield_overrides because **kwargs is more specific, and should # always win. if db_field.__class__ in self.formfield_overrides: kwargs = dict(self.formfield_overrides[db_field.__class__], **kwargs) # Get the correct formfield. if isinstance(db_field, models.ForeignKey): formfield = self.formfield_for_foreignkey(db_field, request, **kwargs) elif isinstance(db_field, models.ManyToManyField): formfield = self.formfield_for_manytomany(db_field, request, **kwargs) # For non-raw_id fields, wrap the widget with a wrapper that adds # extra HTML -- the "add other" interface -- to the end of the # rendered output. formfield can be None if it came from a # OneToOneField with parent_link=True or a M2M intermediary. if formfield and db_field.name not in self.raw_id_fields: related_modeladmin = self.admin_site._registry.get( db_field.rel.to) can_add_related = bool(related_modeladmin and related_modeladmin.has_add_permission(request)) formfield.widget = widgets.RelatedFieldWidgetWrapper( formfield.widget, db_field.rel, self.admin_site, can_add_related=can_add_related) return formfield # If we've got overrides for the formfield defined, use 'em. **kwargs # passed to formfield_for_dbfield override the defaults. for klass in db_field.__class__.mro(): if klass in self.formfield_overrides: kwargs = dict(copy.deepcopy(self.formfield_overrides[klass]), **kwargs) return db_field.formfield(**kwargs) # For any other type of field, just call its formfield() method. return db_field.formfield(**kwargs)
def formfield_for_foreignkey(
self, db_field, request=None, **kwargs)
Get a form Field for a ForeignKey.
def formfield_for_foreignkey(self, db_field, request=None, **kwargs): """ Get a form Field for a ForeignKey. """ db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel, self.admin_site, using=db) elif db_field.name in self.radio_fields: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) kwargs['empty_label'] = _('None') if db_field.blank else None if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def formfield_for_manytomany(
self, db_field, request=None, **kwargs)
Get a form Field for a ManyToManyField.
def formfield_for_manytomany(self, db_field, request=None, **kwargs): """ Get a form Field for a ManyToManyField. """ # If it uses an intermediary model that isn't auto created, don't show # a field in admin. if not db_field.rel.through._meta.auto_created: return None db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel, self.admin_site, using=db) kwargs['help_text'] = '' elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)): kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical)) if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def get_extra(
self, request, obj=None, **kwargs)
Hook for customizing the number of extra inline forms.
def get_extra(self, request, obj=None, **kwargs): """Hook for customizing the number of extra inline forms.""" return self.extra
def get_field_queryset(
self, db, db_field, request)
If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case).
def get_field_queryset(self, db, db_field, request): """ If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case). """ related_admin = self.admin_site._registry.get(db_field.rel.to, None) if related_admin is not None: ordering = related_admin.get_ordering(request) if ordering is not None and ordering != (): return db_field.rel.to._default_manager.using(db).order_by(*ordering).complex_filter(db_field.rel.limit_choices_to) return None
def get_fieldsets(
self, request, obj=None)
def get_fieldsets(self, request, obj=None): if self.declared_fieldsets: return self.declared_fieldsets form = self.get_formset(request, obj, fields=None).form fields = list(form.base_fields) + list(self.get_readonly_fields(request, obj)) return [(None, {'fields': fields})]
def get_formset(
self, request, obj=None, **kwargs)
Returns a BaseInlineFormSet class for use in admin add/change views.
def get_formset(self, request, obj=None, **kwargs): """Returns a BaseInlineFormSet class for use in admin add/change views.""" if 'fields' in kwargs: fields = kwargs.pop('fields') else: fields = flatten_fieldsets(self.get_fieldsets(request, obj)) if self.exclude is None: exclude = [] else: exclude = list(self.exclude) exclude.extend(self.get_readonly_fields(request, obj)) if self.exclude is None and hasattr(self.form, '_meta') and self.form._meta.exclude: # Take the custom ModelForm's Meta.exclude into account only if the # InlineModelAdmin doesn't define its own. exclude.extend(self.form._meta.exclude) # If exclude is an empty list we use None, since that's the actual # default. exclude = exclude or None can_delete = self.can_delete and self.has_delete_permission(request, obj) defaults = { "form": self.form, "formset": self.formset, "fk_name": self.fk_name, "fields": fields, "exclude": exclude, "formfield_callback": partial(self.formfield_for_dbfield, request=request), "extra": self.get_extra(request, obj, **kwargs), "max_num": self.get_max_num(request, obj, **kwargs), "can_delete": can_delete, } defaults.update(kwargs) base_model_form = defaults['form'] class DeleteProtectedModelForm(base_model_form): def hand_clean_DELETE(self): """ We don't validate the 'DELETE' field itself because on templates it's not rendered using the field information, but just using a generic "deletion_field" of the InlineModelAdmin. """ if self.cleaned_data.get(DELETION_FIELD_NAME, False): using = router.db_for_write(self._meta.model) collector = NestedObjects(using=using) collector.collect([self.instance]) if collector.protected: objs = [] for p in collector.protected: objs.append( # Translators: Model verbose name and instance representation, suitable to be an item in a list _('%(class_name)s %(instance)s') % { 'class_name': p._meta.verbose_name, 'instance': p} ) params = {'class_name': self._meta.model._meta.verbose_name, 'instance': self.instance, 'related_objects': get_text_list(objs, _('and'))} msg = _("Deleting %(class_name)s %(instance)s would require " "deleting the following protected related objects: " "%(related_objects)s") raise ValidationError(msg, code='deleting_protected', params=params) def is_valid(self): result = super(DeleteProtectedModelForm, self).is_valid() self.hand_clean_DELETE() return result defaults['form'] = DeleteProtectedModelForm if defaults['fields'] is None and not modelform_defines_fields(defaults['form']): defaults['fields'] = forms.ALL_FIELDS return inlineformset_factory(self.parent_model, self.model, **defaults)
def get_max_num(
self, request, obj=None, **kwargs)
Hook for customizing the max number of extra inline forms.
def get_max_num(self, request, obj=None, **kwargs): """Hook for customizing the max number of extra inline forms.""" return self.max_num
def get_ordering(
self, request)
Hook for specifying field ordering.
def get_ordering(self, request): """ Hook for specifying field ordering. """ return self.ordering or () # otherwise we might try to *None, which is bad ;)
def get_prepopulated_fields(
self, request, obj=None)
Hook for specifying custom prepopulated fields.
def get_prepopulated_fields(self, request, obj=None): """ Hook for specifying custom prepopulated fields. """ return self.prepopulated_fields
def get_queryset(
self, request)
def get_queryset(self, request): queryset = super(InlineModelAdmin, self).get_queryset(request) if not self.has_change_permission(request): queryset = queryset.none() return queryset
def get_readonly_fields(
self, request, obj=None)
Hook for specifying custom readonly fields.
def get_readonly_fields(self, request, obj=None): """ Hook for specifying custom readonly fields. """ return self.readonly_fields
def has_add_permission(
self, request)
def has_add_permission(self, request): if self.opts.auto_created: # We're checking the rights to an auto-created intermediate model, # which doesn't have its own individual permissions. The user needs # to have the change permission for the related model in order to # be able to do anything with the intermediate model. return self.has_change_permission(request) return super(InlineModelAdmin, self).has_add_permission(request)
def has_change_permission(
self, request, obj=None)
def has_change_permission(self, request, obj=None): opts = self.opts if opts.auto_created: # The model was auto-created as intermediary for a # ManyToMany-relationship, find the target model for field in opts.fields: if field.rel and field.rel.to != self.parent_model: opts = field.rel.to._meta break codename = get_permission_codename('change', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_delete_permission(
self, request, obj=None)
def has_delete_permission(self, request, obj=None): if self.opts.auto_created: # We're checking the rights to an auto-created intermediate model, # which doesn't have its own individual permissions. The user needs # to have the change permission for the related model in order to # be able to do anything with the intermediate model. return self.has_change_permission(request, obj) return super(InlineModelAdmin, self).has_delete_permission(request, obj)
def lookup_allowed(
self, lookup, value)
def lookup_allowed(self, lookup, value): model = self.model # Check FKey lookups that are allowed, so that popups produced by # ForeignKeyRawIdWidget, on the basis of ForeignKey.limit_choices_to, # are allowed to work. for l in model._meta.related_fkey_lookups: for k, v in widgets.url_params_from_lookup_dict(l).items(): if k == lookup and v == value: return True parts = lookup.split(LOOKUP_SEP) # Last term in lookup is a query term (__exact, __startswith etc) # This term can be ignored. if len(parts) > 1 and parts[-1] in QUERY_TERMS: parts.pop() # Special case -- foo__id__exact and foo__id queries are implied # if foo has been specifically included in the lookup list; so # drop __id if it is the last part. However, first we need to find # the pk attribute name. rel_name = None for part in parts[:-1]: try: field, _, _, _ = model._meta.get_field_by_name(part) except FieldDoesNotExist: # Lookups on non-existent fields are ok, since they're ignored # later. return True if hasattr(field, 'rel'): if field.rel is None: # This property or relation doesn't exist, but it's allowed # since it's ignored in ChangeList.get_filters(). return True model = field.rel.to rel_name = field.rel.get_related_field().name elif isinstance(field, RelatedObject): model = field.model rel_name = model._meta.pk.name else: rel_name = None if rel_name and len(parts) > 1 and parts[-1] == rel_name: parts.pop() if len(parts) == 1: return True clean_lookup = LOOKUP_SEP.join(parts) return clean_lookup in self.list_filter or clean_lookup == self.date_hierarchy
def queryset(
*args, **kwargs)
def wrapped(*args, **kwargs): warnings.warn( "`%s.%s` is deprecated, use `%s` instead." % (self.class_name, self.old_method_name, self.new_method_name), self.deprecation_warning, 2) return f(*args, **kwargs)
def to_field_allowed(
self, request, to_field)
Returns True if the model associated with this admin should be allowed to be referenced by the specified field.
def to_field_allowed(self, request, to_field): """ Returns True if the model associated with this admin should be allowed to be referenced by the specified field. """ opts = self.model._meta try: field = opts.get_field(to_field) except FieldDoesNotExist: return False # Always allow referencing the primary key since it's already possible # to get this information from the change view URL. if field.primary_key: return True # Make sure at least one of the models registered for this site # references this field through a FK or a M2M relationship. registered_models = set() for model, admin in self.admin_site._registry.items(): registered_models.add(model) for inline in admin.inlines: registered_models.add(inline.model) for related_object in opts.get_all_related_objects(include_hidden=True): related_model = related_object.model if (any(issubclass(model, related_model) for model in registered_models) and related_object.field.rel.get_related_field() == field): return True return False
def validate(
cls, model)
@classmethod def validate(cls, model): validator = cls.validator_class() validator.validate(cls, model)
class MediaItemRelatedInline
class MediaItemRelatedInline(admin.StackedInline): model = MediaItemRelated
Ancestors (in MRO)
- MediaItemRelatedInline
- django.contrib.admin.options.StackedInline
- django.contrib.admin.options.InlineModelAdmin
- django.contrib.admin.options.BaseModelAdmin
- __builtin__.object
Class variables
var can_delete
var exclude
var extra
var fields
var fieldsets
var filter_horizontal
var filter_vertical
var fk_name
var form
var formfield_overrides
var formset
var max_num
var model
var ordering
var prepopulated_fields
var radio_fields
var raw_id_fields
var readonly_fields
var template
var validator_class
var verbose_name
var verbose_name_plural
Instance variables
var declared_fieldsets
var media
Methods
def __init__(
self, parent_model, admin_site)
def __init__(self, parent_model, admin_site): self.admin_site = admin_site self.parent_model = parent_model self.opts = self.model._meta super(InlineModelAdmin, self).__init__() if self.verbose_name is None: self.verbose_name = self.model._meta.verbose_name if self.verbose_name_plural is None: self.verbose_name_plural = self.model._meta.verbose_name_plural
def formfield_for_choice_field(
self, db_field, request=None, **kwargs)
Get a form Field for a database Field that has declared choices.
def formfield_for_choice_field(self, db_field, request=None, **kwargs): """ Get a form Field for a database Field that has declared choices. """ # If the field is named as a radio_field, use a RadioSelect if db_field.name in self.radio_fields: # Avoid stomping on custom widget/choices arguments. if 'widget' not in kwargs: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) if 'choices' not in kwargs: kwargs['choices'] = db_field.get_choices( include_blank=db_field.blank, blank_choice=[('', _('None'))] ) return db_field.formfield(**kwargs)
def formfield_for_dbfield(
self, db_field, **kwargs)
Hook for specifying the form Field instance for a given database Field instance.
If kwargs are given, they're passed to the form Field's constructor.
def formfield_for_dbfield(self, db_field, **kwargs): """ Hook for specifying the form Field instance for a given database Field instance. If kwargs are given, they're passed to the form Field's constructor. """ request = kwargs.pop("request", None) # If the field specifies choices, we don't need to look for special # admin widgets - we just need to use a select widget of some kind. if db_field.choices: return self.formfield_for_choice_field(db_field, request, **kwargs) # ForeignKey or ManyToManyFields if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)): # Combine the field kwargs with any options for formfield_overrides. # Make sure the passed in **kwargs override anything in # formfield_overrides because **kwargs is more specific, and should # always win. if db_field.__class__ in self.formfield_overrides: kwargs = dict(self.formfield_overrides[db_field.__class__], **kwargs) # Get the correct formfield. if isinstance(db_field, models.ForeignKey): formfield = self.formfield_for_foreignkey(db_field, request, **kwargs) elif isinstance(db_field, models.ManyToManyField): formfield = self.formfield_for_manytomany(db_field, request, **kwargs) # For non-raw_id fields, wrap the widget with a wrapper that adds # extra HTML -- the "add other" interface -- to the end of the # rendered output. formfield can be None if it came from a # OneToOneField with parent_link=True or a M2M intermediary. if formfield and db_field.name not in self.raw_id_fields: related_modeladmin = self.admin_site._registry.get( db_field.rel.to) can_add_related = bool(related_modeladmin and related_modeladmin.has_add_permission(request)) formfield.widget = widgets.RelatedFieldWidgetWrapper( formfield.widget, db_field.rel, self.admin_site, can_add_related=can_add_related) return formfield # If we've got overrides for the formfield defined, use 'em. **kwargs # passed to formfield_for_dbfield override the defaults. for klass in db_field.__class__.mro(): if klass in self.formfield_overrides: kwargs = dict(copy.deepcopy(self.formfield_overrides[klass]), **kwargs) return db_field.formfield(**kwargs) # For any other type of field, just call its formfield() method. return db_field.formfield(**kwargs)
def formfield_for_foreignkey(
self, db_field, request=None, **kwargs)
Get a form Field for a ForeignKey.
def formfield_for_foreignkey(self, db_field, request=None, **kwargs): """ Get a form Field for a ForeignKey. """ db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel, self.admin_site, using=db) elif db_field.name in self.radio_fields: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) kwargs['empty_label'] = _('None') if db_field.blank else None if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def formfield_for_manytomany(
self, db_field, request=None, **kwargs)
Get a form Field for a ManyToManyField.
def formfield_for_manytomany(self, db_field, request=None, **kwargs): """ Get a form Field for a ManyToManyField. """ # If it uses an intermediary model that isn't auto created, don't show # a field in admin. if not db_field.rel.through._meta.auto_created: return None db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel, self.admin_site, using=db) kwargs['help_text'] = '' elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)): kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical)) if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def get_extra(
self, request, obj=None, **kwargs)
Hook for customizing the number of extra inline forms.
def get_extra(self, request, obj=None, **kwargs): """Hook for customizing the number of extra inline forms.""" return self.extra
def get_field_queryset(
self, db, db_field, request)
If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case).
def get_field_queryset(self, db, db_field, request): """ If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case). """ related_admin = self.admin_site._registry.get(db_field.rel.to, None) if related_admin is not None: ordering = related_admin.get_ordering(request) if ordering is not None and ordering != (): return db_field.rel.to._default_manager.using(db).order_by(*ordering).complex_filter(db_field.rel.limit_choices_to) return None
def get_fieldsets(
self, request, obj=None)
def get_fieldsets(self, request, obj=None): if self.declared_fieldsets: return self.declared_fieldsets form = self.get_formset(request, obj, fields=None).form fields = list(form.base_fields) + list(self.get_readonly_fields(request, obj)) return [(None, {'fields': fields})]
def get_formset(
self, request, obj=None, **kwargs)
Returns a BaseInlineFormSet class for use in admin add/change views.
def get_formset(self, request, obj=None, **kwargs): """Returns a BaseInlineFormSet class for use in admin add/change views.""" if 'fields' in kwargs: fields = kwargs.pop('fields') else: fields = flatten_fieldsets(self.get_fieldsets(request, obj)) if self.exclude is None: exclude = [] else: exclude = list(self.exclude) exclude.extend(self.get_readonly_fields(request, obj)) if self.exclude is None and hasattr(self.form, '_meta') and self.form._meta.exclude: # Take the custom ModelForm's Meta.exclude into account only if the # InlineModelAdmin doesn't define its own. exclude.extend(self.form._meta.exclude) # If exclude is an empty list we use None, since that's the actual # default. exclude = exclude or None can_delete = self.can_delete and self.has_delete_permission(request, obj) defaults = { "form": self.form, "formset": self.formset, "fk_name": self.fk_name, "fields": fields, "exclude": exclude, "formfield_callback": partial(self.formfield_for_dbfield, request=request), "extra": self.get_extra(request, obj, **kwargs), "max_num": self.get_max_num(request, obj, **kwargs), "can_delete": can_delete, } defaults.update(kwargs) base_model_form = defaults['form'] class DeleteProtectedModelForm(base_model_form): def hand_clean_DELETE(self): """ We don't validate the 'DELETE' field itself because on templates it's not rendered using the field information, but just using a generic "deletion_field" of the InlineModelAdmin. """ if self.cleaned_data.get(DELETION_FIELD_NAME, False): using = router.db_for_write(self._meta.model) collector = NestedObjects(using=using) collector.collect([self.instance]) if collector.protected: objs = [] for p in collector.protected: objs.append( # Translators: Model verbose name and instance representation, suitable to be an item in a list _('%(class_name)s %(instance)s') % { 'class_name': p._meta.verbose_name, 'instance': p} ) params = {'class_name': self._meta.model._meta.verbose_name, 'instance': self.instance, 'related_objects': get_text_list(objs, _('and'))} msg = _("Deleting %(class_name)s %(instance)s would require " "deleting the following protected related objects: " "%(related_objects)s") raise ValidationError(msg, code='deleting_protected', params=params) def is_valid(self): result = super(DeleteProtectedModelForm, self).is_valid() self.hand_clean_DELETE() return result defaults['form'] = DeleteProtectedModelForm if defaults['fields'] is None and not modelform_defines_fields(defaults['form']): defaults['fields'] = forms.ALL_FIELDS return inlineformset_factory(self.parent_model, self.model, **defaults)
def get_max_num(
self, request, obj=None, **kwargs)
Hook for customizing the max number of extra inline forms.
def get_max_num(self, request, obj=None, **kwargs): """Hook for customizing the max number of extra inline forms.""" return self.max_num
def get_ordering(
self, request)
Hook for specifying field ordering.
def get_ordering(self, request): """ Hook for specifying field ordering. """ return self.ordering or () # otherwise we might try to *None, which is bad ;)
def get_prepopulated_fields(
self, request, obj=None)
Hook for specifying custom prepopulated fields.
def get_prepopulated_fields(self, request, obj=None): """ Hook for specifying custom prepopulated fields. """ return self.prepopulated_fields
def get_queryset(
self, request)
def get_queryset(self, request): queryset = super(InlineModelAdmin, self).get_queryset(request) if not self.has_change_permission(request): queryset = queryset.none() return queryset
def get_readonly_fields(
self, request, obj=None)
Hook for specifying custom readonly fields.
def get_readonly_fields(self, request, obj=None): """ Hook for specifying custom readonly fields. """ return self.readonly_fields
def has_add_permission(
self, request)
def has_add_permission(self, request): if self.opts.auto_created: # We're checking the rights to an auto-created intermediate model, # which doesn't have its own individual permissions. The user needs # to have the change permission for the related model in order to # be able to do anything with the intermediate model. return self.has_change_permission(request) return super(InlineModelAdmin, self).has_add_permission(request)
def has_change_permission(
self, request, obj=None)
def has_change_permission(self, request, obj=None): opts = self.opts if opts.auto_created: # The model was auto-created as intermediary for a # ManyToMany-relationship, find the target model for field in opts.fields: if field.rel and field.rel.to != self.parent_model: opts = field.rel.to._meta break codename = get_permission_codename('change', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_delete_permission(
self, request, obj=None)
def has_delete_permission(self, request, obj=None): if self.opts.auto_created: # We're checking the rights to an auto-created intermediate model, # which doesn't have its own individual permissions. The user needs # to have the change permission for the related model in order to # be able to do anything with the intermediate model. return self.has_change_permission(request, obj) return super(InlineModelAdmin, self).has_delete_permission(request, obj)
def lookup_allowed(
self, lookup, value)
def lookup_allowed(self, lookup, value): model = self.model # Check FKey lookups that are allowed, so that popups produced by # ForeignKeyRawIdWidget, on the basis of ForeignKey.limit_choices_to, # are allowed to work. for l in model._meta.related_fkey_lookups: for k, v in widgets.url_params_from_lookup_dict(l).items(): if k == lookup and v == value: return True parts = lookup.split(LOOKUP_SEP) # Last term in lookup is a query term (__exact, __startswith etc) # This term can be ignored. if len(parts) > 1 and parts[-1] in QUERY_TERMS: parts.pop() # Special case -- foo__id__exact and foo__id queries are implied # if foo has been specifically included in the lookup list; so # drop __id if it is the last part. However, first we need to find # the pk attribute name. rel_name = None for part in parts[:-1]: try: field, _, _, _ = model._meta.get_field_by_name(part) except FieldDoesNotExist: # Lookups on non-existent fields are ok, since they're ignored # later. return True if hasattr(field, 'rel'): if field.rel is None: # This property or relation doesn't exist, but it's allowed # since it's ignored in ChangeList.get_filters(). return True model = field.rel.to rel_name = field.rel.get_related_field().name elif isinstance(field, RelatedObject): model = field.model rel_name = model._meta.pk.name else: rel_name = None if rel_name and len(parts) > 1 and parts[-1] == rel_name: parts.pop() if len(parts) == 1: return True clean_lookup = LOOKUP_SEP.join(parts) return clean_lookup in self.list_filter or clean_lookup == self.date_hierarchy
def queryset(
*args, **kwargs)
def wrapped(*args, **kwargs): warnings.warn( "`%s.%s` is deprecated, use `%s` instead." % (self.class_name, self.old_method_name, self.new_method_name), self.deprecation_warning, 2) return f(*args, **kwargs)
def to_field_allowed(
self, request, to_field)
Returns True if the model associated with this admin should be allowed to be referenced by the specified field.
def to_field_allowed(self, request, to_field): """ Returns True if the model associated with this admin should be allowed to be referenced by the specified field. """ opts = self.model._meta try: field = opts.get_field(to_field) except FieldDoesNotExist: return False # Always allow referencing the primary key since it's already possible # to get this information from the change view URL. if field.primary_key: return True # Make sure at least one of the models registered for this site # references this field through a FK or a M2M relationship. registered_models = set() for model, admin in self.admin_site._registry.items(): registered_models.add(model) for inline in admin.inlines: registered_models.add(inline.model) for related_object in opts.get_all_related_objects(include_hidden=True): related_model = related_object.model if (any(issubclass(model, related_model) for model in registered_models) and related_object.field.rel.get_related_field() == field): return True return False
def validate(
cls, model)
@classmethod def validate(cls, model): validator = cls.validator_class() validator.validate(cls, model)
class MediaItemTranscodedInline
class MediaItemTranscodedInline(admin.StackedInline): model = MediaItemTranscoded
Ancestors (in MRO)
- MediaItemTranscodedInline
- django.contrib.admin.options.StackedInline
- django.contrib.admin.options.InlineModelAdmin
- django.contrib.admin.options.BaseModelAdmin
- __builtin__.object
Class variables
var can_delete
var exclude
var extra
var fields
var fieldsets
var filter_horizontal
var filter_vertical
var fk_name
var form
var formfield_overrides
var formset
var max_num
var model
var ordering
var prepopulated_fields
var radio_fields
var raw_id_fields
var readonly_fields
var template
var validator_class
var verbose_name
var verbose_name_plural
Instance variables
var declared_fieldsets
var media
Methods
def __init__(
self, parent_model, admin_site)
def __init__(self, parent_model, admin_site): self.admin_site = admin_site self.parent_model = parent_model self.opts = self.model._meta super(InlineModelAdmin, self).__init__() if self.verbose_name is None: self.verbose_name = self.model._meta.verbose_name if self.verbose_name_plural is None: self.verbose_name_plural = self.model._meta.verbose_name_plural
def formfield_for_choice_field(
self, db_field, request=None, **kwargs)
Get a form Field for a database Field that has declared choices.
def formfield_for_choice_field(self, db_field, request=None, **kwargs): """ Get a form Field for a database Field that has declared choices. """ # If the field is named as a radio_field, use a RadioSelect if db_field.name in self.radio_fields: # Avoid stomping on custom widget/choices arguments. if 'widget' not in kwargs: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) if 'choices' not in kwargs: kwargs['choices'] = db_field.get_choices( include_blank=db_field.blank, blank_choice=[('', _('None'))] ) return db_field.formfield(**kwargs)
def formfield_for_dbfield(
self, db_field, **kwargs)
Hook for specifying the form Field instance for a given database Field instance.
If kwargs are given, they're passed to the form Field's constructor.
def formfield_for_dbfield(self, db_field, **kwargs): """ Hook for specifying the form Field instance for a given database Field instance. If kwargs are given, they're passed to the form Field's constructor. """ request = kwargs.pop("request", None) # If the field specifies choices, we don't need to look for special # admin widgets - we just need to use a select widget of some kind. if db_field.choices: return self.formfield_for_choice_field(db_field, request, **kwargs) # ForeignKey or ManyToManyFields if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)): # Combine the field kwargs with any options for formfield_overrides. # Make sure the passed in **kwargs override anything in # formfield_overrides because **kwargs is more specific, and should # always win. if db_field.__class__ in self.formfield_overrides: kwargs = dict(self.formfield_overrides[db_field.__class__], **kwargs) # Get the correct formfield. if isinstance(db_field, models.ForeignKey): formfield = self.formfield_for_foreignkey(db_field, request, **kwargs) elif isinstance(db_field, models.ManyToManyField): formfield = self.formfield_for_manytomany(db_field, request, **kwargs) # For non-raw_id fields, wrap the widget with a wrapper that adds # extra HTML -- the "add other" interface -- to the end of the # rendered output. formfield can be None if it came from a # OneToOneField with parent_link=True or a M2M intermediary. if formfield and db_field.name not in self.raw_id_fields: related_modeladmin = self.admin_site._registry.get( db_field.rel.to) can_add_related = bool(related_modeladmin and related_modeladmin.has_add_permission(request)) formfield.widget = widgets.RelatedFieldWidgetWrapper( formfield.widget, db_field.rel, self.admin_site, can_add_related=can_add_related) return formfield # If we've got overrides for the formfield defined, use 'em. **kwargs # passed to formfield_for_dbfield override the defaults. for klass in db_field.__class__.mro(): if klass in self.formfield_overrides: kwargs = dict(copy.deepcopy(self.formfield_overrides[klass]), **kwargs) return db_field.formfield(**kwargs) # For any other type of field, just call its formfield() method. return db_field.formfield(**kwargs)
def formfield_for_foreignkey(
self, db_field, request=None, **kwargs)
Get a form Field for a ForeignKey.
def formfield_for_foreignkey(self, db_field, request=None, **kwargs): """ Get a form Field for a ForeignKey. """ db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel, self.admin_site, using=db) elif db_field.name in self.radio_fields: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) kwargs['empty_label'] = _('None') if db_field.blank else None if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def formfield_for_manytomany(
self, db_field, request=None, **kwargs)
Get a form Field for a ManyToManyField.
def formfield_for_manytomany(self, db_field, request=None, **kwargs): """ Get a form Field for a ManyToManyField. """ # If it uses an intermediary model that isn't auto created, don't show # a field in admin. if not db_field.rel.through._meta.auto_created: return None db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel, self.admin_site, using=db) kwargs['help_text'] = '' elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)): kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical)) if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def get_extra(
self, request, obj=None, **kwargs)
Hook for customizing the number of extra inline forms.
def get_extra(self, request, obj=None, **kwargs): """Hook for customizing the number of extra inline forms.""" return self.extra
def get_field_queryset(
self, db, db_field, request)
If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case).
def get_field_queryset(self, db, db_field, request): """ If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case). """ related_admin = self.admin_site._registry.get(db_field.rel.to, None) if related_admin is not None: ordering = related_admin.get_ordering(request) if ordering is not None and ordering != (): return db_field.rel.to._default_manager.using(db).order_by(*ordering).complex_filter(db_field.rel.limit_choices_to) return None
def get_fieldsets(
self, request, obj=None)
def get_fieldsets(self, request, obj=None): if self.declared_fieldsets: return self.declared_fieldsets form = self.get_formset(request, obj, fields=None).form fields = list(form.base_fields) + list(self.get_readonly_fields(request, obj)) return [(None, {'fields': fields})]
def get_formset(
self, request, obj=None, **kwargs)
Returns a BaseInlineFormSet class for use in admin add/change views.
def get_formset(self, request, obj=None, **kwargs): """Returns a BaseInlineFormSet class for use in admin add/change views.""" if 'fields' in kwargs: fields = kwargs.pop('fields') else: fields = flatten_fieldsets(self.get_fieldsets(request, obj)) if self.exclude is None: exclude = [] else: exclude = list(self.exclude) exclude.extend(self.get_readonly_fields(request, obj)) if self.exclude is None and hasattr(self.form, '_meta') and self.form._meta.exclude: # Take the custom ModelForm's Meta.exclude into account only if the # InlineModelAdmin doesn't define its own. exclude.extend(self.form._meta.exclude) # If exclude is an empty list we use None, since that's the actual # default. exclude = exclude or None can_delete = self.can_delete and self.has_delete_permission(request, obj) defaults = { "form": self.form, "formset": self.formset, "fk_name": self.fk_name, "fields": fields, "exclude": exclude, "formfield_callback": partial(self.formfield_for_dbfield, request=request), "extra": self.get_extra(request, obj, **kwargs), "max_num": self.get_max_num(request, obj, **kwargs), "can_delete": can_delete, } defaults.update(kwargs) base_model_form = defaults['form'] class DeleteProtectedModelForm(base_model_form): def hand_clean_DELETE(self): """ We don't validate the 'DELETE' field itself because on templates it's not rendered using the field information, but just using a generic "deletion_field" of the InlineModelAdmin. """ if self.cleaned_data.get(DELETION_FIELD_NAME, False): using = router.db_for_write(self._meta.model) collector = NestedObjects(using=using) collector.collect([self.instance]) if collector.protected: objs = [] for p in collector.protected: objs.append( # Translators: Model verbose name and instance representation, suitable to be an item in a list _('%(class_name)s %(instance)s') % { 'class_name': p._meta.verbose_name, 'instance': p} ) params = {'class_name': self._meta.model._meta.verbose_name, 'instance': self.instance, 'related_objects': get_text_list(objs, _('and'))} msg = _("Deleting %(class_name)s %(instance)s would require " "deleting the following protected related objects: " "%(related_objects)s") raise ValidationError(msg, code='deleting_protected', params=params) def is_valid(self): result = super(DeleteProtectedModelForm, self).is_valid() self.hand_clean_DELETE() return result defaults['form'] = DeleteProtectedModelForm if defaults['fields'] is None and not modelform_defines_fields(defaults['form']): defaults['fields'] = forms.ALL_FIELDS return inlineformset_factory(self.parent_model, self.model, **defaults)
def get_max_num(
self, request, obj=None, **kwargs)
Hook for customizing the max number of extra inline forms.
def get_max_num(self, request, obj=None, **kwargs): """Hook for customizing the max number of extra inline forms.""" return self.max_num
def get_ordering(
self, request)
Hook for specifying field ordering.
def get_ordering(self, request): """ Hook for specifying field ordering. """ return self.ordering or () # otherwise we might try to *None, which is bad ;)
def get_prepopulated_fields(
self, request, obj=None)
Hook for specifying custom prepopulated fields.
def get_prepopulated_fields(self, request, obj=None): """ Hook for specifying custom prepopulated fields. """ return self.prepopulated_fields
def get_queryset(
self, request)
def get_queryset(self, request): queryset = super(InlineModelAdmin, self).get_queryset(request) if not self.has_change_permission(request): queryset = queryset.none() return queryset
def get_readonly_fields(
self, request, obj=None)
Hook for specifying custom readonly fields.
def get_readonly_fields(self, request, obj=None): """ Hook for specifying custom readonly fields. """ return self.readonly_fields
def has_add_permission(
self, request)
def has_add_permission(self, request): if self.opts.auto_created: # We're checking the rights to an auto-created intermediate model, # which doesn't have its own individual permissions. The user needs # to have the change permission for the related model in order to # be able to do anything with the intermediate model. return self.has_change_permission(request) return super(InlineModelAdmin, self).has_add_permission(request)
def has_change_permission(
self, request, obj=None)
def has_change_permission(self, request, obj=None): opts = self.opts if opts.auto_created: # The model was auto-created as intermediary for a # ManyToMany-relationship, find the target model for field in opts.fields: if field.rel and field.rel.to != self.parent_model: opts = field.rel.to._meta break codename = get_permission_codename('change', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_delete_permission(
self, request, obj=None)
def has_delete_permission(self, request, obj=None): if self.opts.auto_created: # We're checking the rights to an auto-created intermediate model, # which doesn't have its own individual permissions. The user needs # to have the change permission for the related model in order to # be able to do anything with the intermediate model. return self.has_change_permission(request, obj) return super(InlineModelAdmin, self).has_delete_permission(request, obj)
def lookup_allowed(
self, lookup, value)
def lookup_allowed(self, lookup, value): model = self.model # Check FKey lookups that are allowed, so that popups produced by # ForeignKeyRawIdWidget, on the basis of ForeignKey.limit_choices_to, # are allowed to work. for l in model._meta.related_fkey_lookups: for k, v in widgets.url_params_from_lookup_dict(l).items(): if k == lookup and v == value: return True parts = lookup.split(LOOKUP_SEP) # Last term in lookup is a query term (__exact, __startswith etc) # This term can be ignored. if len(parts) > 1 and parts[-1] in QUERY_TERMS: parts.pop() # Special case -- foo__id__exact and foo__id queries are implied # if foo has been specifically included in the lookup list; so # drop __id if it is the last part. However, first we need to find # the pk attribute name. rel_name = None for part in parts[:-1]: try: field, _, _, _ = model._meta.get_field_by_name(part) except FieldDoesNotExist: # Lookups on non-existent fields are ok, since they're ignored # later. return True if hasattr(field, 'rel'): if field.rel is None: # This property or relation doesn't exist, but it's allowed # since it's ignored in ChangeList.get_filters(). return True model = field.rel.to rel_name = field.rel.get_related_field().name elif isinstance(field, RelatedObject): model = field.model rel_name = model._meta.pk.name else: rel_name = None if rel_name and len(parts) > 1 and parts[-1] == rel_name: parts.pop() if len(parts) == 1: return True clean_lookup = LOOKUP_SEP.join(parts) return clean_lookup in self.list_filter or clean_lookup == self.date_hierarchy
def queryset(
*args, **kwargs)
def wrapped(*args, **kwargs): warnings.warn( "`%s.%s` is deprecated, use `%s` instead." % (self.class_name, self.old_method_name, self.new_method_name), self.deprecation_warning, 2) return f(*args, **kwargs)
def to_field_allowed(
self, request, to_field)
Returns True if the model associated with this admin should be allowed to be referenced by the specified field.
def to_field_allowed(self, request, to_field): """ Returns True if the model associated with this admin should be allowed to be referenced by the specified field. """ opts = self.model._meta try: field = opts.get_field(to_field) except FieldDoesNotExist: return False # Always allow referencing the primary key since it's already possible # to get this information from the change view URL. if field.primary_key: return True # Make sure at least one of the models registered for this site # references this field through a FK or a M2M relationship. registered_models = set() for model, admin in self.admin_site._registry.items(): registered_models.add(model) for inline in admin.inlines: registered_models.add(inline.model) for related_object in opts.get_all_related_objects(include_hidden=True): related_model = related_object.model if (any(issubclass(model, related_model) for model in registered_models) and related_object.field.rel.get_related_field() == field): return True return False
def validate(
cls, model)
@classmethod def validate(cls, model): validator = cls.validator_class() validator.validate(cls, model)
class MediaPartAdmin
class MediaPartAdmin(admin.ModelAdmin): search_fields = ['title', 'item__code'] ordering = ['title']
Ancestors (in MRO)
- MediaPartAdmin
- django.contrib.admin.options.ModelAdmin
- django.contrib.admin.options.BaseModelAdmin
- __builtin__.object
Class variables
var action_form
var actions
var actions_on_bottom
var actions_on_top
var actions_selection_counter
var add_form_template
var change_form_template
var change_list_template
var date_hierarchy
var delete_confirmation_template
var delete_selected_confirmation_template
var exclude
var fields
var fieldsets
var filter_horizontal
var filter_vertical
var form
var formfield_overrides
var inlines
var list_display
var list_display_links
var list_editable
var list_filter
var list_max_show_all
var list_per_page
var object_history_template
var ordering
var paginator
var prepopulated_fields
var preserve_filters
var radio_fields
var raw_id_fields
var readonly_fields
var save_as
var save_on_top
var search_fields
var validator_class
Instance variables
var declared_fieldsets
var media
var urls
Methods
def __init__(
self, model, admin_site)
def __init__(self, model, admin_site): self.model = model self.opts = model._meta self.admin_site = admin_site super(ModelAdmin, self).__init__()
def action_checkbox(
self, obj)
A list_display column containing a checkbox widget.
def action_checkbox(self, obj): """ A list_display column containing a checkbox widget. """ return helpers.checkbox.render(helpers.ACTION_CHECKBOX_NAME, force_text(obj.pk))
def add_view(
self, *args, **kwargs)
The 'add' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def change_view(
self, *args, **kwargs)
The 'change' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def changelist_view(
self, *args, **kwargs)
The 'change list' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def construct_change_message(
self, request, form, formsets)
Construct a change message from a changed object.
def construct_change_message(self, request, form, formsets): """ Construct a change message from a changed object. """ change_message = [] if form.changed_data: change_message.append(_('Changed %s.') % get_text_list(form.changed_data, _('and'))) if formsets: for formset in formsets: for added_object in formset.new_objects: change_message.append(_('Added %(name)s "%(object)s".') % {'name': force_text(added_object._meta.verbose_name), 'object': force_text(added_object)}) for changed_object, changed_fields in formset.changed_objects: change_message.append(_('Changed %(list)s for %(name)s "%(object)s".') % {'list': get_text_list(changed_fields, _('and')), 'name': force_text(changed_object._meta.verbose_name), 'object': force_text(changed_object)}) for deleted_object in formset.deleted_objects: change_message.append(_('Deleted %(name)s "%(object)s".') % {'name': force_text(deleted_object._meta.verbose_name), 'object': force_text(deleted_object)}) change_message = ' '.join(change_message) return change_message or _('No fields changed.')
def delete_model(
self, request, obj)
Given a model instance delete it from the database.
def delete_model(self, request, obj): """ Given a model instance delete it from the database. """ obj.delete()
def delete_view(
self, *args, **kwargs)
The 'delete' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def formfield_for_choice_field(
self, db_field, request=None, **kwargs)
Get a form Field for a database Field that has declared choices.
def formfield_for_choice_field(self, db_field, request=None, **kwargs): """ Get a form Field for a database Field that has declared choices. """ # If the field is named as a radio_field, use a RadioSelect if db_field.name in self.radio_fields: # Avoid stomping on custom widget/choices arguments. if 'widget' not in kwargs: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) if 'choices' not in kwargs: kwargs['choices'] = db_field.get_choices( include_blank=db_field.blank, blank_choice=[('', _('None'))] ) return db_field.formfield(**kwargs)
def formfield_for_dbfield(
self, db_field, **kwargs)
Hook for specifying the form Field instance for a given database Field instance.
If kwargs are given, they're passed to the form Field's constructor.
def formfield_for_dbfield(self, db_field, **kwargs): """ Hook for specifying the form Field instance for a given database Field instance. If kwargs are given, they're passed to the form Field's constructor. """ request = kwargs.pop("request", None) # If the field specifies choices, we don't need to look for special # admin widgets - we just need to use a select widget of some kind. if db_field.choices: return self.formfield_for_choice_field(db_field, request, **kwargs) # ForeignKey or ManyToManyFields if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)): # Combine the field kwargs with any options for formfield_overrides. # Make sure the passed in **kwargs override anything in # formfield_overrides because **kwargs is more specific, and should # always win. if db_field.__class__ in self.formfield_overrides: kwargs = dict(self.formfield_overrides[db_field.__class__], **kwargs) # Get the correct formfield. if isinstance(db_field, models.ForeignKey): formfield = self.formfield_for_foreignkey(db_field, request, **kwargs) elif isinstance(db_field, models.ManyToManyField): formfield = self.formfield_for_manytomany(db_field, request, **kwargs) # For non-raw_id fields, wrap the widget with a wrapper that adds # extra HTML -- the "add other" interface -- to the end of the # rendered output. formfield can be None if it came from a # OneToOneField with parent_link=True or a M2M intermediary. if formfield and db_field.name not in self.raw_id_fields: related_modeladmin = self.admin_site._registry.get( db_field.rel.to) can_add_related = bool(related_modeladmin and related_modeladmin.has_add_permission(request)) formfield.widget = widgets.RelatedFieldWidgetWrapper( formfield.widget, db_field.rel, self.admin_site, can_add_related=can_add_related) return formfield # If we've got overrides for the formfield defined, use 'em. **kwargs # passed to formfield_for_dbfield override the defaults. for klass in db_field.__class__.mro(): if klass in self.formfield_overrides: kwargs = dict(copy.deepcopy(self.formfield_overrides[klass]), **kwargs) return db_field.formfield(**kwargs) # For any other type of field, just call its formfield() method. return db_field.formfield(**kwargs)
def formfield_for_foreignkey(
self, db_field, request=None, **kwargs)
Get a form Field for a ForeignKey.
def formfield_for_foreignkey(self, db_field, request=None, **kwargs): """ Get a form Field for a ForeignKey. """ db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel, self.admin_site, using=db) elif db_field.name in self.radio_fields: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) kwargs['empty_label'] = _('None') if db_field.blank else None if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def formfield_for_manytomany(
self, db_field, request=None, **kwargs)
Get a form Field for a ManyToManyField.
def formfield_for_manytomany(self, db_field, request=None, **kwargs): """ Get a form Field for a ManyToManyField. """ # If it uses an intermediary model that isn't auto created, don't show # a field in admin. if not db_field.rel.through._meta.auto_created: return None db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel, self.admin_site, using=db) kwargs['help_text'] = '' elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)): kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical)) if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def get_action(
self, action)
Return a given action from a parameter, which can either be a callable, or the name of a method on the ModelAdmin. Return is a tuple of (callable, name, description).
def get_action(self, action): """ Return a given action from a parameter, which can either be a callable, or the name of a method on the ModelAdmin. Return is a tuple of (callable, name, description). """ # If the action is a callable, just use it. if callable(action): func = action action = action.__name__ # Next, look for a method. Grab it off self.__class__ to get an unbound # method instead of a bound one; this ensures that the calling # conventions are the same for functions and methods. elif hasattr(self.__class__, action): func = getattr(self.__class__, action) # Finally, look for a named method on the admin site else: try: func = self.admin_site.get_action(action) except KeyError: return None if hasattr(func, 'short_description'): description = func.short_description else: description = capfirst(action.replace('_', ' ')) return func, action, description
def get_action_choices(
self, request, default_choices=[(u'', u'---------')])
Return a list of choices for use in a form object. Each choice is a tuple (name, description).
def get_action_choices(self, request, default_choices=BLANK_CHOICE_DASH): """ Return a list of choices for use in a form object. Each choice is a tuple (name, description). """ choices = [] + default_choices for func, name, description in six.itervalues(self.get_actions(request)): choice = (name, description % model_format_dict(self.opts)) choices.append(choice) return choices
def get_actions(
self, request)
Return a dictionary mapping the names of all actions for this ModelAdmin to a tuple of (callable, name, description) for each action.
def get_actions(self, request): """ Return a dictionary mapping the names of all actions for this ModelAdmin to a tuple of (callable, name, description) for each action. """ # If self.actions is explicitly set to None that means that we don't # want *any* actions enabled on this page. from django.contrib.admin.views.main import _is_changelist_popup if self.actions is None or _is_changelist_popup(request): return SortedDict() actions = [] # Gather actions from the admin site first for (name, func) in self.admin_site.actions: description = getattr(func, 'short_description', name.replace('_', ' ')) actions.append((func, name, description)) # Then gather them from the model admin and all parent classes, # starting with self and working back up. for klass in self.__class__.mro()[::-1]: class_actions = getattr(klass, 'actions', []) # Avoid trying to iterate over None if not class_actions: continue actions.extend([self.get_action(action) for action in class_actions]) # get_action might have returned None, so filter any of those out. actions = filter(None, actions) # Convert the actions into a SortedDict keyed by name. actions = SortedDict([ (name, (func, name, desc)) for func, name, desc in actions ]) return actions
def get_changelist(
self, request, **kwargs)
Returns the ChangeList class for use on the changelist page.
def get_changelist(self, request, **kwargs): """ Returns the ChangeList class for use on the changelist page. """ from django.contrib.admin.views.main import ChangeList return ChangeList
def get_changelist_form(
self, request, **kwargs)
Returns a Form class for use in the Formset on the changelist page.
def get_changelist_form(self, request, **kwargs): """ Returns a Form class for use in the Formset on the changelist page. """ defaults = { "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) if (defaults.get('fields') is None and not modelform_defines_fields(defaults.get('form'))): defaults['fields'] = forms.ALL_FIELDS return modelform_factory(self.model, **defaults)
def get_changelist_formset(
self, request, **kwargs)
Returns a FormSet class for use on the changelist page if list_editable is used.
def get_changelist_formset(self, request, **kwargs): """ Returns a FormSet class for use on the changelist page if list_editable is used. """ defaults = { "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) return modelformset_factory(self.model, self.get_changelist_form(request), extra=0, fields=self.list_editable, **defaults)
def get_field_queryset(
self, db, db_field, request)
If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case).
def get_field_queryset(self, db, db_field, request): """ If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case). """ related_admin = self.admin_site._registry.get(db_field.rel.to, None) if related_admin is not None: ordering = related_admin.get_ordering(request) if ordering is not None and ordering != (): return db_field.rel.to._default_manager.using(db).order_by(*ordering).complex_filter(db_field.rel.limit_choices_to) return None
def get_fieldsets(
self, request, obj=None)
Hook for specifying fieldsets for the add form.
def get_fieldsets(self, request, obj=None): "Hook for specifying fieldsets for the add form." if self.declared_fieldsets: return self.declared_fieldsets form = self.get_form(request, obj, fields=None) fields = list(form.base_fields) + list(self.get_readonly_fields(request, obj)) return [(None, {'fields': fields})]
def get_form(
self, request, obj=None, **kwargs)
Returns a Form class for use in the admin add view. This is used by add_view and change_view.
def get_form(self, request, obj=None, **kwargs): """ Returns a Form class for use in the admin add view. This is used by add_view and change_view. """ if 'fields' in kwargs: fields = kwargs.pop('fields') else: fields = flatten_fieldsets(self.get_fieldsets(request, obj)) if self.exclude is None: exclude = [] else: exclude = list(self.exclude) exclude.extend(self.get_readonly_fields(request, obj)) if self.exclude is None and hasattr(self.form, '_meta') and self.form._meta.exclude: # Take the custom ModelForm's Meta.exclude into account only if the # ModelAdmin doesn't define its own. exclude.extend(self.form._meta.exclude) # if exclude is an empty list we pass None to be consistent with the # default on modelform_factory exclude = exclude or None defaults = { "form": self.form, "fields": fields, "exclude": exclude, "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) if defaults['fields'] is None and not modelform_defines_fields(defaults['form']): defaults['fields'] = forms.ALL_FIELDS try: return modelform_factory(self.model, **defaults) except FieldError as e: raise FieldError('%s. Check fields/fieldsets/exclude attributes of class %s.' % (e, self.__class__.__name__))
def get_formsets(
self, request, obj=None)
def get_formsets(self, request, obj=None): for inline in self.get_inline_instances(request, obj): yield inline.get_formset(request, obj)
def get_inline_instances(
self, request, obj=None)
def get_inline_instances(self, request, obj=None): inline_instances = [] for inline_class in self.inlines: inline = inline_class(self.model, self.admin_site) if request: if not (inline.has_add_permission(request) or inline.has_change_permission(request, obj) or inline.has_delete_permission(request, obj)): continue if not inline.has_add_permission(request): inline.max_num = 0 inline_instances.append(inline) return inline_instances
def get_list_display(
self, request)
Return a sequence containing the fields to be displayed on the changelist.
def get_list_display(self, request): """ Return a sequence containing the fields to be displayed on the changelist. """ return self.list_display
def get_list_display_links(
self, request, list_display)
Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display().
def get_list_display_links(self, request, list_display): """ Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display(). """ if self.list_display_links or not list_display: return self.list_display_links else: # Use only the first item in list_display as link return list(list_display)[:1]
def get_list_filter(
self, request)
Returns a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page.
def get_list_filter(self, request): """ Returns a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page. """ return self.list_filter
def get_model_perms(
self, request)
Returns a dict of all perms for this model. This dict has the keys
add
, change
, and delete
mapping to the True/False for each
of those actions.
def get_model_perms(self, request): """ Returns a dict of all perms for this model. This dict has the keys ``add``, ``change``, and ``delete`` mapping to the True/False for each of those actions. """ return { 'add': self.has_add_permission(request), 'change': self.has_change_permission(request), 'delete': self.has_delete_permission(request), }
def get_object(
self, request, object_id)
Returns an instance matching the primary key provided. None
is
returned if no match is found (or the object_id failed validation
against the primary key field).
def get_object(self, request, object_id): """ Returns an instance matching the primary key provided. ``None`` is returned if no match is found (or the object_id failed validation against the primary key field). """ queryset = self.get_queryset(request) model = queryset.model try: object_id = model._meta.pk.to_python(object_id) return queryset.get(pk=object_id) except (model.DoesNotExist, ValidationError, ValueError): return None
def get_ordering(
self, request)
Hook for specifying field ordering.
def get_ordering(self, request): """ Hook for specifying field ordering. """ return self.ordering or () # otherwise we might try to *None, which is bad ;)
def get_paginator(
self, request, queryset, per_page, orphans=0, allow_empty_first_page=True)
def get_paginator(self, request, queryset, per_page, orphans=0, allow_empty_first_page=True): return self.paginator(queryset, per_page, orphans, allow_empty_first_page)
def get_prepopulated_fields(
self, request, obj=None)
Hook for specifying custom prepopulated fields.
def get_prepopulated_fields(self, request, obj=None): """ Hook for specifying custom prepopulated fields. """ return self.prepopulated_fields
def get_preserved_filters(
self, request)
Returns the preserved filters querystring.
def get_preserved_filters(self, request): """ Returns the preserved filters querystring. """ match = request.resolver_match if self.preserve_filters and match: opts = self.model._meta current_url = '%s:%s' % (match.app_name, match.url_name) changelist_url = 'admin:%s_%s_changelist' % (opts.app_label, opts.model_name) if current_url == changelist_url: preserved_filters = request.GET.urlencode() else: preserved_filters = request.GET.get('_changelist_filters') if preserved_filters: return urlencode({'_changelist_filters': preserved_filters}) return ''
def get_queryset(
self, request)
Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view.
def get_queryset(self, request): """ Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view. """ qs = self.model._default_manager.get_queryset() # TODO: this should be handled by some parameter to the ChangeList. ordering = self.get_ordering(request) if ordering: qs = qs.order_by(*ordering) return qs
def get_readonly_fields(
self, request, obj=None)
Hook for specifying custom readonly fields.
def get_readonly_fields(self, request, obj=None): """ Hook for specifying custom readonly fields. """ return self.readonly_fields
def get_search_results(
self, request, queryset, search_term)
Returns a tuple containing a queryset to implement the search, and a boolean indicating if the results may contain duplicates.
def get_search_results(self, request, queryset, search_term): """ Returns a tuple containing a queryset to implement the search, and a boolean indicating if the results may contain duplicates. """ # Apply keyword searches. def construct_search(field_name): if field_name.startswith('^'): return "%s__istartswith" % field_name[1:] elif field_name.startswith('='): return "%s__iexact" % field_name[1:] elif field_name.startswith('@'): return "%s__search" % field_name[1:] else: return "%s__icontains" % field_name use_distinct = False if self.search_fields and search_term: orm_lookups = [construct_search(str(search_field)) for search_field in self.search_fields] for bit in search_term.split(): or_queries = [models.Q(**{orm_lookup: bit}) for orm_lookup in orm_lookups] queryset = queryset.filter(reduce(operator.or_, or_queries)) if not use_distinct: for search_spec in orm_lookups: if lookup_needs_distinct(self.opts, search_spec): use_distinct = True break return queryset, use_distinct
def get_urls(
self)
def get_urls(self): from django.conf.urls import patterns, url def wrap(view): def wrapper(*args, **kwargs): return self.admin_site.admin_view(view)(*args, **kwargs) return update_wrapper(wrapper, view) info = self.model._meta.app_label, self.model._meta.model_name urlpatterns = patterns('', url(r'^$', wrap(self.changelist_view), name='%s_%s_changelist' % info), url(r'^add/$', wrap(self.add_view), name='%s_%s_add' % info), url(r'^(.+)/history/$', wrap(self.history_view), name='%s_%s_history' % info), url(r'^(.+)/delete/$', wrap(self.delete_view), name='%s_%s_delete' % info), url(r'^(.+)/$', wrap(self.change_view), name='%s_%s_change' % info), ) return urlpatterns
def has_add_permission(
self, request)
Returns True if the given request has permission to add an object. Can be overridden by the user in subclasses.
def has_add_permission(self, request): """ Returns True if the given request has permission to add an object. Can be overridden by the user in subclasses. """ opts = self.opts codename = get_permission_codename('add', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_change_permission(
self, request, obj=None)
Returns True if the given request has permission to change the given
Django model instance, the default implementation doesn't examine the
obj
parameter.
Can be overridden by the user in subclasses. In such case it should
return True if the given request has permission to change the obj
model instance. If obj
is None, this should return True if the given
request has permission to change any object of the given type.
def has_change_permission(self, request, obj=None): """ Returns True if the given request has permission to change the given Django model instance, the default implementation doesn't examine the `obj` parameter. Can be overridden by the user in subclasses. In such case it should return True if the given request has permission to change the `obj` model instance. If `obj` is None, this should return True if the given request has permission to change *any* object of the given type. """ opts = self.opts codename = get_permission_codename('change', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_delete_permission(
self, request, obj=None)
Returns True if the given request has permission to change the given
Django model instance, the default implementation doesn't examine the
obj
parameter.
Can be overridden by the user in subclasses. In such case it should
return True if the given request has permission to delete the obj
model instance. If obj
is None, this should return True if the given
request has permission to delete any object of the given type.
def has_delete_permission(self, request, obj=None): """ Returns True if the given request has permission to change the given Django model instance, the default implementation doesn't examine the `obj` parameter. Can be overridden by the user in subclasses. In such case it should return True if the given request has permission to delete the `obj` model instance. If `obj` is None, this should return True if the given request has permission to delete *any* object of the given type. """ opts = self.opts codename = get_permission_codename('delete', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def history_view(
self, request, object_id, extra_context=None)
The 'history' admin view for this model.
def history_view(self, request, object_id, extra_context=None): "The 'history' admin view for this model." from django.contrib.admin.models import LogEntry # First check if the user can see this history. model = self.model obj = get_object_or_404(model, pk=unquote(object_id)) if not self.has_change_permission(request, obj): raise PermissionDenied # Then get the history for this object. opts = model._meta app_label = opts.app_label action_list = LogEntry.objects.filter( object_id=unquote(object_id), content_type__id__exact=ContentType.objects.get_for_model(model).id ).select_related().order_by('action_time') context = { 'title': _('Change history: %s') % force_text(obj), 'action_list': action_list, 'module_name': capfirst(force_text(opts.verbose_name_plural)), 'object': obj, 'app_label': app_label, 'opts': opts, 'preserved_filters': self.get_preserved_filters(request), } context.update(extra_context or {}) return TemplateResponse(request, self.object_history_template or [ "admin/%s/%s/object_history.html" % (app_label, opts.model_name), "admin/%s/object_history.html" % app_label, "admin/object_history.html" ], context, current_app=self.admin_site.name)
def log_addition(
self, request, object)
Log that an object has been successfully added.
The default implementation creates an admin LogEntry object.
def log_addition(self, request, object): """ Log that an object has been successfully added. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, ADDITION LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=ADDITION )
def log_change(
self, request, object, message)
Log that an object has been successfully changed.
The default implementation creates an admin LogEntry object.
def log_change(self, request, object, message): """ Log that an object has been successfully changed. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, CHANGE LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=CHANGE, change_message=message )
def log_deletion(
self, request, object, object_repr)
Log that an object will be deleted. Note that this method is called before the deletion.
The default implementation creates an admin LogEntry object.
def log_deletion(self, request, object, object_repr): """ Log that an object will be deleted. Note that this method is called before the deletion. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, DELETION LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(self.model).pk, object_id=object.pk, object_repr=object_repr, action_flag=DELETION )
def lookup_allowed(
self, lookup, value)
def lookup_allowed(self, lookup, value): model = self.model # Check FKey lookups that are allowed, so that popups produced by # ForeignKeyRawIdWidget, on the basis of ForeignKey.limit_choices_to, # are allowed to work. for l in model._meta.related_fkey_lookups: for k, v in widgets.url_params_from_lookup_dict(l).items(): if k == lookup and v == value: return True parts = lookup.split(LOOKUP_SEP) # Last term in lookup is a query term (__exact, __startswith etc) # This term can be ignored. if len(parts) > 1 and parts[-1] in QUERY_TERMS: parts.pop() # Special case -- foo__id__exact and foo__id queries are implied # if foo has been specifically included in the lookup list; so # drop __id if it is the last part. However, first we need to find # the pk attribute name. rel_name = None for part in parts[:-1]: try: field, _, _, _ = model._meta.get_field_by_name(part) except FieldDoesNotExist: # Lookups on non-existent fields are ok, since they're ignored # later. return True if hasattr(field, 'rel'): if field.rel is None: # This property or relation doesn't exist, but it's allowed # since it's ignored in ChangeList.get_filters(). return True model = field.rel.to rel_name = field.rel.get_related_field().name elif isinstance(field, RelatedObject): model = field.model rel_name = model._meta.pk.name else: rel_name = None if rel_name and len(parts) > 1 and parts[-1] == rel_name: parts.pop() if len(parts) == 1: return True clean_lookup = LOOKUP_SEP.join(parts) return clean_lookup in self.list_filter or clean_lookup == self.date_hierarchy
def message_user(
self, request, message, level=20, extra_tags='', fail_silently=False)
Send a message to the user. The default implementation posts a message using the django.contrib.messages backend.
Exposes almost the same API as messages.add_message(), but accepts the
positional arguments in a different order to maintain backwards
compatibility. For convenience, it accepts the level
argument as
a string rather than the usual level number.
def message_user(self, request, message, level=messages.INFO, extra_tags='', fail_silently=False): """ Send a message to the user. The default implementation posts a message using the django.contrib.messages backend. Exposes almost the same API as messages.add_message(), but accepts the positional arguments in a different order to maintain backwards compatibility. For convenience, it accepts the `level` argument as a string rather than the usual level number. """ if not isinstance(level, int): # attempt to get the level if passed a string try: level = getattr(messages.constants, level.upper()) except AttributeError: levels = messages.constants.DEFAULT_TAGS.values() levels_repr = ', '.join('`%s`' % l for l in levels) raise ValueError('Bad message level string: `%s`. ' 'Possible values are: %s' % (level, levels_repr)) messages.add_message(request, level, message, extra_tags=extra_tags, fail_silently=fail_silently)
def queryset(
*args, **kwargs)
def wrapped(*args, **kwargs): warnings.warn( "`%s.%s` is deprecated, use `%s` instead." % (self.class_name, self.old_method_name, self.new_method_name), self.deprecation_warning, 2) return f(*args, **kwargs)
def render_change_form(
self, request, context, add=False, change=False, form_url='', obj=None)
def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None): opts = self.model._meta app_label = opts.app_label preserved_filters = self.get_preserved_filters(request) form_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, form_url) context.update({ 'add': add, 'change': change, 'has_add_permission': self.has_add_permission(request), 'has_change_permission': self.has_change_permission(request, obj), 'has_delete_permission': self.has_delete_permission(request, obj), 'has_file_field': True, # FIXME - this should check if form or formsets have a FileField, 'has_absolute_url': hasattr(self.model, 'get_absolute_url'), 'form_url': form_url, 'opts': opts, 'content_type_id': ContentType.objects.get_for_model(self.model).id, 'save_as': self.save_as, 'save_on_top': self.save_on_top, }) if add and self.add_form_template is not None: form_template = self.add_form_template else: form_template = self.change_form_template return TemplateResponse(request, form_template or [ "admin/%s/%s/change_form.html" % (app_label, opts.model_name), "admin/%s/change_form.html" % app_label, "admin/change_form.html" ], context, current_app=self.admin_site.name)
def response_action(
self, request, queryset)
Handle an admin action. This is called if a request is POSTed to the changelist; it returns an HttpResponse if the action was handled, and None otherwise.
def response_action(self, request, queryset): """ Handle an admin action. This is called if a request is POSTed to the changelist; it returns an HttpResponse if the action was handled, and None otherwise. """ # There can be multiple action forms on the page (at the top # and bottom of the change list, for example). Get the action # whose button was pushed. try: action_index = int(request.POST.get('index', 0)) except ValueError: action_index = 0 # Construct the action form. data = request.POST.copy() data.pop(helpers.ACTION_CHECKBOX_NAME, None) data.pop("index", None) # Use the action whose button was pushed try: data.update({'action': data.getlist('action')[action_index]}) except IndexError: # If we didn't get an action from the chosen form that's invalid # POST data, so by deleting action it'll fail the validation check # below. So no need to do anything here pass action_form = self.action_form(data, auto_id=None) action_form.fields['action'].choices = self.get_action_choices(request) # If the form's valid we can handle the action. if action_form.is_valid(): action = action_form.cleaned_data['action'] select_across = action_form.cleaned_data['select_across'] func = self.get_actions(request)[action][0] # Get the list of selected PKs. If nothing's selected, we can't # perform an action on it, so bail. Except we want to perform # the action explicitly on all objects. selected = request.POST.getlist(helpers.ACTION_CHECKBOX_NAME) if not selected and not select_across: # Reminder that something needs to be selected or nothing will happen msg = _("Items must be selected in order to perform " "actions on them. No items have been changed.") self.message_user(request, msg, messages.WARNING) return None if not select_across: # Perform the action only on the selected objects queryset = queryset.filter(pk__in=selected) response = func(self, request, queryset) # Actions may return an HttpResponse-like object, which will be # used as the response from the POST. If not, we'll be a good # little HTTP citizen and redirect back to the changelist page. if isinstance(response, HttpResponseBase): return response else: return HttpResponseRedirect(request.get_full_path()) else: msg = _("No action selected.") self.message_user(request, msg, messages.WARNING) return None
def response_add(
self, request, obj, post_url_continue=None)
Determines the HttpResponse for the add_view stage.
def response_add(self, request, obj, post_url_continue=None): """ Determines the HttpResponse for the add_view stage. """ opts = obj._meta pk_value = obj._get_pk_val() preserved_filters = self.get_preserved_filters(request) msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)} # Here, we distinguish between different save types by checking for # the presence of keys in request.POST. if IS_POPUP_VAR in request.POST: return SimpleTemplateResponse('admin/popup_response.html', { 'pk_value': escape(pk_value), 'obj': escapejs(obj) }) elif "_continue" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) if post_url_continue is None: post_url_continue = reverse('admin:%s_%s_change' % (opts.app_label, opts.model_name), args=(pk_value,), current_app=self.admin_site.name) post_url_continue = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url_continue) return HttpResponseRedirect(post_url_continue) elif "_addanother" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may add another %(name)s below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = request.path redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) else: msg = _('The %(name)s "%(obj)s" was added successfully.') % msg_dict self.message_user(request, msg, messages.SUCCESS) return self.response_post_save_add(request, obj)
def response_change(
self, request, obj)
Determines the HttpResponse for the change_view stage.
def response_change(self, request, obj): """ Determines the HttpResponse for the change_view stage. """ opts = self.model._meta pk_value = obj._get_pk_val() preserved_filters = self.get_preserved_filters(request) msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)} if "_continue" in request.POST: msg = _('The %(name)s "%(obj)s" was changed successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = request.path redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) elif "_saveasnew" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = reverse('admin:%s_%s_change' % (opts.app_label, opts.model_name), args=(pk_value,), current_app=self.admin_site.name) redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) elif "_addanother" in request.POST: msg = _('The %(name)s "%(obj)s" was changed successfully. You may add another %(name)s below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = reverse('admin:%s_%s_add' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) else: msg = _('The %(name)s "%(obj)s" was changed successfully.') % msg_dict self.message_user(request, msg, messages.SUCCESS) return self.response_post_save_change(request, obj)
def response_post_save_add(
self, request, obj)
Figure out where to redirect after the 'Save' button has been pressed when adding a new object.
def response_post_save_add(self, request, obj): """ Figure out where to redirect after the 'Save' button has been pressed when adding a new object. """ opts = self.model._meta if self.has_change_permission(request, None): post_url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url) else: post_url = reverse('admin:index', current_app=self.admin_site.name) return HttpResponseRedirect(post_url)
def response_post_save_change(
self, request, obj)
Figure out where to redirect after the 'Save' button has been pressed when editing an existing object.
def response_post_save_change(self, request, obj): """ Figure out where to redirect after the 'Save' button has been pressed when editing an existing object. """ opts = self.model._meta if self.has_change_permission(request, None): post_url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url) else: post_url = reverse('admin:index', current_app=self.admin_site.name) return HttpResponseRedirect(post_url)
def save_form(
self, request, form, change)
Given a ModelForm return an unsaved instance. change
is True if
the object is being changed, and False if it's being added.
def save_form(self, request, form, change): """ Given a ModelForm return an unsaved instance. ``change`` is True if the object is being changed, and False if it's being added. """ return form.save(commit=False)
def save_formset(
self, request, form, formset, change)
Given an inline formset save it to the database.
def save_formset(self, request, form, formset, change): """ Given an inline formset save it to the database. """ formset.save()
def save_model(
self, request, obj, form, change)
Given a model instance save it to the database.
def save_model(self, request, obj, form, change): """ Given a model instance save it to the database. """ obj.save()
Given the HttpRequest
, the parent ModelForm
instance, the
list of inline formsets and a boolean value based on whether the
parent is being added or changed, save the related objects to the
database. Note that at this point save_form() and save_model() have
already been called.
def to_field_allowed(
self, request, to_field)
Returns True if the model associated with this admin should be allowed to be referenced by the specified field.
def to_field_allowed(self, request, to_field): """ Returns True if the model associated with this admin should be allowed to be referenced by the specified field. """ opts = self.model._meta try: field = opts.get_field(to_field) except FieldDoesNotExist: return False # Always allow referencing the primary key since it's already possible # to get this information from the change view URL. if field.primary_key: return True # Make sure at least one of the models registered for this site # references this field through a FK or a M2M relationship. registered_models = set() for model, admin in self.admin_site._registry.items(): registered_models.add(model) for inline in admin.inlines: registered_models.add(inline.model) for related_object in opts.get_all_related_objects(include_hidden=True): related_model = related_object.model if (any(issubclass(model, related_model) for model in registered_models) and related_object.field.rel.get_related_field() == field): return True return False
def validate(
cls, model)
@classmethod def validate(cls, model): validator = cls.validator_class() validator.validate(cls, model)
class PlaylistAdmin
class PlaylistAdmin(admin.ModelAdmin): search_fields = ['title', 'public_id']
Ancestors (in MRO)
- PlaylistAdmin
- django.contrib.admin.options.ModelAdmin
- django.contrib.admin.options.BaseModelAdmin
- __builtin__.object
Class variables
var action_form
var actions
var actions_on_bottom
var actions_on_top
var actions_selection_counter
var add_form_template
var change_form_template
var change_list_template
var date_hierarchy
var delete_confirmation_template
var delete_selected_confirmation_template
var exclude
var fields
var fieldsets
var filter_horizontal
var filter_vertical
var form
var formfield_overrides
var inlines
var list_display
var list_display_links
var list_editable
var list_filter
var list_max_show_all
var list_per_page
var object_history_template
var ordering
var paginator
var prepopulated_fields
var preserve_filters
var radio_fields
var raw_id_fields
var readonly_fields
var save_as
var save_on_top
var search_fields
var validator_class
Instance variables
var declared_fieldsets
var media
var urls
Methods
def __init__(
self, model, admin_site)
def __init__(self, model, admin_site): self.model = model self.opts = model._meta self.admin_site = admin_site super(ModelAdmin, self).__init__()
def action_checkbox(
self, obj)
A list_display column containing a checkbox widget.
def action_checkbox(self, obj): """ A list_display column containing a checkbox widget. """ return helpers.checkbox.render(helpers.ACTION_CHECKBOX_NAME, force_text(obj.pk))
def add_view(
self, *args, **kwargs)
The 'add' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def change_view(
self, *args, **kwargs)
The 'change' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def changelist_view(
self, *args, **kwargs)
The 'change list' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def construct_change_message(
self, request, form, formsets)
Construct a change message from a changed object.
def construct_change_message(self, request, form, formsets): """ Construct a change message from a changed object. """ change_message = [] if form.changed_data: change_message.append(_('Changed %s.') % get_text_list(form.changed_data, _('and'))) if formsets: for formset in formsets: for added_object in formset.new_objects: change_message.append(_('Added %(name)s "%(object)s".') % {'name': force_text(added_object._meta.verbose_name), 'object': force_text(added_object)}) for changed_object, changed_fields in formset.changed_objects: change_message.append(_('Changed %(list)s for %(name)s "%(object)s".') % {'list': get_text_list(changed_fields, _('and')), 'name': force_text(changed_object._meta.verbose_name), 'object': force_text(changed_object)}) for deleted_object in formset.deleted_objects: change_message.append(_('Deleted %(name)s "%(object)s".') % {'name': force_text(deleted_object._meta.verbose_name), 'object': force_text(deleted_object)}) change_message = ' '.join(change_message) return change_message or _('No fields changed.')
def delete_model(
self, request, obj)
Given a model instance delete it from the database.
def delete_model(self, request, obj): """ Given a model instance delete it from the database. """ obj.delete()
def delete_view(
self, *args, **kwargs)
The 'delete' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def formfield_for_choice_field(
self, db_field, request=None, **kwargs)
Get a form Field for a database Field that has declared choices.
def formfield_for_choice_field(self, db_field, request=None, **kwargs): """ Get a form Field for a database Field that has declared choices. """ # If the field is named as a radio_field, use a RadioSelect if db_field.name in self.radio_fields: # Avoid stomping on custom widget/choices arguments. if 'widget' not in kwargs: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) if 'choices' not in kwargs: kwargs['choices'] = db_field.get_choices( include_blank=db_field.blank, blank_choice=[('', _('None'))] ) return db_field.formfield(**kwargs)
def formfield_for_dbfield(
self, db_field, **kwargs)
Hook for specifying the form Field instance for a given database Field instance.
If kwargs are given, they're passed to the form Field's constructor.
def formfield_for_dbfield(self, db_field, **kwargs): """ Hook for specifying the form Field instance for a given database Field instance. If kwargs are given, they're passed to the form Field's constructor. """ request = kwargs.pop("request", None) # If the field specifies choices, we don't need to look for special # admin widgets - we just need to use a select widget of some kind. if db_field.choices: return self.formfield_for_choice_field(db_field, request, **kwargs) # ForeignKey or ManyToManyFields if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)): # Combine the field kwargs with any options for formfield_overrides. # Make sure the passed in **kwargs override anything in # formfield_overrides because **kwargs is more specific, and should # always win. if db_field.__class__ in self.formfield_overrides: kwargs = dict(self.formfield_overrides[db_field.__class__], **kwargs) # Get the correct formfield. if isinstance(db_field, models.ForeignKey): formfield = self.formfield_for_foreignkey(db_field, request, **kwargs) elif isinstance(db_field, models.ManyToManyField): formfield = self.formfield_for_manytomany(db_field, request, **kwargs) # For non-raw_id fields, wrap the widget with a wrapper that adds # extra HTML -- the "add other" interface -- to the end of the # rendered output. formfield can be None if it came from a # OneToOneField with parent_link=True or a M2M intermediary. if formfield and db_field.name not in self.raw_id_fields: related_modeladmin = self.admin_site._registry.get( db_field.rel.to) can_add_related = bool(related_modeladmin and related_modeladmin.has_add_permission(request)) formfield.widget = widgets.RelatedFieldWidgetWrapper( formfield.widget, db_field.rel, self.admin_site, can_add_related=can_add_related) return formfield # If we've got overrides for the formfield defined, use 'em. **kwargs # passed to formfield_for_dbfield override the defaults. for klass in db_field.__class__.mro(): if klass in self.formfield_overrides: kwargs = dict(copy.deepcopy(self.formfield_overrides[klass]), **kwargs) return db_field.formfield(**kwargs) # For any other type of field, just call its formfield() method. return db_field.formfield(**kwargs)
def formfield_for_foreignkey(
self, db_field, request=None, **kwargs)
Get a form Field for a ForeignKey.
def formfield_for_foreignkey(self, db_field, request=None, **kwargs): """ Get a form Field for a ForeignKey. """ db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel, self.admin_site, using=db) elif db_field.name in self.radio_fields: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) kwargs['empty_label'] = _('None') if db_field.blank else None if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def formfield_for_manytomany(
self, db_field, request=None, **kwargs)
Get a form Field for a ManyToManyField.
def formfield_for_manytomany(self, db_field, request=None, **kwargs): """ Get a form Field for a ManyToManyField. """ # If it uses an intermediary model that isn't auto created, don't show # a field in admin. if not db_field.rel.through._meta.auto_created: return None db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel, self.admin_site, using=db) kwargs['help_text'] = '' elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)): kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical)) if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def get_action(
self, action)
Return a given action from a parameter, which can either be a callable, or the name of a method on the ModelAdmin. Return is a tuple of (callable, name, description).
def get_action(self, action): """ Return a given action from a parameter, which can either be a callable, or the name of a method on the ModelAdmin. Return is a tuple of (callable, name, description). """ # If the action is a callable, just use it. if callable(action): func = action action = action.__name__ # Next, look for a method. Grab it off self.__class__ to get an unbound # method instead of a bound one; this ensures that the calling # conventions are the same for functions and methods. elif hasattr(self.__class__, action): func = getattr(self.__class__, action) # Finally, look for a named method on the admin site else: try: func = self.admin_site.get_action(action) except KeyError: return None if hasattr(func, 'short_description'): description = func.short_description else: description = capfirst(action.replace('_', ' ')) return func, action, description
def get_action_choices(
self, request, default_choices=[(u'', u'---------')])
Return a list of choices for use in a form object. Each choice is a tuple (name, description).
def get_action_choices(self, request, default_choices=BLANK_CHOICE_DASH): """ Return a list of choices for use in a form object. Each choice is a tuple (name, description). """ choices = [] + default_choices for func, name, description in six.itervalues(self.get_actions(request)): choice = (name, description % model_format_dict(self.opts)) choices.append(choice) return choices
def get_actions(
self, request)
Return a dictionary mapping the names of all actions for this ModelAdmin to a tuple of (callable, name, description) for each action.
def get_actions(self, request): """ Return a dictionary mapping the names of all actions for this ModelAdmin to a tuple of (callable, name, description) for each action. """ # If self.actions is explicitly set to None that means that we don't # want *any* actions enabled on this page. from django.contrib.admin.views.main import _is_changelist_popup if self.actions is None or _is_changelist_popup(request): return SortedDict() actions = [] # Gather actions from the admin site first for (name, func) in self.admin_site.actions: description = getattr(func, 'short_description', name.replace('_', ' ')) actions.append((func, name, description)) # Then gather them from the model admin and all parent classes, # starting with self and working back up. for klass in self.__class__.mro()[::-1]: class_actions = getattr(klass, 'actions', []) # Avoid trying to iterate over None if not class_actions: continue actions.extend([self.get_action(action) for action in class_actions]) # get_action might have returned None, so filter any of those out. actions = filter(None, actions) # Convert the actions into a SortedDict keyed by name. actions = SortedDict([ (name, (func, name, desc)) for func, name, desc in actions ]) return actions
def get_changelist(
self, request, **kwargs)
Returns the ChangeList class for use on the changelist page.
def get_changelist(self, request, **kwargs): """ Returns the ChangeList class for use on the changelist page. """ from django.contrib.admin.views.main import ChangeList return ChangeList
def get_changelist_form(
self, request, **kwargs)
Returns a Form class for use in the Formset on the changelist page.
def get_changelist_form(self, request, **kwargs): """ Returns a Form class for use in the Formset on the changelist page. """ defaults = { "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) if (defaults.get('fields') is None and not modelform_defines_fields(defaults.get('form'))): defaults['fields'] = forms.ALL_FIELDS return modelform_factory(self.model, **defaults)
def get_changelist_formset(
self, request, **kwargs)
Returns a FormSet class for use on the changelist page if list_editable is used.
def get_changelist_formset(self, request, **kwargs): """ Returns a FormSet class for use on the changelist page if list_editable is used. """ defaults = { "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) return modelformset_factory(self.model, self.get_changelist_form(request), extra=0, fields=self.list_editable, **defaults)
def get_field_queryset(
self, db, db_field, request)
If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case).
def get_field_queryset(self, db, db_field, request): """ If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case). """ related_admin = self.admin_site._registry.get(db_field.rel.to, None) if related_admin is not None: ordering = related_admin.get_ordering(request) if ordering is not None and ordering != (): return db_field.rel.to._default_manager.using(db).order_by(*ordering).complex_filter(db_field.rel.limit_choices_to) return None
def get_fieldsets(
self, request, obj=None)
Hook for specifying fieldsets for the add form.
def get_fieldsets(self, request, obj=None): "Hook for specifying fieldsets for the add form." if self.declared_fieldsets: return self.declared_fieldsets form = self.get_form(request, obj, fields=None) fields = list(form.base_fields) + list(self.get_readonly_fields(request, obj)) return [(None, {'fields': fields})]
def get_form(
self, request, obj=None, **kwargs)
Returns a Form class for use in the admin add view. This is used by add_view and change_view.
def get_form(self, request, obj=None, **kwargs): """ Returns a Form class for use in the admin add view. This is used by add_view and change_view. """ if 'fields' in kwargs: fields = kwargs.pop('fields') else: fields = flatten_fieldsets(self.get_fieldsets(request, obj)) if self.exclude is None: exclude = [] else: exclude = list(self.exclude) exclude.extend(self.get_readonly_fields(request, obj)) if self.exclude is None and hasattr(self.form, '_meta') and self.form._meta.exclude: # Take the custom ModelForm's Meta.exclude into account only if the # ModelAdmin doesn't define its own. exclude.extend(self.form._meta.exclude) # if exclude is an empty list we pass None to be consistent with the # default on modelform_factory exclude = exclude or None defaults = { "form": self.form, "fields": fields, "exclude": exclude, "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) if defaults['fields'] is None and not modelform_defines_fields(defaults['form']): defaults['fields'] = forms.ALL_FIELDS try: return modelform_factory(self.model, **defaults) except FieldError as e: raise FieldError('%s. Check fields/fieldsets/exclude attributes of class %s.' % (e, self.__class__.__name__))
def get_formsets(
self, request, obj=None)
def get_formsets(self, request, obj=None): for inline in self.get_inline_instances(request, obj): yield inline.get_formset(request, obj)
def get_inline_instances(
self, request, obj=None)
def get_inline_instances(self, request, obj=None): inline_instances = [] for inline_class in self.inlines: inline = inline_class(self.model, self.admin_site) if request: if not (inline.has_add_permission(request) or inline.has_change_permission(request, obj) or inline.has_delete_permission(request, obj)): continue if not inline.has_add_permission(request): inline.max_num = 0 inline_instances.append(inline) return inline_instances
def get_list_display(
self, request)
Return a sequence containing the fields to be displayed on the changelist.
def get_list_display(self, request): """ Return a sequence containing the fields to be displayed on the changelist. """ return self.list_display
def get_list_display_links(
self, request, list_display)
Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display().
def get_list_display_links(self, request, list_display): """ Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display(). """ if self.list_display_links or not list_display: return self.list_display_links else: # Use only the first item in list_display as link return list(list_display)[:1]
def get_list_filter(
self, request)
Returns a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page.
def get_list_filter(self, request): """ Returns a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page. """ return self.list_filter
def get_model_perms(
self, request)
Returns a dict of all perms for this model. This dict has the keys
add
, change
, and delete
mapping to the True/False for each
of those actions.
def get_model_perms(self, request): """ Returns a dict of all perms for this model. This dict has the keys ``add``, ``change``, and ``delete`` mapping to the True/False for each of those actions. """ return { 'add': self.has_add_permission(request), 'change': self.has_change_permission(request), 'delete': self.has_delete_permission(request), }
def get_object(
self, request, object_id)
Returns an instance matching the primary key provided. None
is
returned if no match is found (or the object_id failed validation
against the primary key field).
def get_object(self, request, object_id): """ Returns an instance matching the primary key provided. ``None`` is returned if no match is found (or the object_id failed validation against the primary key field). """ queryset = self.get_queryset(request) model = queryset.model try: object_id = model._meta.pk.to_python(object_id) return queryset.get(pk=object_id) except (model.DoesNotExist, ValidationError, ValueError): return None
def get_ordering(
self, request)
Hook for specifying field ordering.
def get_ordering(self, request): """ Hook for specifying field ordering. """ return self.ordering or () # otherwise we might try to *None, which is bad ;)
def get_paginator(
self, request, queryset, per_page, orphans=0, allow_empty_first_page=True)
def get_paginator(self, request, queryset, per_page, orphans=0, allow_empty_first_page=True): return self.paginator(queryset, per_page, orphans, allow_empty_first_page)
def get_prepopulated_fields(
self, request, obj=None)
Hook for specifying custom prepopulated fields.
def get_prepopulated_fields(self, request, obj=None): """ Hook for specifying custom prepopulated fields. """ return self.prepopulated_fields
def get_preserved_filters(
self, request)
Returns the preserved filters querystring.
def get_preserved_filters(self, request): """ Returns the preserved filters querystring. """ match = request.resolver_match if self.preserve_filters and match: opts = self.model._meta current_url = '%s:%s' % (match.app_name, match.url_name) changelist_url = 'admin:%s_%s_changelist' % (opts.app_label, opts.model_name) if current_url == changelist_url: preserved_filters = request.GET.urlencode() else: preserved_filters = request.GET.get('_changelist_filters') if preserved_filters: return urlencode({'_changelist_filters': preserved_filters}) return ''
def get_queryset(
self, request)
Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view.
def get_queryset(self, request): """ Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view. """ qs = self.model._default_manager.get_queryset() # TODO: this should be handled by some parameter to the ChangeList. ordering = self.get_ordering(request) if ordering: qs = qs.order_by(*ordering) return qs
def get_readonly_fields(
self, request, obj=None)
Hook for specifying custom readonly fields.
def get_readonly_fields(self, request, obj=None): """ Hook for specifying custom readonly fields. """ return self.readonly_fields
def get_search_results(
self, request, queryset, search_term)
Returns a tuple containing a queryset to implement the search, and a boolean indicating if the results may contain duplicates.
def get_search_results(self, request, queryset, search_term): """ Returns a tuple containing a queryset to implement the search, and a boolean indicating if the results may contain duplicates. """ # Apply keyword searches. def construct_search(field_name): if field_name.startswith('^'): return "%s__istartswith" % field_name[1:] elif field_name.startswith('='): return "%s__iexact" % field_name[1:] elif field_name.startswith('@'): return "%s__search" % field_name[1:] else: return "%s__icontains" % field_name use_distinct = False if self.search_fields and search_term: orm_lookups = [construct_search(str(search_field)) for search_field in self.search_fields] for bit in search_term.split(): or_queries = [models.Q(**{orm_lookup: bit}) for orm_lookup in orm_lookups] queryset = queryset.filter(reduce(operator.or_, or_queries)) if not use_distinct: for search_spec in orm_lookups: if lookup_needs_distinct(self.opts, search_spec): use_distinct = True break return queryset, use_distinct
def get_urls(
self)
def get_urls(self): from django.conf.urls import patterns, url def wrap(view): def wrapper(*args, **kwargs): return self.admin_site.admin_view(view)(*args, **kwargs) return update_wrapper(wrapper, view) info = self.model._meta.app_label, self.model._meta.model_name urlpatterns = patterns('', url(r'^$', wrap(self.changelist_view), name='%s_%s_changelist' % info), url(r'^add/$', wrap(self.add_view), name='%s_%s_add' % info), url(r'^(.+)/history/$', wrap(self.history_view), name='%s_%s_history' % info), url(r'^(.+)/delete/$', wrap(self.delete_view), name='%s_%s_delete' % info), url(r'^(.+)/$', wrap(self.change_view), name='%s_%s_change' % info), ) return urlpatterns
def has_add_permission(
self, request)
Returns True if the given request has permission to add an object. Can be overridden by the user in subclasses.
def has_add_permission(self, request): """ Returns True if the given request has permission to add an object. Can be overridden by the user in subclasses. """ opts = self.opts codename = get_permission_codename('add', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_change_permission(
self, request, obj=None)
Returns True if the given request has permission to change the given
Django model instance, the default implementation doesn't examine the
obj
parameter.
Can be overridden by the user in subclasses. In such case it should
return True if the given request has permission to change the obj
model instance. If obj
is None, this should return True if the given
request has permission to change any object of the given type.
def has_change_permission(self, request, obj=None): """ Returns True if the given request has permission to change the given Django model instance, the default implementation doesn't examine the `obj` parameter. Can be overridden by the user in subclasses. In such case it should return True if the given request has permission to change the `obj` model instance. If `obj` is None, this should return True if the given request has permission to change *any* object of the given type. """ opts = self.opts codename = get_permission_codename('change', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_delete_permission(
self, request, obj=None)
Returns True if the given request has permission to change the given
Django model instance, the default implementation doesn't examine the
obj
parameter.
Can be overridden by the user in subclasses. In such case it should
return True if the given request has permission to delete the obj
model instance. If obj
is None, this should return True if the given
request has permission to delete any object of the given type.
def has_delete_permission(self, request, obj=None): """ Returns True if the given request has permission to change the given Django model instance, the default implementation doesn't examine the `obj` parameter. Can be overridden by the user in subclasses. In such case it should return True if the given request has permission to delete the `obj` model instance. If `obj` is None, this should return True if the given request has permission to delete *any* object of the given type. """ opts = self.opts codename = get_permission_codename('delete', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def history_view(
self, request, object_id, extra_context=None)
The 'history' admin view for this model.
def history_view(self, request, object_id, extra_context=None): "The 'history' admin view for this model." from django.contrib.admin.models import LogEntry # First check if the user can see this history. model = self.model obj = get_object_or_404(model, pk=unquote(object_id)) if not self.has_change_permission(request, obj): raise PermissionDenied # Then get the history for this object. opts = model._meta app_label = opts.app_label action_list = LogEntry.objects.filter( object_id=unquote(object_id), content_type__id__exact=ContentType.objects.get_for_model(model).id ).select_related().order_by('action_time') context = { 'title': _('Change history: %s') % force_text(obj), 'action_list': action_list, 'module_name': capfirst(force_text(opts.verbose_name_plural)), 'object': obj, 'app_label': app_label, 'opts': opts, 'preserved_filters': self.get_preserved_filters(request), } context.update(extra_context or {}) return TemplateResponse(request, self.object_history_template or [ "admin/%s/%s/object_history.html" % (app_label, opts.model_name), "admin/%s/object_history.html" % app_label, "admin/object_history.html" ], context, current_app=self.admin_site.name)
def log_addition(
self, request, object)
Log that an object has been successfully added.
The default implementation creates an admin LogEntry object.
def log_addition(self, request, object): """ Log that an object has been successfully added. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, ADDITION LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=ADDITION )
def log_change(
self, request, object, message)
Log that an object has been successfully changed.
The default implementation creates an admin LogEntry object.
def log_change(self, request, object, message): """ Log that an object has been successfully changed. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, CHANGE LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=CHANGE, change_message=message )
def log_deletion(
self, request, object, object_repr)
Log that an object will be deleted. Note that this method is called before the deletion.
The default implementation creates an admin LogEntry object.
def log_deletion(self, request, object, object_repr): """ Log that an object will be deleted. Note that this method is called before the deletion. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, DELETION LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(self.model).pk, object_id=object.pk, object_repr=object_repr, action_flag=DELETION )
def lookup_allowed(
self, lookup, value)
def lookup_allowed(self, lookup, value): model = self.model # Check FKey lookups that are allowed, so that popups produced by # ForeignKeyRawIdWidget, on the basis of ForeignKey.limit_choices_to, # are allowed to work. for l in model._meta.related_fkey_lookups: for k, v in widgets.url_params_from_lookup_dict(l).items(): if k == lookup and v == value: return True parts = lookup.split(LOOKUP_SEP) # Last term in lookup is a query term (__exact, __startswith etc) # This term can be ignored. if len(parts) > 1 and parts[-1] in QUERY_TERMS: parts.pop() # Special case -- foo__id__exact and foo__id queries are implied # if foo has been specifically included in the lookup list; so # drop __id if it is the last part. However, first we need to find # the pk attribute name. rel_name = None for part in parts[:-1]: try: field, _, _, _ = model._meta.get_field_by_name(part) except FieldDoesNotExist: # Lookups on non-existent fields are ok, since they're ignored # later. return True if hasattr(field, 'rel'): if field.rel is None: # This property or relation doesn't exist, but it's allowed # since it's ignored in ChangeList.get_filters(). return True model = field.rel.to rel_name = field.rel.get_related_field().name elif isinstance(field, RelatedObject): model = field.model rel_name = model._meta.pk.name else: rel_name = None if rel_name and len(parts) > 1 and parts[-1] == rel_name: parts.pop() if len(parts) == 1: return True clean_lookup = LOOKUP_SEP.join(parts) return clean_lookup in self.list_filter or clean_lookup == self.date_hierarchy
def message_user(
self, request, message, level=20, extra_tags='', fail_silently=False)
Send a message to the user. The default implementation posts a message using the django.contrib.messages backend.
Exposes almost the same API as messages.add_message(), but accepts the
positional arguments in a different order to maintain backwards
compatibility. For convenience, it accepts the level
argument as
a string rather than the usual level number.
def message_user(self, request, message, level=messages.INFO, extra_tags='', fail_silently=False): """ Send a message to the user. The default implementation posts a message using the django.contrib.messages backend. Exposes almost the same API as messages.add_message(), but accepts the positional arguments in a different order to maintain backwards compatibility. For convenience, it accepts the `level` argument as a string rather than the usual level number. """ if not isinstance(level, int): # attempt to get the level if passed a string try: level = getattr(messages.constants, level.upper()) except AttributeError: levels = messages.constants.DEFAULT_TAGS.values() levels_repr = ', '.join('`%s`' % l for l in levels) raise ValueError('Bad message level string: `%s`. ' 'Possible values are: %s' % (level, levels_repr)) messages.add_message(request, level, message, extra_tags=extra_tags, fail_silently=fail_silently)
def queryset(
*args, **kwargs)
def wrapped(*args, **kwargs): warnings.warn( "`%s.%s` is deprecated, use `%s` instead." % (self.class_name, self.old_method_name, self.new_method_name), self.deprecation_warning, 2) return f(*args, **kwargs)
def render_change_form(
self, request, context, add=False, change=False, form_url='', obj=None)
def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None): opts = self.model._meta app_label = opts.app_label preserved_filters = self.get_preserved_filters(request) form_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, form_url) context.update({ 'add': add, 'change': change, 'has_add_permission': self.has_add_permission(request), 'has_change_permission': self.has_change_permission(request, obj), 'has_delete_permission': self.has_delete_permission(request, obj), 'has_file_field': True, # FIXME - this should check if form or formsets have a FileField, 'has_absolute_url': hasattr(self.model, 'get_absolute_url'), 'form_url': form_url, 'opts': opts, 'content_type_id': ContentType.objects.get_for_model(self.model).id, 'save_as': self.save_as, 'save_on_top': self.save_on_top, }) if add and self.add_form_template is not None: form_template = self.add_form_template else: form_template = self.change_form_template return TemplateResponse(request, form_template or [ "admin/%s/%s/change_form.html" % (app_label, opts.model_name), "admin/%s/change_form.html" % app_label, "admin/change_form.html" ], context, current_app=self.admin_site.name)
def response_action(
self, request, queryset)
Handle an admin action. This is called if a request is POSTed to the changelist; it returns an HttpResponse if the action was handled, and None otherwise.
def response_action(self, request, queryset): """ Handle an admin action. This is called if a request is POSTed to the changelist; it returns an HttpResponse if the action was handled, and None otherwise. """ # There can be multiple action forms on the page (at the top # and bottom of the change list, for example). Get the action # whose button was pushed. try: action_index = int(request.POST.get('index', 0)) except ValueError: action_index = 0 # Construct the action form. data = request.POST.copy() data.pop(helpers.ACTION_CHECKBOX_NAME, None) data.pop("index", None) # Use the action whose button was pushed try: data.update({'action': data.getlist('action')[action_index]}) except IndexError: # If we didn't get an action from the chosen form that's invalid # POST data, so by deleting action it'll fail the validation check # below. So no need to do anything here pass action_form = self.action_form(data, auto_id=None) action_form.fields['action'].choices = self.get_action_choices(request) # If the form's valid we can handle the action. if action_form.is_valid(): action = action_form.cleaned_data['action'] select_across = action_form.cleaned_data['select_across'] func = self.get_actions(request)[action][0] # Get the list of selected PKs. If nothing's selected, we can't # perform an action on it, so bail. Except we want to perform # the action explicitly on all objects. selected = request.POST.getlist(helpers.ACTION_CHECKBOX_NAME) if not selected and not select_across: # Reminder that something needs to be selected or nothing will happen msg = _("Items must be selected in order to perform " "actions on them. No items have been changed.") self.message_user(request, msg, messages.WARNING) return None if not select_across: # Perform the action only on the selected objects queryset = queryset.filter(pk__in=selected) response = func(self, request, queryset) # Actions may return an HttpResponse-like object, which will be # used as the response from the POST. If not, we'll be a good # little HTTP citizen and redirect back to the changelist page. if isinstance(response, HttpResponseBase): return response else: return HttpResponseRedirect(request.get_full_path()) else: msg = _("No action selected.") self.message_user(request, msg, messages.WARNING) return None
def response_add(
self, request, obj, post_url_continue=None)
Determines the HttpResponse for the add_view stage.
def response_add(self, request, obj, post_url_continue=None): """ Determines the HttpResponse for the add_view stage. """ opts = obj._meta pk_value = obj._get_pk_val() preserved_filters = self.get_preserved_filters(request) msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)} # Here, we distinguish between different save types by checking for # the presence of keys in request.POST. if IS_POPUP_VAR in request.POST: return SimpleTemplateResponse('admin/popup_response.html', { 'pk_value': escape(pk_value), 'obj': escapejs(obj) }) elif "_continue" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) if post_url_continue is None: post_url_continue = reverse('admin:%s_%s_change' % (opts.app_label, opts.model_name), args=(pk_value,), current_app=self.admin_site.name) post_url_continue = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url_continue) return HttpResponseRedirect(post_url_continue) elif "_addanother" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may add another %(name)s below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = request.path redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) else: msg = _('The %(name)s "%(obj)s" was added successfully.') % msg_dict self.message_user(request, msg, messages.SUCCESS) return self.response_post_save_add(request, obj)
def response_change(
self, request, obj)
Determines the HttpResponse for the change_view stage.
def response_change(self, request, obj): """ Determines the HttpResponse for the change_view stage. """ opts = self.model._meta pk_value = obj._get_pk_val() preserved_filters = self.get_preserved_filters(request) msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)} if "_continue" in request.POST: msg = _('The %(name)s "%(obj)s" was changed successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = request.path redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) elif "_saveasnew" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = reverse('admin:%s_%s_change' % (opts.app_label, opts.model_name), args=(pk_value,), current_app=self.admin_site.name) redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) elif "_addanother" in request.POST: msg = _('The %(name)s "%(obj)s" was changed successfully. You may add another %(name)s below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = reverse('admin:%s_%s_add' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) else: msg = _('The %(name)s "%(obj)s" was changed successfully.') % msg_dict self.message_user(request, msg, messages.SUCCESS) return self.response_post_save_change(request, obj)
def response_post_save_add(
self, request, obj)
Figure out where to redirect after the 'Save' button has been pressed when adding a new object.
def response_post_save_add(self, request, obj): """ Figure out where to redirect after the 'Save' button has been pressed when adding a new object. """ opts = self.model._meta if self.has_change_permission(request, None): post_url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url) else: post_url = reverse('admin:index', current_app=self.admin_site.name) return HttpResponseRedirect(post_url)
def response_post_save_change(
self, request, obj)
Figure out where to redirect after the 'Save' button has been pressed when editing an existing object.
def response_post_save_change(self, request, obj): """ Figure out where to redirect after the 'Save' button has been pressed when editing an existing object. """ opts = self.model._meta if self.has_change_permission(request, None): post_url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url) else: post_url = reverse('admin:index', current_app=self.admin_site.name) return HttpResponseRedirect(post_url)
def save_form(
self, request, form, change)
Given a ModelForm return an unsaved instance. change
is True if
the object is being changed, and False if it's being added.
def save_form(self, request, form, change): """ Given a ModelForm return an unsaved instance. ``change`` is True if the object is being changed, and False if it's being added. """ return form.save(commit=False)
def save_formset(
self, request, form, formset, change)
Given an inline formset save it to the database.
def save_formset(self, request, form, formset, change): """ Given an inline formset save it to the database. """ formset.save()
def save_model(
self, request, obj, form, change)
Given a model instance save it to the database.
def save_model(self, request, obj, form, change): """ Given a model instance save it to the database. """ obj.save()
Given the HttpRequest
, the parent ModelForm
instance, the
list of inline formsets and a boolean value based on whether the
parent is being added or changed, save the related objects to the
database. Note that at this point save_form() and save_model() have
already been called.
def to_field_allowed(
self, request, to_field)
Returns True if the model associated with this admin should be allowed to be referenced by the specified field.
def to_field_allowed(self, request, to_field): """ Returns True if the model associated with this admin should be allowed to be referenced by the specified field. """ opts = self.model._meta try: field = opts.get_field(to_field) except FieldDoesNotExist: return False # Always allow referencing the primary key since it's already possible # to get this information from the change view URL. if field.primary_key: return True # Make sure at least one of the models registered for this site # references this field through a FK or a M2M relationship. registered_models = set() for model, admin in self.admin_site._registry.items(): registered_models.add(model) for inline in admin.inlines: registered_models.add(inline.model) for related_object in opts.get_all_related_objects(include_hidden=True): related_model = related_object.model if (any(issubclass(model, related_model) for model in registered_models) and related_object.field.rel.get_related_field() == field): return True return False
def validate(
cls, model)
@classmethod def validate(cls, model): validator = cls.validator_class() validator.validate(cls, model)
class RevisionAdmin
class RevisionAdmin(admin.ModelAdmin): search_fields = ['element_id', 'user'] ordering = ['-time']
Ancestors (in MRO)
- RevisionAdmin
- django.contrib.admin.options.ModelAdmin
- django.contrib.admin.options.BaseModelAdmin
- __builtin__.object
Class variables
var action_form
var actions
var actions_on_bottom
var actions_on_top
var actions_selection_counter
var add_form_template
var change_form_template
var change_list_template
var date_hierarchy
var delete_confirmation_template
var delete_selected_confirmation_template
var exclude
var fields
var fieldsets
var filter_horizontal
var filter_vertical
var form
var formfield_overrides
var inlines
var list_display
var list_display_links
var list_editable
var list_filter
var list_max_show_all
var list_per_page
var object_history_template
var ordering
var paginator
var prepopulated_fields
var preserve_filters
var radio_fields
var raw_id_fields
var readonly_fields
var save_as
var save_on_top
var search_fields
var validator_class
Instance variables
var declared_fieldsets
var media
var urls
Methods
def __init__(
self, model, admin_site)
def __init__(self, model, admin_site): self.model = model self.opts = model._meta self.admin_site = admin_site super(ModelAdmin, self).__init__()
def action_checkbox(
self, obj)
A list_display column containing a checkbox widget.
def action_checkbox(self, obj): """ A list_display column containing a checkbox widget. """ return helpers.checkbox.render(helpers.ACTION_CHECKBOX_NAME, force_text(obj.pk))
def add_view(
self, *args, **kwargs)
The 'add' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def change_view(
self, *args, **kwargs)
The 'change' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def changelist_view(
self, *args, **kwargs)
The 'change list' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def construct_change_message(
self, request, form, formsets)
Construct a change message from a changed object.
def construct_change_message(self, request, form, formsets): """ Construct a change message from a changed object. """ change_message = [] if form.changed_data: change_message.append(_('Changed %s.') % get_text_list(form.changed_data, _('and'))) if formsets: for formset in formsets: for added_object in formset.new_objects: change_message.append(_('Added %(name)s "%(object)s".') % {'name': force_text(added_object._meta.verbose_name), 'object': force_text(added_object)}) for changed_object, changed_fields in formset.changed_objects: change_message.append(_('Changed %(list)s for %(name)s "%(object)s".') % {'list': get_text_list(changed_fields, _('and')), 'name': force_text(changed_object._meta.verbose_name), 'object': force_text(changed_object)}) for deleted_object in formset.deleted_objects: change_message.append(_('Deleted %(name)s "%(object)s".') % {'name': force_text(deleted_object._meta.verbose_name), 'object': force_text(deleted_object)}) change_message = ' '.join(change_message) return change_message or _('No fields changed.')
def delete_model(
self, request, obj)
Given a model instance delete it from the database.
def delete_model(self, request, obj): """ Given a model instance delete it from the database. """ obj.delete()
def delete_view(
self, *args, **kwargs)
The 'delete' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def formfield_for_choice_field(
self, db_field, request=None, **kwargs)
Get a form Field for a database Field that has declared choices.
def formfield_for_choice_field(self, db_field, request=None, **kwargs): """ Get a form Field for a database Field that has declared choices. """ # If the field is named as a radio_field, use a RadioSelect if db_field.name in self.radio_fields: # Avoid stomping on custom widget/choices arguments. if 'widget' not in kwargs: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) if 'choices' not in kwargs: kwargs['choices'] = db_field.get_choices( include_blank=db_field.blank, blank_choice=[('', _('None'))] ) return db_field.formfield(**kwargs)
def formfield_for_dbfield(
self, db_field, **kwargs)
Hook for specifying the form Field instance for a given database Field instance.
If kwargs are given, they're passed to the form Field's constructor.
def formfield_for_dbfield(self, db_field, **kwargs): """ Hook for specifying the form Field instance for a given database Field instance. If kwargs are given, they're passed to the form Field's constructor. """ request = kwargs.pop("request", None) # If the field specifies choices, we don't need to look for special # admin widgets - we just need to use a select widget of some kind. if db_field.choices: return self.formfield_for_choice_field(db_field, request, **kwargs) # ForeignKey or ManyToManyFields if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)): # Combine the field kwargs with any options for formfield_overrides. # Make sure the passed in **kwargs override anything in # formfield_overrides because **kwargs is more specific, and should # always win. if db_field.__class__ in self.formfield_overrides: kwargs = dict(self.formfield_overrides[db_field.__class__], **kwargs) # Get the correct formfield. if isinstance(db_field, models.ForeignKey): formfield = self.formfield_for_foreignkey(db_field, request, **kwargs) elif isinstance(db_field, models.ManyToManyField): formfield = self.formfield_for_manytomany(db_field, request, **kwargs) # For non-raw_id fields, wrap the widget with a wrapper that adds # extra HTML -- the "add other" interface -- to the end of the # rendered output. formfield can be None if it came from a # OneToOneField with parent_link=True or a M2M intermediary. if formfield and db_field.name not in self.raw_id_fields: related_modeladmin = self.admin_site._registry.get( db_field.rel.to) can_add_related = bool(related_modeladmin and related_modeladmin.has_add_permission(request)) formfield.widget = widgets.RelatedFieldWidgetWrapper( formfield.widget, db_field.rel, self.admin_site, can_add_related=can_add_related) return formfield # If we've got overrides for the formfield defined, use 'em. **kwargs # passed to formfield_for_dbfield override the defaults. for klass in db_field.__class__.mro(): if klass in self.formfield_overrides: kwargs = dict(copy.deepcopy(self.formfield_overrides[klass]), **kwargs) return db_field.formfield(**kwargs) # For any other type of field, just call its formfield() method. return db_field.formfield(**kwargs)
def formfield_for_foreignkey(
self, db_field, request=None, **kwargs)
Get a form Field for a ForeignKey.
def formfield_for_foreignkey(self, db_field, request=None, **kwargs): """ Get a form Field for a ForeignKey. """ db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel, self.admin_site, using=db) elif db_field.name in self.radio_fields: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) kwargs['empty_label'] = _('None') if db_field.blank else None if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def formfield_for_manytomany(
self, db_field, request=None, **kwargs)
Get a form Field for a ManyToManyField.
def formfield_for_manytomany(self, db_field, request=None, **kwargs): """ Get a form Field for a ManyToManyField. """ # If it uses an intermediary model that isn't auto created, don't show # a field in admin. if not db_field.rel.through._meta.auto_created: return None db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel, self.admin_site, using=db) kwargs['help_text'] = '' elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)): kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical)) if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def get_action(
self, action)
Return a given action from a parameter, which can either be a callable, or the name of a method on the ModelAdmin. Return is a tuple of (callable, name, description).
def get_action(self, action): """ Return a given action from a parameter, which can either be a callable, or the name of a method on the ModelAdmin. Return is a tuple of (callable, name, description). """ # If the action is a callable, just use it. if callable(action): func = action action = action.__name__ # Next, look for a method. Grab it off self.__class__ to get an unbound # method instead of a bound one; this ensures that the calling # conventions are the same for functions and methods. elif hasattr(self.__class__, action): func = getattr(self.__class__, action) # Finally, look for a named method on the admin site else: try: func = self.admin_site.get_action(action) except KeyError: return None if hasattr(func, 'short_description'): description = func.short_description else: description = capfirst(action.replace('_', ' ')) return func, action, description
def get_action_choices(
self, request, default_choices=[(u'', u'---------')])
Return a list of choices for use in a form object. Each choice is a tuple (name, description).
def get_action_choices(self, request, default_choices=BLANK_CHOICE_DASH): """ Return a list of choices for use in a form object. Each choice is a tuple (name, description). """ choices = [] + default_choices for func, name, description in six.itervalues(self.get_actions(request)): choice = (name, description % model_format_dict(self.opts)) choices.append(choice) return choices
def get_actions(
self, request)
Return a dictionary mapping the names of all actions for this ModelAdmin to a tuple of (callable, name, description) for each action.
def get_actions(self, request): """ Return a dictionary mapping the names of all actions for this ModelAdmin to a tuple of (callable, name, description) for each action. """ # If self.actions is explicitly set to None that means that we don't # want *any* actions enabled on this page. from django.contrib.admin.views.main import _is_changelist_popup if self.actions is None or _is_changelist_popup(request): return SortedDict() actions = [] # Gather actions from the admin site first for (name, func) in self.admin_site.actions: description = getattr(func, 'short_description', name.replace('_', ' ')) actions.append((func, name, description)) # Then gather them from the model admin and all parent classes, # starting with self and working back up. for klass in self.__class__.mro()[::-1]: class_actions = getattr(klass, 'actions', []) # Avoid trying to iterate over None if not class_actions: continue actions.extend([self.get_action(action) for action in class_actions]) # get_action might have returned None, so filter any of those out. actions = filter(None, actions) # Convert the actions into a SortedDict keyed by name. actions = SortedDict([ (name, (func, name, desc)) for func, name, desc in actions ]) return actions
def get_changelist(
self, request, **kwargs)
Returns the ChangeList class for use on the changelist page.
def get_changelist(self, request, **kwargs): """ Returns the ChangeList class for use on the changelist page. """ from django.contrib.admin.views.main import ChangeList return ChangeList
def get_changelist_form(
self, request, **kwargs)
Returns a Form class for use in the Formset on the changelist page.
def get_changelist_form(self, request, **kwargs): """ Returns a Form class for use in the Formset on the changelist page. """ defaults = { "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) if (defaults.get('fields') is None and not modelform_defines_fields(defaults.get('form'))): defaults['fields'] = forms.ALL_FIELDS return modelform_factory(self.model, **defaults)
def get_changelist_formset(
self, request, **kwargs)
Returns a FormSet class for use on the changelist page if list_editable is used.
def get_changelist_formset(self, request, **kwargs): """ Returns a FormSet class for use on the changelist page if list_editable is used. """ defaults = { "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) return modelformset_factory(self.model, self.get_changelist_form(request), extra=0, fields=self.list_editable, **defaults)
def get_field_queryset(
self, db, db_field, request)
If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case).
def get_field_queryset(self, db, db_field, request): """ If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case). """ related_admin = self.admin_site._registry.get(db_field.rel.to, None) if related_admin is not None: ordering = related_admin.get_ordering(request) if ordering is not None and ordering != (): return db_field.rel.to._default_manager.using(db).order_by(*ordering).complex_filter(db_field.rel.limit_choices_to) return None
def get_fieldsets(
self, request, obj=None)
Hook for specifying fieldsets for the add form.
def get_fieldsets(self, request, obj=None): "Hook for specifying fieldsets for the add form." if self.declared_fieldsets: return self.declared_fieldsets form = self.get_form(request, obj, fields=None) fields = list(form.base_fields) + list(self.get_readonly_fields(request, obj)) return [(None, {'fields': fields})]
def get_form(
self, request, obj=None, **kwargs)
Returns a Form class for use in the admin add view. This is used by add_view and change_view.
def get_form(self, request, obj=None, **kwargs): """ Returns a Form class for use in the admin add view. This is used by add_view and change_view. """ if 'fields' in kwargs: fields = kwargs.pop('fields') else: fields = flatten_fieldsets(self.get_fieldsets(request, obj)) if self.exclude is None: exclude = [] else: exclude = list(self.exclude) exclude.extend(self.get_readonly_fields(request, obj)) if self.exclude is None and hasattr(self.form, '_meta') and self.form._meta.exclude: # Take the custom ModelForm's Meta.exclude into account only if the # ModelAdmin doesn't define its own. exclude.extend(self.form._meta.exclude) # if exclude is an empty list we pass None to be consistent with the # default on modelform_factory exclude = exclude or None defaults = { "form": self.form, "fields": fields, "exclude": exclude, "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) if defaults['fields'] is None and not modelform_defines_fields(defaults['form']): defaults['fields'] = forms.ALL_FIELDS try: return modelform_factory(self.model, **defaults) except FieldError as e: raise FieldError('%s. Check fields/fieldsets/exclude attributes of class %s.' % (e, self.__class__.__name__))
def get_formsets(
self, request, obj=None)
def get_formsets(self, request, obj=None): for inline in self.get_inline_instances(request, obj): yield inline.get_formset(request, obj)
def get_inline_instances(
self, request, obj=None)
def get_inline_instances(self, request, obj=None): inline_instances = [] for inline_class in self.inlines: inline = inline_class(self.model, self.admin_site) if request: if not (inline.has_add_permission(request) or inline.has_change_permission(request, obj) or inline.has_delete_permission(request, obj)): continue if not inline.has_add_permission(request): inline.max_num = 0 inline_instances.append(inline) return inline_instances
def get_list_display(
self, request)
Return a sequence containing the fields to be displayed on the changelist.
def get_list_display(self, request): """ Return a sequence containing the fields to be displayed on the changelist. """ return self.list_display
def get_list_display_links(
self, request, list_display)
Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display().
def get_list_display_links(self, request, list_display): """ Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display(). """ if self.list_display_links or not list_display: return self.list_display_links else: # Use only the first item in list_display as link return list(list_display)[:1]
def get_list_filter(
self, request)
Returns a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page.
def get_list_filter(self, request): """ Returns a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page. """ return self.list_filter
def get_model_perms(
self, request)
Returns a dict of all perms for this model. This dict has the keys
add
, change
, and delete
mapping to the True/False for each
of those actions.
def get_model_perms(self, request): """ Returns a dict of all perms for this model. This dict has the keys ``add``, ``change``, and ``delete`` mapping to the True/False for each of those actions. """ return { 'add': self.has_add_permission(request), 'change': self.has_change_permission(request), 'delete': self.has_delete_permission(request), }
def get_object(
self, request, object_id)
Returns an instance matching the primary key provided. None
is
returned if no match is found (or the object_id failed validation
against the primary key field).
def get_object(self, request, object_id): """ Returns an instance matching the primary key provided. ``None`` is returned if no match is found (or the object_id failed validation against the primary key field). """ queryset = self.get_queryset(request) model = queryset.model try: object_id = model._meta.pk.to_python(object_id) return queryset.get(pk=object_id) except (model.DoesNotExist, ValidationError, ValueError): return None
def get_ordering(
self, request)
Hook for specifying field ordering.
def get_ordering(self, request): """ Hook for specifying field ordering. """ return self.ordering or () # otherwise we might try to *None, which is bad ;)
def get_paginator(
self, request, queryset, per_page, orphans=0, allow_empty_first_page=True)
def get_paginator(self, request, queryset, per_page, orphans=0, allow_empty_first_page=True): return self.paginator(queryset, per_page, orphans, allow_empty_first_page)
def get_prepopulated_fields(
self, request, obj=None)
Hook for specifying custom prepopulated fields.
def get_prepopulated_fields(self, request, obj=None): """ Hook for specifying custom prepopulated fields. """ return self.prepopulated_fields
def get_preserved_filters(
self, request)
Returns the preserved filters querystring.
def get_preserved_filters(self, request): """ Returns the preserved filters querystring. """ match = request.resolver_match if self.preserve_filters and match: opts = self.model._meta current_url = '%s:%s' % (match.app_name, match.url_name) changelist_url = 'admin:%s_%s_changelist' % (opts.app_label, opts.model_name) if current_url == changelist_url: preserved_filters = request.GET.urlencode() else: preserved_filters = request.GET.get('_changelist_filters') if preserved_filters: return urlencode({'_changelist_filters': preserved_filters}) return ''
def get_queryset(
self, request)
Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view.
def get_queryset(self, request): """ Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view. """ qs = self.model._default_manager.get_queryset() # TODO: this should be handled by some parameter to the ChangeList. ordering = self.get_ordering(request) if ordering: qs = qs.order_by(*ordering) return qs
def get_readonly_fields(
self, request, obj=None)
Hook for specifying custom readonly fields.
def get_readonly_fields(self, request, obj=None): """ Hook for specifying custom readonly fields. """ return self.readonly_fields
def get_search_results(
self, request, queryset, search_term)
Returns a tuple containing a queryset to implement the search, and a boolean indicating if the results may contain duplicates.
def get_search_results(self, request, queryset, search_term): """ Returns a tuple containing a queryset to implement the search, and a boolean indicating if the results may contain duplicates. """ # Apply keyword searches. def construct_search(field_name): if field_name.startswith('^'): return "%s__istartswith" % field_name[1:] elif field_name.startswith('='): return "%s__iexact" % field_name[1:] elif field_name.startswith('@'): return "%s__search" % field_name[1:] else: return "%s__icontains" % field_name use_distinct = False if self.search_fields and search_term: orm_lookups = [construct_search(str(search_field)) for search_field in self.search_fields] for bit in search_term.split(): or_queries = [models.Q(**{orm_lookup: bit}) for orm_lookup in orm_lookups] queryset = queryset.filter(reduce(operator.or_, or_queries)) if not use_distinct: for search_spec in orm_lookups: if lookup_needs_distinct(self.opts, search_spec): use_distinct = True break return queryset, use_distinct
def get_urls(
self)
def get_urls(self): from django.conf.urls import patterns, url def wrap(view): def wrapper(*args, **kwargs): return self.admin_site.admin_view(view)(*args, **kwargs) return update_wrapper(wrapper, view) info = self.model._meta.app_label, self.model._meta.model_name urlpatterns = patterns('', url(r'^$', wrap(self.changelist_view), name='%s_%s_changelist' % info), url(r'^add/$', wrap(self.add_view), name='%s_%s_add' % info), url(r'^(.+)/history/$', wrap(self.history_view), name='%s_%s_history' % info), url(r'^(.+)/delete/$', wrap(self.delete_view), name='%s_%s_delete' % info), url(r'^(.+)/$', wrap(self.change_view), name='%s_%s_change' % info), ) return urlpatterns
def has_add_permission(
self, request)
Returns True if the given request has permission to add an object. Can be overridden by the user in subclasses.
def has_add_permission(self, request): """ Returns True if the given request has permission to add an object. Can be overridden by the user in subclasses. """ opts = self.opts codename = get_permission_codename('add', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_change_permission(
self, request, obj=None)
Returns True if the given request has permission to change the given
Django model instance, the default implementation doesn't examine the
obj
parameter.
Can be overridden by the user in subclasses. In such case it should
return True if the given request has permission to change the obj
model instance. If obj
is None, this should return True if the given
request has permission to change any object of the given type.
def has_change_permission(self, request, obj=None): """ Returns True if the given request has permission to change the given Django model instance, the default implementation doesn't examine the `obj` parameter. Can be overridden by the user in subclasses. In such case it should return True if the given request has permission to change the `obj` model instance. If `obj` is None, this should return True if the given request has permission to change *any* object of the given type. """ opts = self.opts codename = get_permission_codename('change', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_delete_permission(
self, request, obj=None)
Returns True if the given request has permission to change the given
Django model instance, the default implementation doesn't examine the
obj
parameter.
Can be overridden by the user in subclasses. In such case it should
return True if the given request has permission to delete the obj
model instance. If obj
is None, this should return True if the given
request has permission to delete any object of the given type.
def has_delete_permission(self, request, obj=None): """ Returns True if the given request has permission to change the given Django model instance, the default implementation doesn't examine the `obj` parameter. Can be overridden by the user in subclasses. In such case it should return True if the given request has permission to delete the `obj` model instance. If `obj` is None, this should return True if the given request has permission to delete *any* object of the given type. """ opts = self.opts codename = get_permission_codename('delete', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def history_view(
self, request, object_id, extra_context=None)
The 'history' admin view for this model.
def history_view(self, request, object_id, extra_context=None): "The 'history' admin view for this model." from django.contrib.admin.models import LogEntry # First check if the user can see this history. model = self.model obj = get_object_or_404(model, pk=unquote(object_id)) if not self.has_change_permission(request, obj): raise PermissionDenied # Then get the history for this object. opts = model._meta app_label = opts.app_label action_list = LogEntry.objects.filter( object_id=unquote(object_id), content_type__id__exact=ContentType.objects.get_for_model(model).id ).select_related().order_by('action_time') context = { 'title': _('Change history: %s') % force_text(obj), 'action_list': action_list, 'module_name': capfirst(force_text(opts.verbose_name_plural)), 'object': obj, 'app_label': app_label, 'opts': opts, 'preserved_filters': self.get_preserved_filters(request), } context.update(extra_context or {}) return TemplateResponse(request, self.object_history_template or [ "admin/%s/%s/object_history.html" % (app_label, opts.model_name), "admin/%s/object_history.html" % app_label, "admin/object_history.html" ], context, current_app=self.admin_site.name)
def log_addition(
self, request, object)
Log that an object has been successfully added.
The default implementation creates an admin LogEntry object.
def log_addition(self, request, object): """ Log that an object has been successfully added. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, ADDITION LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=ADDITION )
def log_change(
self, request, object, message)
Log that an object has been successfully changed.
The default implementation creates an admin LogEntry object.
def log_change(self, request, object, message): """ Log that an object has been successfully changed. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, CHANGE LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=CHANGE, change_message=message )
def log_deletion(
self, request, object, object_repr)
Log that an object will be deleted. Note that this method is called before the deletion.
The default implementation creates an admin LogEntry object.
def log_deletion(self, request, object, object_repr): """ Log that an object will be deleted. Note that this method is called before the deletion. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, DELETION LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(self.model).pk, object_id=object.pk, object_repr=object_repr, action_flag=DELETION )
def lookup_allowed(
self, lookup, value)
def lookup_allowed(self, lookup, value): model = self.model # Check FKey lookups that are allowed, so that popups produced by # ForeignKeyRawIdWidget, on the basis of ForeignKey.limit_choices_to, # are allowed to work. for l in model._meta.related_fkey_lookups: for k, v in widgets.url_params_from_lookup_dict(l).items(): if k == lookup and v == value: return True parts = lookup.split(LOOKUP_SEP) # Last term in lookup is a query term (__exact, __startswith etc) # This term can be ignored. if len(parts) > 1 and parts[-1] in QUERY_TERMS: parts.pop() # Special case -- foo__id__exact and foo__id queries are implied # if foo has been specifically included in the lookup list; so # drop __id if it is the last part. However, first we need to find # the pk attribute name. rel_name = None for part in parts[:-1]: try: field, _, _, _ = model._meta.get_field_by_name(part) except FieldDoesNotExist: # Lookups on non-existent fields are ok, since they're ignored # later. return True if hasattr(field, 'rel'): if field.rel is None: # This property or relation doesn't exist, but it's allowed # since it's ignored in ChangeList.get_filters(). return True model = field.rel.to rel_name = field.rel.get_related_field().name elif isinstance(field, RelatedObject): model = field.model rel_name = model._meta.pk.name else: rel_name = None if rel_name and len(parts) > 1 and parts[-1] == rel_name: parts.pop() if len(parts) == 1: return True clean_lookup = LOOKUP_SEP.join(parts) return clean_lookup in self.list_filter or clean_lookup == self.date_hierarchy
def message_user(
self, request, message, level=20, extra_tags='', fail_silently=False)
Send a message to the user. The default implementation posts a message using the django.contrib.messages backend.
Exposes almost the same API as messages.add_message(), but accepts the
positional arguments in a different order to maintain backwards
compatibility. For convenience, it accepts the level
argument as
a string rather than the usual level number.
def message_user(self, request, message, level=messages.INFO, extra_tags='', fail_silently=False): """ Send a message to the user. The default implementation posts a message using the django.contrib.messages backend. Exposes almost the same API as messages.add_message(), but accepts the positional arguments in a different order to maintain backwards compatibility. For convenience, it accepts the `level` argument as a string rather than the usual level number. """ if not isinstance(level, int): # attempt to get the level if passed a string try: level = getattr(messages.constants, level.upper()) except AttributeError: levels = messages.constants.DEFAULT_TAGS.values() levels_repr = ', '.join('`%s`' % l for l in levels) raise ValueError('Bad message level string: `%s`. ' 'Possible values are: %s' % (level, levels_repr)) messages.add_message(request, level, message, extra_tags=extra_tags, fail_silently=fail_silently)
def queryset(
*args, **kwargs)
def wrapped(*args, **kwargs): warnings.warn( "`%s.%s` is deprecated, use `%s` instead." % (self.class_name, self.old_method_name, self.new_method_name), self.deprecation_warning, 2) return f(*args, **kwargs)
def render_change_form(
self, request, context, add=False, change=False, form_url='', obj=None)
def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None): opts = self.model._meta app_label = opts.app_label preserved_filters = self.get_preserved_filters(request) form_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, form_url) context.update({ 'add': add, 'change': change, 'has_add_permission': self.has_add_permission(request), 'has_change_permission': self.has_change_permission(request, obj), 'has_delete_permission': self.has_delete_permission(request, obj), 'has_file_field': True, # FIXME - this should check if form or formsets have a FileField, 'has_absolute_url': hasattr(self.model, 'get_absolute_url'), 'form_url': form_url, 'opts': opts, 'content_type_id': ContentType.objects.get_for_model(self.model).id, 'save_as': self.save_as, 'save_on_top': self.save_on_top, }) if add and self.add_form_template is not None: form_template = self.add_form_template else: form_template = self.change_form_template return TemplateResponse(request, form_template or [ "admin/%s/%s/change_form.html" % (app_label, opts.model_name), "admin/%s/change_form.html" % app_label, "admin/change_form.html" ], context, current_app=self.admin_site.name)
def response_action(
self, request, queryset)
Handle an admin action. This is called if a request is POSTed to the changelist; it returns an HttpResponse if the action was handled, and None otherwise.
def response_action(self, request, queryset): """ Handle an admin action. This is called if a request is POSTed to the changelist; it returns an HttpResponse if the action was handled, and None otherwise. """ # There can be multiple action forms on the page (at the top # and bottom of the change list, for example). Get the action # whose button was pushed. try: action_index = int(request.POST.get('index', 0)) except ValueError: action_index = 0 # Construct the action form. data = request.POST.copy() data.pop(helpers.ACTION_CHECKBOX_NAME, None) data.pop("index", None) # Use the action whose button was pushed try: data.update({'action': data.getlist('action')[action_index]}) except IndexError: # If we didn't get an action from the chosen form that's invalid # POST data, so by deleting action it'll fail the validation check # below. So no need to do anything here pass action_form = self.action_form(data, auto_id=None) action_form.fields['action'].choices = self.get_action_choices(request) # If the form's valid we can handle the action. if action_form.is_valid(): action = action_form.cleaned_data['action'] select_across = action_form.cleaned_data['select_across'] func = self.get_actions(request)[action][0] # Get the list of selected PKs. If nothing's selected, we can't # perform an action on it, so bail. Except we want to perform # the action explicitly on all objects. selected = request.POST.getlist(helpers.ACTION_CHECKBOX_NAME) if not selected and not select_across: # Reminder that something needs to be selected or nothing will happen msg = _("Items must be selected in order to perform " "actions on them. No items have been changed.") self.message_user(request, msg, messages.WARNING) return None if not select_across: # Perform the action only on the selected objects queryset = queryset.filter(pk__in=selected) response = func(self, request, queryset) # Actions may return an HttpResponse-like object, which will be # used as the response from the POST. If not, we'll be a good # little HTTP citizen and redirect back to the changelist page. if isinstance(response, HttpResponseBase): return response else: return HttpResponseRedirect(request.get_full_path()) else: msg = _("No action selected.") self.message_user(request, msg, messages.WARNING) return None
def response_add(
self, request, obj, post_url_continue=None)
Determines the HttpResponse for the add_view stage.
def response_add(self, request, obj, post_url_continue=None): """ Determines the HttpResponse for the add_view stage. """ opts = obj._meta pk_value = obj._get_pk_val() preserved_filters = self.get_preserved_filters(request) msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)} # Here, we distinguish between different save types by checking for # the presence of keys in request.POST. if IS_POPUP_VAR in request.POST: return SimpleTemplateResponse('admin/popup_response.html', { 'pk_value': escape(pk_value), 'obj': escapejs(obj) }) elif "_continue" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) if post_url_continue is None: post_url_continue = reverse('admin:%s_%s_change' % (opts.app_label, opts.model_name), args=(pk_value,), current_app=self.admin_site.name) post_url_continue = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url_continue) return HttpResponseRedirect(post_url_continue) elif "_addanother" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may add another %(name)s below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = request.path redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) else: msg = _('The %(name)s "%(obj)s" was added successfully.') % msg_dict self.message_user(request, msg, messages.SUCCESS) return self.response_post_save_add(request, obj)
def response_change(
self, request, obj)
Determines the HttpResponse for the change_view stage.
def response_change(self, request, obj): """ Determines the HttpResponse for the change_view stage. """ opts = self.model._meta pk_value = obj._get_pk_val() preserved_filters = self.get_preserved_filters(request) msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)} if "_continue" in request.POST: msg = _('The %(name)s "%(obj)s" was changed successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = request.path redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) elif "_saveasnew" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = reverse('admin:%s_%s_change' % (opts.app_label, opts.model_name), args=(pk_value,), current_app=self.admin_site.name) redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) elif "_addanother" in request.POST: msg = _('The %(name)s "%(obj)s" was changed successfully. You may add another %(name)s below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = reverse('admin:%s_%s_add' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) else: msg = _('The %(name)s "%(obj)s" was changed successfully.') % msg_dict self.message_user(request, msg, messages.SUCCESS) return self.response_post_save_change(request, obj)
def response_post_save_add(
self, request, obj)
Figure out where to redirect after the 'Save' button has been pressed when adding a new object.
def response_post_save_add(self, request, obj): """ Figure out where to redirect after the 'Save' button has been pressed when adding a new object. """ opts = self.model._meta if self.has_change_permission(request, None): post_url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url) else: post_url = reverse('admin:index', current_app=self.admin_site.name) return HttpResponseRedirect(post_url)
def response_post_save_change(
self, request, obj)
Figure out where to redirect after the 'Save' button has been pressed when editing an existing object.
def response_post_save_change(self, request, obj): """ Figure out where to redirect after the 'Save' button has been pressed when editing an existing object. """ opts = self.model._meta if self.has_change_permission(request, None): post_url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url) else: post_url = reverse('admin:index', current_app=self.admin_site.name) return HttpResponseRedirect(post_url)
def save_form(
self, request, form, change)
Given a ModelForm return an unsaved instance. change
is True if
the object is being changed, and False if it's being added.
def save_form(self, request, form, change): """ Given a ModelForm return an unsaved instance. ``change`` is True if the object is being changed, and False if it's being added. """ return form.save(commit=False)
def save_formset(
self, request, form, formset, change)
Given an inline formset save it to the database.
def save_formset(self, request, form, formset, change): """ Given an inline formset save it to the database. """ formset.save()
def save_model(
self, request, obj, form, change)
Given a model instance save it to the database.
def save_model(self, request, obj, form, change): """ Given a model instance save it to the database. """ obj.save()
Given the HttpRequest
, the parent ModelForm
instance, the
list of inline formsets and a boolean value based on whether the
parent is being added or changed, save the related objects to the
database. Note that at this point save_form() and save_model() have
already been called.
def to_field_allowed(
self, request, to_field)
Returns True if the model associated with this admin should be allowed to be referenced by the specified field.
def to_field_allowed(self, request, to_field): """ Returns True if the model associated with this admin should be allowed to be referenced by the specified field. """ opts = self.model._meta try: field = opts.get_field(to_field) except FieldDoesNotExist: return False # Always allow referencing the primary key since it's already possible # to get this information from the change view URL. if field.primary_key: return True # Make sure at least one of the models registered for this site # references this field through a FK or a M2M relationship. registered_models = set() for model, admin in self.admin_site._registry.items(): registered_models.add(model) for inline in admin.inlines: registered_models.add(inline.model) for related_object in opts.get_all_related_objects(include_hidden=True): related_model = related_object.model if (any(issubclass(model, related_model) for model in registered_models) and related_object.field.rel.get_related_field() == field): return True return False
def validate(
cls, model)
@classmethod def validate(cls, model): validator = cls.validator_class() validator.validate(cls, model)
class UserProfileAdmin
class UserProfileAdmin(UserAdmin): inlines = [UserProfileInline]
Ancestors (in MRO)
- UserProfileAdmin
- django.contrib.auth.admin.UserAdmin
- django.contrib.admin.options.ModelAdmin
- django.contrib.admin.options.BaseModelAdmin
- __builtin__.object
Class variables
var action_form
var actions
var actions_on_bottom
var actions_on_top
var actions_selection_counter
var add_fieldsets
var add_form
var add_form_template
var change_form_template
var change_list_template
var change_password_form
var change_user_password_template
var date_hierarchy
var delete_confirmation_template
var delete_selected_confirmation_template
var exclude
var fields
var fieldsets
var filter_horizontal
var filter_vertical
var form
var formfield_overrides
var inlines
var list_display
var list_display_links
var list_editable
var list_filter
var list_max_show_all
var list_per_page
var object_history_template
var ordering
var paginator
var prepopulated_fields
var preserve_filters
var radio_fields
var raw_id_fields
var readonly_fields
var save_as
var save_on_top
var search_fields
var validator_class
Instance variables
var declared_fieldsets
var media
var urls
Methods
def __init__(
self, model, admin_site)
def __init__(self, model, admin_site): self.model = model self.opts = model._meta self.admin_site = admin_site super(ModelAdmin, self).__init__()
def action_checkbox(
self, obj)
A list_display column containing a checkbox widget.
def action_checkbox(self, obj): """ A list_display column containing a checkbox widget. """ return helpers.checkbox.render(helpers.ACTION_CHECKBOX_NAME, force_text(obj.pk))
def add_view(
self, *args, **kwargs)
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def change_view(
self, *args, **kwargs)
The 'change' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def changelist_view(
self, *args, **kwargs)
The 'change list' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def construct_change_message(
self, request, form, formsets)
Construct a change message from a changed object.
def construct_change_message(self, request, form, formsets): """ Construct a change message from a changed object. """ change_message = [] if form.changed_data: change_message.append(_('Changed %s.') % get_text_list(form.changed_data, _('and'))) if formsets: for formset in formsets: for added_object in formset.new_objects: change_message.append(_('Added %(name)s "%(object)s".') % {'name': force_text(added_object._meta.verbose_name), 'object': force_text(added_object)}) for changed_object, changed_fields in formset.changed_objects: change_message.append(_('Changed %(list)s for %(name)s "%(object)s".') % {'list': get_text_list(changed_fields, _('and')), 'name': force_text(changed_object._meta.verbose_name), 'object': force_text(changed_object)}) for deleted_object in formset.deleted_objects: change_message.append(_('Deleted %(name)s "%(object)s".') % {'name': force_text(deleted_object._meta.verbose_name), 'object': force_text(deleted_object)}) change_message = ' '.join(change_message) return change_message or _('No fields changed.')
def delete_model(
self, request, obj)
Given a model instance delete it from the database.
def delete_model(self, request, obj): """ Given a model instance delete it from the database. """ obj.delete()
def delete_view(
self, *args, **kwargs)
The 'delete' admin view for this model.
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def formfield_for_choice_field(
self, db_field, request=None, **kwargs)
Get a form Field for a database Field that has declared choices.
def formfield_for_choice_field(self, db_field, request=None, **kwargs): """ Get a form Field for a database Field that has declared choices. """ # If the field is named as a radio_field, use a RadioSelect if db_field.name in self.radio_fields: # Avoid stomping on custom widget/choices arguments. if 'widget' not in kwargs: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) if 'choices' not in kwargs: kwargs['choices'] = db_field.get_choices( include_blank=db_field.blank, blank_choice=[('', _('None'))] ) return db_field.formfield(**kwargs)
def formfield_for_dbfield(
self, db_field, **kwargs)
Hook for specifying the form Field instance for a given database Field instance.
If kwargs are given, they're passed to the form Field's constructor.
def formfield_for_dbfield(self, db_field, **kwargs): """ Hook for specifying the form Field instance for a given database Field instance. If kwargs are given, they're passed to the form Field's constructor. """ request = kwargs.pop("request", None) # If the field specifies choices, we don't need to look for special # admin widgets - we just need to use a select widget of some kind. if db_field.choices: return self.formfield_for_choice_field(db_field, request, **kwargs) # ForeignKey or ManyToManyFields if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)): # Combine the field kwargs with any options for formfield_overrides. # Make sure the passed in **kwargs override anything in # formfield_overrides because **kwargs is more specific, and should # always win. if db_field.__class__ in self.formfield_overrides: kwargs = dict(self.formfield_overrides[db_field.__class__], **kwargs) # Get the correct formfield. if isinstance(db_field, models.ForeignKey): formfield = self.formfield_for_foreignkey(db_field, request, **kwargs) elif isinstance(db_field, models.ManyToManyField): formfield = self.formfield_for_manytomany(db_field, request, **kwargs) # For non-raw_id fields, wrap the widget with a wrapper that adds # extra HTML -- the "add other" interface -- to the end of the # rendered output. formfield can be None if it came from a # OneToOneField with parent_link=True or a M2M intermediary. if formfield and db_field.name not in self.raw_id_fields: related_modeladmin = self.admin_site._registry.get( db_field.rel.to) can_add_related = bool(related_modeladmin and related_modeladmin.has_add_permission(request)) formfield.widget = widgets.RelatedFieldWidgetWrapper( formfield.widget, db_field.rel, self.admin_site, can_add_related=can_add_related) return formfield # If we've got overrides for the formfield defined, use 'em. **kwargs # passed to formfield_for_dbfield override the defaults. for klass in db_field.__class__.mro(): if klass in self.formfield_overrides: kwargs = dict(copy.deepcopy(self.formfield_overrides[klass]), **kwargs) return db_field.formfield(**kwargs) # For any other type of field, just call its formfield() method. return db_field.formfield(**kwargs)
def formfield_for_foreignkey(
self, db_field, request=None, **kwargs)
Get a form Field for a ForeignKey.
def formfield_for_foreignkey(self, db_field, request=None, **kwargs): """ Get a form Field for a ForeignKey. """ db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel, self.admin_site, using=db) elif db_field.name in self.radio_fields: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) kwargs['empty_label'] = _('None') if db_field.blank else None if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def formfield_for_manytomany(
self, db_field, request=None, **kwargs)
Get a form Field for a ManyToManyField.
def formfield_for_manytomany(self, db_field, request=None, **kwargs): """ Get a form Field for a ManyToManyField. """ # If it uses an intermediary model that isn't auto created, don't show # a field in admin. if not db_field.rel.through._meta.auto_created: return None db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel, self.admin_site, using=db) kwargs['help_text'] = '' elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)): kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical)) if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def get_action(
self, action)
Return a given action from a parameter, which can either be a callable, or the name of a method on the ModelAdmin. Return is a tuple of (callable, name, description).
def get_action(self, action): """ Return a given action from a parameter, which can either be a callable, or the name of a method on the ModelAdmin. Return is a tuple of (callable, name, description). """ # If the action is a callable, just use it. if callable(action): func = action action = action.__name__ # Next, look for a method. Grab it off self.__class__ to get an unbound # method instead of a bound one; this ensures that the calling # conventions are the same for functions and methods. elif hasattr(self.__class__, action): func = getattr(self.__class__, action) # Finally, look for a named method on the admin site else: try: func = self.admin_site.get_action(action) except KeyError: return None if hasattr(func, 'short_description'): description = func.short_description else: description = capfirst(action.replace('_', ' ')) return func, action, description
def get_action_choices(
self, request, default_choices=[(u'', u'---------')])
Return a list of choices for use in a form object. Each choice is a tuple (name, description).
def get_action_choices(self, request, default_choices=BLANK_CHOICE_DASH): """ Return a list of choices for use in a form object. Each choice is a tuple (name, description). """ choices = [] + default_choices for func, name, description in six.itervalues(self.get_actions(request)): choice = (name, description % model_format_dict(self.opts)) choices.append(choice) return choices
def get_actions(
self, request)
Return a dictionary mapping the names of all actions for this ModelAdmin to a tuple of (callable, name, description) for each action.
def get_actions(self, request): """ Return a dictionary mapping the names of all actions for this ModelAdmin to a tuple of (callable, name, description) for each action. """ # If self.actions is explicitly set to None that means that we don't # want *any* actions enabled on this page. from django.contrib.admin.views.main import _is_changelist_popup if self.actions is None or _is_changelist_popup(request): return SortedDict() actions = [] # Gather actions from the admin site first for (name, func) in self.admin_site.actions: description = getattr(func, 'short_description', name.replace('_', ' ')) actions.append((func, name, description)) # Then gather them from the model admin and all parent classes, # starting with self and working back up. for klass in self.__class__.mro()[::-1]: class_actions = getattr(klass, 'actions', []) # Avoid trying to iterate over None if not class_actions: continue actions.extend([self.get_action(action) for action in class_actions]) # get_action might have returned None, so filter any of those out. actions = filter(None, actions) # Convert the actions into a SortedDict keyed by name. actions = SortedDict([ (name, (func, name, desc)) for func, name, desc in actions ]) return actions
def get_changelist(
self, request, **kwargs)
Returns the ChangeList class for use on the changelist page.
def get_changelist(self, request, **kwargs): """ Returns the ChangeList class for use on the changelist page. """ from django.contrib.admin.views.main import ChangeList return ChangeList
def get_changelist_form(
self, request, **kwargs)
Returns a Form class for use in the Formset on the changelist page.
def get_changelist_form(self, request, **kwargs): """ Returns a Form class for use in the Formset on the changelist page. """ defaults = { "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) if (defaults.get('fields') is None and not modelform_defines_fields(defaults.get('form'))): defaults['fields'] = forms.ALL_FIELDS return modelform_factory(self.model, **defaults)
def get_changelist_formset(
self, request, **kwargs)
Returns a FormSet class for use on the changelist page if list_editable is used.
def get_changelist_formset(self, request, **kwargs): """ Returns a FormSet class for use on the changelist page if list_editable is used. """ defaults = { "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) return modelformset_factory(self.model, self.get_changelist_form(request), extra=0, fields=self.list_editable, **defaults)
def get_field_queryset(
self, db, db_field, request)
If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case).
def get_field_queryset(self, db, db_field, request): """ If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case). """ related_admin = self.admin_site._registry.get(db_field.rel.to, None) if related_admin is not None: ordering = related_admin.get_ordering(request) if ordering is not None and ordering != (): return db_field.rel.to._default_manager.using(db).order_by(*ordering).complex_filter(db_field.rel.limit_choices_to) return None
def get_fieldsets(
self, request, obj=None)
def get_fieldsets(self, request, obj=None): if not obj: return self.add_fieldsets return super(UserAdmin, self).get_fieldsets(request, obj)
def get_form(
self, request, obj=None, **kwargs)
Use special form during user creation
def get_form(self, request, obj=None, **kwargs): """ Use special form during user creation """ defaults = {} if obj is None: defaults.update({ 'form': self.add_form, 'fields': admin.util.flatten_fieldsets(self.add_fieldsets), }) defaults.update(kwargs) return super(UserAdmin, self).get_form(request, obj, **defaults)
def get_formsets(
self, request, obj=None)
def get_formsets(self, request, obj=None): for inline in self.get_inline_instances(request, obj): yield inline.get_formset(request, obj)
def get_inline_instances(
self, request, obj=None)
def get_inline_instances(self, request, obj=None): inline_instances = [] for inline_class in self.inlines: inline = inline_class(self.model, self.admin_site) if request: if not (inline.has_add_permission(request) or inline.has_change_permission(request, obj) or inline.has_delete_permission(request, obj)): continue if not inline.has_add_permission(request): inline.max_num = 0 inline_instances.append(inline) return inline_instances
def get_list_display(
self, request)
Return a sequence containing the fields to be displayed on the changelist.
def get_list_display(self, request): """ Return a sequence containing the fields to be displayed on the changelist. """ return self.list_display
def get_list_display_links(
self, request, list_display)
Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display().
def get_list_display_links(self, request, list_display): """ Return a sequence containing the fields to be displayed as links on the changelist. The list_display parameter is the list of fields returned by get_list_display(). """ if self.list_display_links or not list_display: return self.list_display_links else: # Use only the first item in list_display as link return list(list_display)[:1]
def get_list_filter(
self, request)
Returns a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page.
def get_list_filter(self, request): """ Returns a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page. """ return self.list_filter
def get_model_perms(
self, request)
Returns a dict of all perms for this model. This dict has the keys
add
, change
, and delete
mapping to the True/False for each
of those actions.
def get_model_perms(self, request): """ Returns a dict of all perms for this model. This dict has the keys ``add``, ``change``, and ``delete`` mapping to the True/False for each of those actions. """ return { 'add': self.has_add_permission(request), 'change': self.has_change_permission(request), 'delete': self.has_delete_permission(request), }
def get_object(
self, request, object_id)
Returns an instance matching the primary key provided. None
is
returned if no match is found (or the object_id failed validation
against the primary key field).
def get_object(self, request, object_id): """ Returns an instance matching the primary key provided. ``None`` is returned if no match is found (or the object_id failed validation against the primary key field). """ queryset = self.get_queryset(request) model = queryset.model try: object_id = model._meta.pk.to_python(object_id) return queryset.get(pk=object_id) except (model.DoesNotExist, ValidationError, ValueError): return None
def get_ordering(
self, request)
Hook for specifying field ordering.
def get_ordering(self, request): """ Hook for specifying field ordering. """ return self.ordering or () # otherwise we might try to *None, which is bad ;)
def get_paginator(
self, request, queryset, per_page, orphans=0, allow_empty_first_page=True)
def get_paginator(self, request, queryset, per_page, orphans=0, allow_empty_first_page=True): return self.paginator(queryset, per_page, orphans, allow_empty_first_page)
def get_prepopulated_fields(
self, request, obj=None)
Hook for specifying custom prepopulated fields.
def get_prepopulated_fields(self, request, obj=None): """ Hook for specifying custom prepopulated fields. """ return self.prepopulated_fields
def get_preserved_filters(
self, request)
Returns the preserved filters querystring.
def get_preserved_filters(self, request): """ Returns the preserved filters querystring. """ match = request.resolver_match if self.preserve_filters and match: opts = self.model._meta current_url = '%s:%s' % (match.app_name, match.url_name) changelist_url = 'admin:%s_%s_changelist' % (opts.app_label, opts.model_name) if current_url == changelist_url: preserved_filters = request.GET.urlencode() else: preserved_filters = request.GET.get('_changelist_filters') if preserved_filters: return urlencode({'_changelist_filters': preserved_filters}) return ''
def get_queryset(
self, request)
Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view.
def get_queryset(self, request): """ Returns a QuerySet of all model instances that can be edited by the admin site. This is used by changelist_view. """ qs = self.model._default_manager.get_queryset() # TODO: this should be handled by some parameter to the ChangeList. ordering = self.get_ordering(request) if ordering: qs = qs.order_by(*ordering) return qs
def get_readonly_fields(
self, request, obj=None)
Hook for specifying custom readonly fields.
def get_readonly_fields(self, request, obj=None): """ Hook for specifying custom readonly fields. """ return self.readonly_fields
def get_search_results(
self, request, queryset, search_term)
Returns a tuple containing a queryset to implement the search, and a boolean indicating if the results may contain duplicates.
def get_search_results(self, request, queryset, search_term): """ Returns a tuple containing a queryset to implement the search, and a boolean indicating if the results may contain duplicates. """ # Apply keyword searches. def construct_search(field_name): if field_name.startswith('^'): return "%s__istartswith" % field_name[1:] elif field_name.startswith('='): return "%s__iexact" % field_name[1:] elif field_name.startswith('@'): return "%s__search" % field_name[1:] else: return "%s__icontains" % field_name use_distinct = False if self.search_fields and search_term: orm_lookups = [construct_search(str(search_field)) for search_field in self.search_fields] for bit in search_term.split(): or_queries = [models.Q(**{orm_lookup: bit}) for orm_lookup in orm_lookups] queryset = queryset.filter(reduce(operator.or_, or_queries)) if not use_distinct: for search_spec in orm_lookups: if lookup_needs_distinct(self.opts, search_spec): use_distinct = True break return queryset, use_distinct
def get_urls(
self)
def get_urls(self): from django.conf.urls import patterns return patterns('', (r'^(\d+)/password/$', self.admin_site.admin_view(self.user_change_password)) ) + super(UserAdmin, self).get_urls()
def has_add_permission(
self, request)
Returns True if the given request has permission to add an object. Can be overridden by the user in subclasses.
def has_add_permission(self, request): """ Returns True if the given request has permission to add an object. Can be overridden by the user in subclasses. """ opts = self.opts codename = get_permission_codename('add', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_change_permission(
self, request, obj=None)
Returns True if the given request has permission to change the given
Django model instance, the default implementation doesn't examine the
obj
parameter.
Can be overridden by the user in subclasses. In such case it should
return True if the given request has permission to change the obj
model instance. If obj
is None, this should return True if the given
request has permission to change any object of the given type.
def has_change_permission(self, request, obj=None): """ Returns True if the given request has permission to change the given Django model instance, the default implementation doesn't examine the `obj` parameter. Can be overridden by the user in subclasses. In such case it should return True if the given request has permission to change the `obj` model instance. If `obj` is None, this should return True if the given request has permission to change *any* object of the given type. """ opts = self.opts codename = get_permission_codename('change', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_delete_permission(
self, request, obj=None)
Returns True if the given request has permission to change the given
Django model instance, the default implementation doesn't examine the
obj
parameter.
Can be overridden by the user in subclasses. In such case it should
return True if the given request has permission to delete the obj
model instance. If obj
is None, this should return True if the given
request has permission to delete any object of the given type.
def has_delete_permission(self, request, obj=None): """ Returns True if the given request has permission to change the given Django model instance, the default implementation doesn't examine the `obj` parameter. Can be overridden by the user in subclasses. In such case it should return True if the given request has permission to delete the `obj` model instance. If `obj` is None, this should return True if the given request has permission to delete *any* object of the given type. """ opts = self.opts codename = get_permission_codename('delete', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def history_view(
self, request, object_id, extra_context=None)
The 'history' admin view for this model.
def history_view(self, request, object_id, extra_context=None): "The 'history' admin view for this model." from django.contrib.admin.models import LogEntry # First check if the user can see this history. model = self.model obj = get_object_or_404(model, pk=unquote(object_id)) if not self.has_change_permission(request, obj): raise PermissionDenied # Then get the history for this object. opts = model._meta app_label = opts.app_label action_list = LogEntry.objects.filter( object_id=unquote(object_id), content_type__id__exact=ContentType.objects.get_for_model(model).id ).select_related().order_by('action_time') context = { 'title': _('Change history: %s') % force_text(obj), 'action_list': action_list, 'module_name': capfirst(force_text(opts.verbose_name_plural)), 'object': obj, 'app_label': app_label, 'opts': opts, 'preserved_filters': self.get_preserved_filters(request), } context.update(extra_context or {}) return TemplateResponse(request, self.object_history_template or [ "admin/%s/%s/object_history.html" % (app_label, opts.model_name), "admin/%s/object_history.html" % app_label, "admin/object_history.html" ], context, current_app=self.admin_site.name)
def log_addition(
self, request, object)
Log that an object has been successfully added.
The default implementation creates an admin LogEntry object.
def log_addition(self, request, object): """ Log that an object has been successfully added. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, ADDITION LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=ADDITION )
def log_change(
self, request, object, message)
Log that an object has been successfully changed.
The default implementation creates an admin LogEntry object.
def log_change(self, request, object, message): """ Log that an object has been successfully changed. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, CHANGE LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(object).pk, object_id=object.pk, object_repr=force_text(object), action_flag=CHANGE, change_message=message )
def log_deletion(
self, request, object, object_repr)
Log that an object will be deleted. Note that this method is called before the deletion.
The default implementation creates an admin LogEntry object.
def log_deletion(self, request, object, object_repr): """ Log that an object will be deleted. Note that this method is called before the deletion. The default implementation creates an admin LogEntry object. """ from django.contrib.admin.models import LogEntry, DELETION LogEntry.objects.log_action( user_id=request.user.pk, content_type_id=ContentType.objects.get_for_model(self.model).pk, object_id=object.pk, object_repr=object_repr, action_flag=DELETION )
def lookup_allowed(
self, lookup, value)
def lookup_allowed(self, lookup, value): # See #20078: we don't want to allow any lookups involving passwords. if lookup.startswith('password'): return False return super(UserAdmin, self).lookup_allowed(lookup, value)
def message_user(
self, request, message, level=20, extra_tags='', fail_silently=False)
Send a message to the user. The default implementation posts a message using the django.contrib.messages backend.
Exposes almost the same API as messages.add_message(), but accepts the
positional arguments in a different order to maintain backwards
compatibility. For convenience, it accepts the level
argument as
a string rather than the usual level number.
def message_user(self, request, message, level=messages.INFO, extra_tags='', fail_silently=False): """ Send a message to the user. The default implementation posts a message using the django.contrib.messages backend. Exposes almost the same API as messages.add_message(), but accepts the positional arguments in a different order to maintain backwards compatibility. For convenience, it accepts the `level` argument as a string rather than the usual level number. """ if not isinstance(level, int): # attempt to get the level if passed a string try: level = getattr(messages.constants, level.upper()) except AttributeError: levels = messages.constants.DEFAULT_TAGS.values() levels_repr = ', '.join('`%s`' % l for l in levels) raise ValueError('Bad message level string: `%s`. ' 'Possible values are: %s' % (level, levels_repr)) messages.add_message(request, level, message, extra_tags=extra_tags, fail_silently=fail_silently)
def queryset(
*args, **kwargs)
def wrapped(*args, **kwargs): warnings.warn( "`%s.%s` is deprecated, use `%s` instead." % (self.class_name, self.old_method_name, self.new_method_name), self.deprecation_warning, 2) return f(*args, **kwargs)
def render_change_form(
self, request, context, add=False, change=False, form_url='', obj=None)
def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None): opts = self.model._meta app_label = opts.app_label preserved_filters = self.get_preserved_filters(request) form_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, form_url) context.update({ 'add': add, 'change': change, 'has_add_permission': self.has_add_permission(request), 'has_change_permission': self.has_change_permission(request, obj), 'has_delete_permission': self.has_delete_permission(request, obj), 'has_file_field': True, # FIXME - this should check if form or formsets have a FileField, 'has_absolute_url': hasattr(self.model, 'get_absolute_url'), 'form_url': form_url, 'opts': opts, 'content_type_id': ContentType.objects.get_for_model(self.model).id, 'save_as': self.save_as, 'save_on_top': self.save_on_top, }) if add and self.add_form_template is not None: form_template = self.add_form_template else: form_template = self.change_form_template return TemplateResponse(request, form_template or [ "admin/%s/%s/change_form.html" % (app_label, opts.model_name), "admin/%s/change_form.html" % app_label, "admin/change_form.html" ], context, current_app=self.admin_site.name)
def response_action(
self, request, queryset)
Handle an admin action. This is called if a request is POSTed to the changelist; it returns an HttpResponse if the action was handled, and None otherwise.
def response_action(self, request, queryset): """ Handle an admin action. This is called if a request is POSTed to the changelist; it returns an HttpResponse if the action was handled, and None otherwise. """ # There can be multiple action forms on the page (at the top # and bottom of the change list, for example). Get the action # whose button was pushed. try: action_index = int(request.POST.get('index', 0)) except ValueError: action_index = 0 # Construct the action form. data = request.POST.copy() data.pop(helpers.ACTION_CHECKBOX_NAME, None) data.pop("index", None) # Use the action whose button was pushed try: data.update({'action': data.getlist('action')[action_index]}) except IndexError: # If we didn't get an action from the chosen form that's invalid # POST data, so by deleting action it'll fail the validation check # below. So no need to do anything here pass action_form = self.action_form(data, auto_id=None) action_form.fields['action'].choices = self.get_action_choices(request) # If the form's valid we can handle the action. if action_form.is_valid(): action = action_form.cleaned_data['action'] select_across = action_form.cleaned_data['select_across'] func = self.get_actions(request)[action][0] # Get the list of selected PKs. If nothing's selected, we can't # perform an action on it, so bail. Except we want to perform # the action explicitly on all objects. selected = request.POST.getlist(helpers.ACTION_CHECKBOX_NAME) if not selected and not select_across: # Reminder that something needs to be selected or nothing will happen msg = _("Items must be selected in order to perform " "actions on them. No items have been changed.") self.message_user(request, msg, messages.WARNING) return None if not select_across: # Perform the action only on the selected objects queryset = queryset.filter(pk__in=selected) response = func(self, request, queryset) # Actions may return an HttpResponse-like object, which will be # used as the response from the POST. If not, we'll be a good # little HTTP citizen and redirect back to the changelist page. if isinstance(response, HttpResponseBase): return response else: return HttpResponseRedirect(request.get_full_path()) else: msg = _("No action selected.") self.message_user(request, msg, messages.WARNING) return None
def response_add(
self, request, obj, post_url_continue=None)
Determines the HttpResponse for the add_view stage. It mostly defers to its superclass implementation but is customized because the User model has a slightly different workflow.
def response_add(self, request, obj, post_url_continue=None): """ Determines the HttpResponse for the add_view stage. It mostly defers to its superclass implementation but is customized because the User model has a slightly different workflow. """ # We should allow further modification of the user just added i.e. the # 'Save' button should behave like the 'Save and continue editing' # button except in two scenarios: # * The user has pressed the 'Save and add another' button # * We are adding a user in a popup if '_addanother' not in request.POST and IS_POPUP_VAR not in request.POST: request.POST['_continue'] = 1 return super(UserAdmin, self).response_add(request, obj, post_url_continue)
def response_change(
self, request, obj)
Determines the HttpResponse for the change_view stage.
def response_change(self, request, obj): """ Determines the HttpResponse for the change_view stage. """ opts = self.model._meta pk_value = obj._get_pk_val() preserved_filters = self.get_preserved_filters(request) msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)} if "_continue" in request.POST: msg = _('The %(name)s "%(obj)s" was changed successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = request.path redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) elif "_saveasnew" in request.POST: msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = reverse('admin:%s_%s_change' % (opts.app_label, opts.model_name), args=(pk_value,), current_app=self.admin_site.name) redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) elif "_addanother" in request.POST: msg = _('The %(name)s "%(obj)s" was changed successfully. You may add another %(name)s below.') % msg_dict self.message_user(request, msg, messages.SUCCESS) redirect_url = reverse('admin:%s_%s_add' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) else: msg = _('The %(name)s "%(obj)s" was changed successfully.') % msg_dict self.message_user(request, msg, messages.SUCCESS) return self.response_post_save_change(request, obj)
def response_post_save_add(
self, request, obj)
Figure out where to redirect after the 'Save' button has been pressed when adding a new object.
def response_post_save_add(self, request, obj): """ Figure out where to redirect after the 'Save' button has been pressed when adding a new object. """ opts = self.model._meta if self.has_change_permission(request, None): post_url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url) else: post_url = reverse('admin:index', current_app=self.admin_site.name) return HttpResponseRedirect(post_url)
def response_post_save_change(
self, request, obj)
Figure out where to redirect after the 'Save' button has been pressed when editing an existing object.
def response_post_save_change(self, request, obj): """ Figure out where to redirect after the 'Save' button has been pressed when editing an existing object. """ opts = self.model._meta if self.has_change_permission(request, None): post_url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name), current_app=self.admin_site.name) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url) else: post_url = reverse('admin:index', current_app=self.admin_site.name) return HttpResponseRedirect(post_url)
def save_form(
self, request, form, change)
Given a ModelForm return an unsaved instance. change
is True if
the object is being changed, and False if it's being added.
def save_form(self, request, form, change): """ Given a ModelForm return an unsaved instance. ``change`` is True if the object is being changed, and False if it's being added. """ return form.save(commit=False)
def save_formset(
self, request, form, formset, change)
Given an inline formset save it to the database.
def save_formset(self, request, form, formset, change): """ Given an inline formset save it to the database. """ formset.save()
def save_model(
self, request, obj, form, change)
Given a model instance save it to the database.
def save_model(self, request, obj, form, change): """ Given a model instance save it to the database. """ obj.save()
Given the HttpRequest
, the parent ModelForm
instance, the
list of inline formsets and a boolean value based on whether the
parent is being added or changed, save the related objects to the
database. Note that at this point save_form() and save_model() have
already been called.
def to_field_allowed(
self, request, to_field)
Returns True if the model associated with this admin should be allowed to be referenced by the specified field.
def to_field_allowed(self, request, to_field): """ Returns True if the model associated with this admin should be allowed to be referenced by the specified field. """ opts = self.model._meta try: field = opts.get_field(to_field) except FieldDoesNotExist: return False # Always allow referencing the primary key since it's already possible # to get this information from the change view URL. if field.primary_key: return True # Make sure at least one of the models registered for this site # references this field through a FK or a M2M relationship. registered_models = set() for model, admin in self.admin_site._registry.items(): registered_models.add(model) for inline in admin.inlines: registered_models.add(inline.model) for related_object in opts.get_all_related_objects(include_hidden=True): related_model = related_object.model if (any(issubclass(model, related_model) for model in registered_models) and related_object.field.rel.get_related_field() == field): return True return False
def user_change_password(
self, *args, **kwargs)
def _wrapper(self, *args, **kwargs): @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs)
def validate(
cls, model)
@classmethod def validate(cls, model): validator = cls.validator_class() validator.validate(cls, model)
class UserProfileInline
class UserProfileInline(admin.StackedInline): model = UserProfile
Ancestors (in MRO)
- UserProfileInline
- django.contrib.admin.options.StackedInline
- django.contrib.admin.options.InlineModelAdmin
- django.contrib.admin.options.BaseModelAdmin
- __builtin__.object
Class variables
var can_delete
var exclude
var extra
var fields
var fieldsets
var filter_horizontal
var filter_vertical
var fk_name
var form
var formfield_overrides
var formset
var max_num
var model
var ordering
var prepopulated_fields
var radio_fields
var raw_id_fields
var readonly_fields
var template
var validator_class
var verbose_name
var verbose_name_plural
Instance variables
var declared_fieldsets
var media
Methods
def __init__(
self, parent_model, admin_site)
def __init__(self, parent_model, admin_site): self.admin_site = admin_site self.parent_model = parent_model self.opts = self.model._meta super(InlineModelAdmin, self).__init__() if self.verbose_name is None: self.verbose_name = self.model._meta.verbose_name if self.verbose_name_plural is None: self.verbose_name_plural = self.model._meta.verbose_name_plural
def formfield_for_choice_field(
self, db_field, request=None, **kwargs)
Get a form Field for a database Field that has declared choices.
def formfield_for_choice_field(self, db_field, request=None, **kwargs): """ Get a form Field for a database Field that has declared choices. """ # If the field is named as a radio_field, use a RadioSelect if db_field.name in self.radio_fields: # Avoid stomping on custom widget/choices arguments. if 'widget' not in kwargs: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) if 'choices' not in kwargs: kwargs['choices'] = db_field.get_choices( include_blank=db_field.blank, blank_choice=[('', _('None'))] ) return db_field.formfield(**kwargs)
def formfield_for_dbfield(
self, db_field, **kwargs)
Hook for specifying the form Field instance for a given database Field instance.
If kwargs are given, they're passed to the form Field's constructor.
def formfield_for_dbfield(self, db_field, **kwargs): """ Hook for specifying the form Field instance for a given database Field instance. If kwargs are given, they're passed to the form Field's constructor. """ request = kwargs.pop("request", None) # If the field specifies choices, we don't need to look for special # admin widgets - we just need to use a select widget of some kind. if db_field.choices: return self.formfield_for_choice_field(db_field, request, **kwargs) # ForeignKey or ManyToManyFields if isinstance(db_field, (models.ForeignKey, models.ManyToManyField)): # Combine the field kwargs with any options for formfield_overrides. # Make sure the passed in **kwargs override anything in # formfield_overrides because **kwargs is more specific, and should # always win. if db_field.__class__ in self.formfield_overrides: kwargs = dict(self.formfield_overrides[db_field.__class__], **kwargs) # Get the correct formfield. if isinstance(db_field, models.ForeignKey): formfield = self.formfield_for_foreignkey(db_field, request, **kwargs) elif isinstance(db_field, models.ManyToManyField): formfield = self.formfield_for_manytomany(db_field, request, **kwargs) # For non-raw_id fields, wrap the widget with a wrapper that adds # extra HTML -- the "add other" interface -- to the end of the # rendered output. formfield can be None if it came from a # OneToOneField with parent_link=True or a M2M intermediary. if formfield and db_field.name not in self.raw_id_fields: related_modeladmin = self.admin_site._registry.get( db_field.rel.to) can_add_related = bool(related_modeladmin and related_modeladmin.has_add_permission(request)) formfield.widget = widgets.RelatedFieldWidgetWrapper( formfield.widget, db_field.rel, self.admin_site, can_add_related=can_add_related) return formfield # If we've got overrides for the formfield defined, use 'em. **kwargs # passed to formfield_for_dbfield override the defaults. for klass in db_field.__class__.mro(): if klass in self.formfield_overrides: kwargs = dict(copy.deepcopy(self.formfield_overrides[klass]), **kwargs) return db_field.formfield(**kwargs) # For any other type of field, just call its formfield() method. return db_field.formfield(**kwargs)
def formfield_for_foreignkey(
self, db_field, request=None, **kwargs)
Get a form Field for a ForeignKey.
def formfield_for_foreignkey(self, db_field, request=None, **kwargs): """ Get a form Field for a ForeignKey. """ db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel, self.admin_site, using=db) elif db_field.name in self.radio_fields: kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 'class': get_ul_class(self.radio_fields[db_field.name]), }) kwargs['empty_label'] = _('None') if db_field.blank else None if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def formfield_for_manytomany(
self, db_field, request=None, **kwargs)
Get a form Field for a ManyToManyField.
def formfield_for_manytomany(self, db_field, request=None, **kwargs): """ Get a form Field for a ManyToManyField. """ # If it uses an intermediary model that isn't auto created, don't show # a field in admin. if not db_field.rel.through._meta.auto_created: return None db = kwargs.get('using') if db_field.name in self.raw_id_fields: kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel, self.admin_site, using=db) kwargs['help_text'] = '' elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)): kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical)) if not 'queryset' in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs)
def get_extra(
self, request, obj=None, **kwargs)
Hook for customizing the number of extra inline forms.
def get_extra(self, request, obj=None, **kwargs): """Hook for customizing the number of extra inline forms.""" return self.extra
def get_field_queryset(
self, db, db_field, request)
If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case).
def get_field_queryset(self, db, db_field, request): """ If the ModelAdmin specifies ordering, the queryset should respect that ordering. Otherwise don't specify the queryset, let the field decide (returns None in that case). """ related_admin = self.admin_site._registry.get(db_field.rel.to, None) if related_admin is not None: ordering = related_admin.get_ordering(request) if ordering is not None and ordering != (): return db_field.rel.to._default_manager.using(db).order_by(*ordering).complex_filter(db_field.rel.limit_choices_to) return None
def get_fieldsets(
self, request, obj=None)
def get_fieldsets(self, request, obj=None): if self.declared_fieldsets: return self.declared_fieldsets form = self.get_formset(request, obj, fields=None).form fields = list(form.base_fields) + list(self.get_readonly_fields(request, obj)) return [(None, {'fields': fields})]
def get_formset(
self, request, obj=None, **kwargs)
Returns a BaseInlineFormSet class for use in admin add/change views.
def get_formset(self, request, obj=None, **kwargs): """Returns a BaseInlineFormSet class for use in admin add/change views.""" if 'fields' in kwargs: fields = kwargs.pop('fields') else: fields = flatten_fieldsets(self.get_fieldsets(request, obj)) if self.exclude is None: exclude = [] else: exclude = list(self.exclude) exclude.extend(self.get_readonly_fields(request, obj)) if self.exclude is None and hasattr(self.form, '_meta') and self.form._meta.exclude: # Take the custom ModelForm's Meta.exclude into account only if the # InlineModelAdmin doesn't define its own. exclude.extend(self.form._meta.exclude) # If exclude is an empty list we use None, since that's the actual # default. exclude = exclude or None can_delete = self.can_delete and self.has_delete_permission(request, obj) defaults = { "form": self.form, "formset": self.formset, "fk_name": self.fk_name, "fields": fields, "exclude": exclude, "formfield_callback": partial(self.formfield_for_dbfield, request=request), "extra": self.get_extra(request, obj, **kwargs), "max_num": self.get_max_num(request, obj, **kwargs), "can_delete": can_delete, } defaults.update(kwargs) base_model_form = defaults['form'] class DeleteProtectedModelForm(base_model_form): def hand_clean_DELETE(self): """ We don't validate the 'DELETE' field itself because on templates it's not rendered using the field information, but just using a generic "deletion_field" of the InlineModelAdmin. """ if self.cleaned_data.get(DELETION_FIELD_NAME, False): using = router.db_for_write(self._meta.model) collector = NestedObjects(using=using) collector.collect([self.instance]) if collector.protected: objs = [] for p in collector.protected: objs.append( # Translators: Model verbose name and instance representation, suitable to be an item in a list _('%(class_name)s %(instance)s') % { 'class_name': p._meta.verbose_name, 'instance': p} ) params = {'class_name': self._meta.model._meta.verbose_name, 'instance': self.instance, 'related_objects': get_text_list(objs, _('and'))} msg = _("Deleting %(class_name)s %(instance)s would require " "deleting the following protected related objects: " "%(related_objects)s") raise ValidationError(msg, code='deleting_protected', params=params) def is_valid(self): result = super(DeleteProtectedModelForm, self).is_valid() self.hand_clean_DELETE() return result defaults['form'] = DeleteProtectedModelForm if defaults['fields'] is None and not modelform_defines_fields(defaults['form']): defaults['fields'] = forms.ALL_FIELDS return inlineformset_factory(self.parent_model, self.model, **defaults)
def get_max_num(
self, request, obj=None, **kwargs)
Hook for customizing the max number of extra inline forms.
def get_max_num(self, request, obj=None, **kwargs): """Hook for customizing the max number of extra inline forms.""" return self.max_num
def get_ordering(
self, request)
Hook for specifying field ordering.
def get_ordering(self, request): """ Hook for specifying field ordering. """ return self.ordering or () # otherwise we might try to *None, which is bad ;)
def get_prepopulated_fields(
self, request, obj=None)
Hook for specifying custom prepopulated fields.
def get_prepopulated_fields(self, request, obj=None): """ Hook for specifying custom prepopulated fields. """ return self.prepopulated_fields
def get_queryset(
self, request)
def get_queryset(self, request): queryset = super(InlineModelAdmin, self).get_queryset(request) if not self.has_change_permission(request): queryset = queryset.none() return queryset
def get_readonly_fields(
self, request, obj=None)
Hook for specifying custom readonly fields.
def get_readonly_fields(self, request, obj=None): """ Hook for specifying custom readonly fields. """ return self.readonly_fields
def has_add_permission(
self, request)
def has_add_permission(self, request): if self.opts.auto_created: # We're checking the rights to an auto-created intermediate model, # which doesn't have its own individual permissions. The user needs # to have the change permission for the related model in order to # be able to do anything with the intermediate model. return self.has_change_permission(request) return super(InlineModelAdmin, self).has_add_permission(request)
def has_change_permission(
self, request, obj=None)
def has_change_permission(self, request, obj=None): opts = self.opts if opts.auto_created: # The model was auto-created as intermediary for a # ManyToMany-relationship, find the target model for field in opts.fields: if field.rel and field.rel.to != self.parent_model: opts = field.rel.to._meta break codename = get_permission_codename('change', opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename))
def has_delete_permission(
self, request, obj=None)
def has_delete_permission(self, request, obj=None): if self.opts.auto_created: # We're checking the rights to an auto-created intermediate model, # which doesn't have its own individual permissions. The user needs # to have the change permission for the related model in order to # be able to do anything with the intermediate model. return self.has_change_permission(request, obj) return super(InlineModelAdmin, self).has_delete_permission(request, obj)
def lookup_allowed(
self, lookup, value)
def lookup_allowed(self, lookup, value): model = self.model # Check FKey lookups that are allowed, so that popups produced by # ForeignKeyRawIdWidget, on the basis of ForeignKey.limit_choices_to, # are allowed to work. for l in model._meta.related_fkey_lookups: for k, v in widgets.url_params_from_lookup_dict(l).items(): if k == lookup and v == value: return True parts = lookup.split(LOOKUP_SEP) # Last term in lookup is a query term (__exact, __startswith etc) # This term can be ignored. if len(parts) > 1 and parts[-1] in QUERY_TERMS: parts.pop() # Special case -- foo__id__exact and foo__id queries are implied # if foo has been specifically included in the lookup list; so # drop __id if it is the last part. However, first we need to find # the pk attribute name. rel_name = None for part in parts[:-1]: try: field, _, _, _ = model._meta.get_field_by_name(part) except FieldDoesNotExist: # Lookups on non-existent fields are ok, since they're ignored # later. return True if hasattr(field, 'rel'): if field.rel is None: # This property or relation doesn't exist, but it's allowed # since it's ignored in ChangeList.get_filters(). return True model = field.rel.to rel_name = field.rel.get_related_field().name elif isinstance(field, RelatedObject): model = field.model rel_name = model._meta.pk.name else: rel_name = None if rel_name and len(parts) > 1 and parts[-1] == rel_name: parts.pop() if len(parts) == 1: return True clean_lookup = LOOKUP_SEP.join(parts) return clean_lookup in self.list_filter or clean_lookup == self.date_hierarchy
def queryset(
*args, **kwargs)
def wrapped(*args, **kwargs): warnings.warn( "`%s.%s` is deprecated, use `%s` instead." % (self.class_name, self.old_method_name, self.new_method_name), self.deprecation_warning, 2) return f(*args, **kwargs)
def to_field_allowed(
self, request, to_field)
Returns True if the model associated with this admin should be allowed to be referenced by the specified field.
def to_field_allowed(self, request, to_field): """ Returns True if the model associated with this admin should be allowed to be referenced by the specified field. """ opts = self.model._meta try: field = opts.get_field(to_field) except FieldDoesNotExist: return False # Always allow referencing the primary key since it's already possible # to get this information from the change view URL. if field.primary_key: return True # Make sure at least one of the models registered for this site # references this field through a FK or a M2M relationship. registered_models = set() for model, admin in self.admin_site._registry.items(): registered_models.add(model) for inline in admin.inlines: registered_models.add(inline.model) for related_object in opts.get_all_related_objects(include_hidden=True): related_model = related_object.model if (any(issubclass(model, related_model) for model in registered_models) and related_object.field.rel.get_related_field() == field): return True return False
def validate(
cls, model)
@classmethod def validate(cls, model): validator = cls.validator_class() validator.validate(cls, model)