PK݆F jjmassadmin/__init__.py''' Copyright (c) 2010, Stanislaw Adaszewski All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Stanislaw Adaszewski nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Stanislaw Adaszewski BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ''' from django.contrib import admin from .massadmin import mass_change_selected admin.site.add_action(mass_change_selected) PKB4Gk{7{7massadmin/massadmin.py# Updates by David Burke # Orginal code is at # http://algoholic.eu/django-mass-change-admin-site-extension/ """ Copyright (c) 2010, Stanislaw Adaszewski All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Stanislaw Adaszewski nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Stanislaw Adaszewski BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """ import types import sys from django.contrib import admin from django.core.exceptions import PermissionDenied, ValidationError from django.core.urlresolvers import reverse from django.db import transaction, models try: from django.contrib.admin.utils import unquote except ImportError: from django.contrib.admin.util import unquote from django.contrib.admin import helpers from django.utils.translation import ugettext_lazy as _ try: from django.utils.encoding import force_text except: # 1.4 compat from django.utils.encoding import force_unicode as force_text from django.utils.safestring import mark_safe from django.contrib.admin.views.decorators import staff_member_required from django.http import Http404, HttpResponseRedirect from django.utils.html import escape from django.contrib.contenttypes.models import ContentType from django import template from django.shortcuts import render_to_response from django.forms.formsets import all_valid from django.contrib.admin.templatetags.admin_urls import add_preserved_filters def mass_change_selected(modeladmin, request, queryset): selected = queryset.values_list('pk', flat=True) opts = modeladmin.model._meta redirect_url = reverse( "massadmin_change_view", kwargs={"app_name": opts.app_label, "model_name": opts.model_name, "object_ids": ",".join(str(s) for s in selected)}) redirect_url = add_preserved_filters( {'preserved_filters': modeladmin.get_preserved_filters(request), 'opts': queryset.model._meta}, redirect_url) return HttpResponseRedirect(redirect_url) mass_change_selected.short_description = _('Mass Edit') def mass_change_view(request, app_name, model_name, object_ids): model = models.get_model(app_name, model_name) ma = MassAdmin(model, admin.site) return ma.mass_change_view(request, object_ids) mass_change_view = staff_member_required(mass_change_view) class MassAdmin(admin.ModelAdmin): def __init__(self, model, admin_site): try: self.admin_obj = admin_site._registry[model] except KeyError: raise Exception('Model not registered with the admin site.') for (varname, var) in self.get_overrided_properties().items(): if not varname.startswith('_') and not isinstance(var, types.FunctionType): self.__dict__[varname] = var super(MassAdmin, self).__init__(model, admin_site) def get_overrided_properties(self): """ Find all overrided properties, like form, raw_id_fields and so on. """ items = {} for cl in self.admin_obj.__class__.mro(): if cl is admin.ModelAdmin: break for k, v in cl.__dict__.items(): if not k in items: items[k] = v return items def response_change(self, request, obj): """ Determines the HttpResponse for the change_view stage. """ opts = obj._meta msg = _('Selected %(name)s were changed successfully.') % { 'name': force_text( opts.verbose_name_plural), 'obj': force_text(obj)} self.message_user(request, msg) redirect_url = reverse('admin:{}_{}_changelist'.format( self.model._meta.app_label, self.model._meta.model_name, )) preserved_filters = self.get_preserved_filters(request) redirect_url = add_preserved_filters( {'preserved_filters': preserved_filters, 'opts': opts}, redirect_url) return HttpResponseRedirect(redirect_url) def render_mass_change_form( self, request, context, add=False, change=False, form_url='', obj=None): opts = self.model._meta app_label = opts.app_label 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, 'has_absolute_url': hasattr(self.model, 'get_absolute_url'), 'form_url': mark_safe(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, }) context_instance = template.RequestContext( request, current_app=self.admin_site.name) return render_to_response( self.change_form_template or [ "admin/%s/%s/mass_change_form.html" % (app_label, opts.object_name.lower()), "admin/%s/mass_change_form.html" % app_label, "admin/mass_change_form.html"], context, context_instance=context_instance) def mass_change_view( self, request, comma_separated_object_ids, extra_context=None): """The 'mass change' admin view for this model.""" global new_object model = self.model opts = model._meta general_error = None # Allow model to hide some fields for mass admin exclude_fields = getattr(self.admin_obj, "massadmin_exclude", ()) queryset = getattr( self.admin_obj, "massadmin_queryset", self.get_queryset)(request) object_ids = comma_separated_object_ids.split(',') object_id = object_ids[0] try: obj = queryset.get(pk=unquote(object_id)) except model.DoesNotExist: obj = None # TODO It's necessary to check permission and existence for all object if not self.has_change_permission(request, obj): raise PermissionDenied if obj is None: raise Http404( _('%(name)s object with primary key %(key)r does not exist.') % { 'name': force_text( opts.verbose_name), 'key': escape(object_id)}) ModelForm = self.get_form(request, obj) formsets = [] errors, errors_list = None, None mass_changes_fields = request.POST.getlist("_mass_change") if request.method == 'POST': # commit only when all forms are valid try: with transaction.atomic(): objects_count = 0 changed_count = 0 objects = queryset.filter(pk__in=object_ids) for obj in objects: objects_count += 1 form = ModelForm( request.POST, request.FILES, instance=obj) exclude = [] for fieldname, field in list(form.fields.items()): if fieldname not in mass_changes_fields: exclude.append(fieldname) for exclude_fieldname in exclude: del form.fields[exclude_fieldname] if form.is_valid(): form_validated = True new_object = self.save_form( request, form, change=True) else: form_validated = False new_object = obj prefixes = {} for FormSet in self.get_formsets(request, new_object): prefix = FormSet.get_default_prefix() prefixes[prefix] = prefixes.get(prefix, 0) + 1 if prefixes[prefix] != 1: prefix = "%s-%s" % (prefix, prefixes[prefix]) if prefix in mass_changes_fields: formset = FormSet( request.POST, request.FILES, instance=new_object, prefix=prefix) formsets.append(formset) if all_valid(formsets) and form_validated: # self.admin_obj.save_model(request, new_object, form, change=True) self.save_model( request, new_object, form, change=True) form.save_m2m() for formset in formsets: self.save_formset( request, form, formset, change=True) change_message = self.construct_change_message( request, form, formsets) self.log_change( request, new_object, change_message) changed_count += 1 if changed_count == objects_count: return self.response_change(request, new_object) else: errors = form.errors errors_list = helpers.AdminErrorList(form, formsets) # Raise error for rollback transaction in atomic block raise ValidationError("Not all forms is correct") except: general_error = sys.exc_info()[1] form = ModelForm(instance=obj) form._errors = errors prefixes = {} for FormSet in self.get_formsets(request, obj): prefix = FormSet.get_default_prefix() prefixes[prefix] = prefixes.get(prefix, 0) + 1 if prefixes[prefix] != 1: prefix = "%s-%s" % (prefix, prefixes[prefix]) formset = FormSet(instance=obj, prefix=prefix) formsets.append(formset) adminForm = helpers.AdminForm( form, self.get_fieldsets( request, obj), self.prepopulated_fields, self.get_readonly_fields( request, obj), model_admin=self.admin_obj) media = self.media + adminForm.media # We don't want the user trying to mass change unique fields! unique_fields = [] for field_name in model._meta.get_all_field_names(): try: field = model._meta.get_field(field_name) if field.unique: unique_fields.append(field_name) except: pass # Buggy! Use at your own risk #inline_admin_formsets = [] # for inline, formset in zip(self.inline_instances, formsets): # fieldsets = list(inline.get_fieldsets(request, obj)) # inline_admin_formset = helpers.InlineAdminFormSet(inline, formset, fieldsets) # inline_admin_formsets.append(inline_admin_formset) # media = media + inline_admin_formset.media context = { 'title': _('Change %s') % force_text(opts.verbose_name), 'adminform': adminForm, 'object_id': object_id, 'original': obj, 'unique_fields': unique_fields, 'exclude_fields': exclude_fields, 'is_popup': '_popup' in request.REQUEST, 'media': mark_safe(media), #'inline_admin_formsets': inline_admin_formsets, 'errors': errors_list, 'general_error': general_error, 'app_label': opts.app_label, 'object_ids': comma_separated_object_ids, 'mass_changes_fields': mass_changes_fields, } context.update(extra_context or {}) return self.render_mass_change_form( request, context, change=True, obj=obj)PKB4G7massadmin/urls.pyfrom django.conf.urls import url, patterns urlpatterns = patterns('', url(r'(?P[^/]+)/(?P[^/]+)-masschange/(?P[\w,\.]+)/$', 'massadmin.massadmin.mass_change_view', name='massadmin_change_view'), ) PKFY84massadmin/templates/admin/save_only_submit_line.html{% load i18n %}
PKF8. . /massadmin/templates/admin/mass_change_form.html{% extends "admin/change_form.html" %} {% load i18n admin_modify %} {% load truncchar %} {% block extrahead %}{{ block.super }} {% endblock %} {% block breadcrumbs %}{% if not is_popup %} {% endif %}{% endblock %} {% block content %}
{% block object-tools %} {% endblock %}
{% csrf_token %}{% block form_top %}{% endblock %}
{% if is_popup %}{% endif %} {% if save_on_top %}{% include "admin/save_only_submit_line.html" %}{% endif %} {% if errors %}

{% blocktrans count errors|length as counter %}Please correct the error below.{% plural %}Please correct the errors below.{% endblocktrans %}

    {% for error in adminform.form.non_field_errors %}
  • {{ error }}
  • {% endfor %}
{% endif %} {% for fieldset in adminform %} {% include "admin/includes/mass_fieldset.html" %} {% endfor %} {% block after_field_sets %}{% endblock %} {% block after_related_objects %}{% endblock %} {% include "admin/save_only_submit_line.html" %} {% if adminform and add %} {% endif %} {# JavaScript for prepopulated fields #} {% prepopulated_fields_js %}
{% endblock %} PKB4GAA5massadmin/templates/admin/includes/mass_fieldset.html{% load i18n %}
{% if fieldset.name %}

{{ fieldset.name }} Mass Edit

{% endif %} {% if fieldset.description %}

{{ fieldset.description|safe }}

{% endif %} {% if general_error %}
{{ general_error}}
{% endif %} {% for line in fieldset %} {% if line.errors %} {% endif %} {% for field in line %} {% if field.field.name in adminform.readonly_fields %} {% else %}{% if field.field.name in unique_fields %} {% elif not field.field.name in exclude_fields %} {% endif %}{% endif %} {% endfor %} {% endfor %}
{% trans "Mass Update?" %} {% trans "Field" %}
{{ line.errors }}
{{ field.field.name }} {% trans "is read only." %} {{ field.field.name }} {% trans "is unique." %} {% if field.is_checkbox %} {{ field.field }}{{ field.label_tag }} {% else %}
{{ field.label_tag }}
{{ field.field }}
{% endif %} {% if field.field.field.help_text %}

{{ field.field.field.help_text|safe }}

{% endif %}
PKF(c)massadmin/locale/cs/LC_MESSAGES/django.po# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-07-08 10:10+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" #: massadmin.py:60 msgid "Mass Edit" msgstr "Hromadná úprava" #: massadmin.py:87 #, python-format msgid "Selected %(name)s were changed successfully." msgstr "Vybrané %(name)s byly úspěšně změněny." #: massadmin.py:135 #, python-format msgid "%(name)s object with primary key %(key)r does not exist." msgstr "%(name)s objekt s primárním klíčem %(key)r neexistuje." #: massadmin.py:229 #, python-format msgid "Change %s" msgstr "Změnit %s" #: templates/admin/includes/mass_fieldset.html:14 msgid "Mass Update?" msgstr "Upravit?" #: templates/admin/includes/mass_fieldset.html:17 msgid "Field" msgstr "Položka" #: templates/admin/includes/mass_fieldset.html:36 msgid "is read only." msgstr "je pouze pro čtení." #: templates/admin/includes/mass_fieldset.html:43 msgid "is unique." msgstr "je unikátní." PKFo)massadmin/locale/cs/LC_MESSAGES/django.mo d 8 $ * 4,A n |: IT]o-x %(name)s object with primary key %(key)r does not exist.Change %sFieldMass EditMass Update?Selected %(name)s were changed successfully.is read only.is unique.Project-Id-Version: PACKAGE VERSION Report-Msgid-Bugs-To: POT-Creation-Date: 2013-07-08 10:10+0200 PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE Last-Translator: FULL NAME Language-Team: LANGUAGE Language: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2; %(name)s objekt s primárním klíčem %(key)r neexistuje.Změnit %sPoložkaHromadná úpravaUpravit?Vybrané %(name)s byly úspěšně změněny.je pouze pro čtení.je unikátní.PKF14)massadmin/locale/pt/LC_MESSAGES/django.po# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2014-09-18 16:40-0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" #: massadmin.py:63 msgid "Mass Edit" msgstr "Editar em Lote" #: massadmin.py:94 #, python-format msgid "Selected %(name)s were changed successfully." msgstr "Os objetos a seguir foram modificados com sucesso. %(name)s." #: massadmin.py:146 #, python-format msgid "%(name)s object with primary key %(key)r does not exist." msgstr "O objeto %(name)s com chave primária %(key)r não existe." #: massadmin.py:240 #, python-format msgid "Change %s" msgstr "Modificar %s" #: templates/admin/mass_change_form.html:25 msgid "Home" msgstr "Home" #: templates/admin/mass_change_form.html:28 msgid "Add" msgstr "Adicionar" #: templates/admin/mass_change_form.html:42 msgid "Please correct the error below." msgid_plural "Please correct the errors below." msgstr[0] "Por favor corrija o erro a seguir." msgstr[1] "Por favor corrija os erros a seguir." #: templates/admin/mass_change_form.html:55 msgid "Mass Change" msgstr "Editar em Lote" #: templates/admin/save_only_submit_line.html:3 msgid "Save" msgstr "Salvar" #: templates/admin/includes/mass_fieldset.html:14 msgid "Mass Update?" msgstr "Editar em Lote?" #: templates/admin/includes/mass_fieldset.html:17 msgid "Field" msgstr "Campo" #: templates/admin/includes/mass_fieldset.html:36 msgid "is read only." msgstr "é do tipo somente-leitura." #: templates/admin/includes/mass_fieldset.html:43 msgid "is unique." msgstr "é do tipo unique." PKFu)massadmin/locale/pt/LC_MESSAGES/django.moH8I    @, 1 ?jJ:   !0G@<   %(name)s object with primary key %(key)r does not exist.AddChange %sFieldHomeMass ChangeMass EditMass Update?Please correct the error below.Please correct the errors below.SaveSelected %(name)s were changed successfully.is read only.is unique.Project-Id-Version: PACKAGE VERSION Report-Msgid-Bugs-To: POT-Creation-Date: 2014-09-18 16:40-0300 PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE Last-Translator: FULL NAME Language-Team: LANGUAGE Language: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=2; plural=(n != 1) O objeto %(name)s com chave primária %(key)r não existe.AdicionarModificar %sCampoHomeEditar em LoteEditar em LoteEditar em Lote?Por favor corrija o erro a seguir.Por favor corrija os erros a seguir.SalvarOs objetos a seguir foram modificados com sucesso. %(name)s.é do tipo somente-leitura.é do tipo unique.PKG׆*)massadmin/locale/pl/LC_MESSAGES/django.po# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2015-07-24 16:56+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " "|| n%100>=20) ? 1 : 2);\n" #: massadmin.py:72 msgid "Mass Edit" msgstr "Edycja masowa" #: massadmin.py:106 #, python-format msgid "Selected %(name)s were changed successfully." msgstr "Wybrane %(name)s zostały zmienione poprawnie." #: massadmin.py:190 #, python-format msgid "%(name)s object with primary key %(key)r does not exist." msgstr "Obiekt %(name)s z kluczem głównym %(key)r nie istnieje." #: massadmin.py:315 #, python-format msgid "Change %s" msgstr "Zmień %s" #: templates/admin/includes/mass_fieldset.html:14 msgid "Mass Update?" msgstr "Edycja Masowa?" #: templates/admin/includes/mass_fieldset.html:17 msgid "Field" msgstr "Pole" #: templates/admin/includes/mass_fieldset.html:36 msgid "is read only." msgstr "jest tylko do odczytu." #: templates/admin/includes/mass_fieldset.html:43 msgid "is unique." msgstr "jest unikalne." #: templates/admin/mass_change_form.html:25 msgid "Home" msgstr "Początek" #: templates/admin/mass_change_form.html:28 msgid "Add" msgstr "Dodaj" #: templates/admin/mass_change_form.html:43 msgid "Please correct the error below." msgid_plural "Please correct the errors below." msgstr[0] "Popraw błąd poniżej." msgstr[1] "Popraw błędy poniżej." #: templates/admin/mass_change_form.html:56 msgid "Mass Change" msgstr "Zmiana masowa" #: templates/admin/save_only_submit_line.html:3 msgid "Save" msgstr "Zapisz" PKGpBk)massadmin/locale/pl/LC_MESSAGES/django.moH8I    @, 1 ?J9* 0: ? I We0t.   %(name)s object with primary key %(key)r does not exist.AddChange %sFieldHomeMass ChangeMass EditMass Update?Please correct the error below.Please correct the errors below.SaveSelected %(name)s were changed successfully.is read only.is unique.Project-Id-Version: PACKAGE VERSION Report-Msgid-Bugs-To: POT-Creation-Date: 2015-07-24 16:56+0000 PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE Last-Translator: FULL NAME Language-Team: LANGUAGE Language: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); Obiekt %(name)s z kluczem głównym %(key)r nie istnieje.DodajZmień %sPolePoczątekZmiana masowaEdycja masowaEdycja Masowa?Popraw błąd poniżej.Popraw błędy poniżej.ZapiszWybrane %(name)s zostały zmienione poprawnie.jest tylko do odczytu.jest unikalne.PKF}\)massadmin/locale/es/LC_MESSAGES/django.po# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-11-05 12:35-0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" #: massadmin.py:60 msgid "Mass Edit" msgstr "Editar en Lote" #: massadmin.py:87 #, python-format msgid "Selected %(name)s were changed successfully." msgstr "Se han modificado correctamente los objetos %(name)s." #: massadmin.py:138 #, python-format msgid "%(name)s object with primary key %(key)r does not exist." msgstr "El objeto %(name)s con clave primaria %(key)r no existe." #: massadmin.py:232 #, python-format msgid "Change %s" msgstr "Modificar %s" #: templates/admin/mass_change_form.html:33 msgid "Home" msgstr "Inicio" #: templates/admin/mass_change_form.html:36 msgid "Add" msgstr "Agregar" #: templates/admin/mass_change_form.html:54 msgid "Please correct the error below." msgid_plural "Please correct the errors below." msgstr[0] "Por favor corrija el siguiente error." msgstr[1] "Por favor corrija los siguientes errores." #: templates/admin/mass_change_form.html:67 msgid "Mass Change" msgstr "Editar en Lote" #: templates/admin/save_only_submit_line.html:3 msgid "Save" msgstr "Guardar" #: templates/admin/includes/mass_fieldset.html:14 msgid "Mass Update?" msgstr "¿Editar en Lote?" #: templates/admin/includes/mass_fieldset.html:17 msgid "Field" msgstr "Campo" #: templates/admin/includes/mass_fieldset.html:36 msgid "is read only." msgstr "es de solo lectura." #: templates/admin/includes/mass_fieldset.html:43 msgid "is unique." msgstr "es único." PKFc)massadmin/locale/es/LC_MESSAGES/django.moH8I    @, 1 ?jJ8  .O@5    %(name)s object with primary key %(key)r does not exist.AddChange %sFieldHomeMass ChangeMass EditMass Update?Please correct the error below.Please correct the errors below.SaveSelected %(name)s were changed successfully.is read only.is unique.Project-Id-Version: PACKAGE VERSION Report-Msgid-Bugs-To: POT-Creation-Date: 2013-11-05 12:35-0300 PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE Last-Translator: FULL NAME Language-Team: LANGUAGE Language: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=2; plural=(n != 1) El objeto %(name)s con clave primaria %(key)r no existe.AgregarModificar %sCampoInicioEditar en LoteEditar en Lote¿Editar en Lote?Por favor corrija el siguiente error.Por favor corrija los siguientes errores.GuardarSe han modificado correctamente los objetos %(name)s.es de solo lectura.es único.PK݆F5#massadmin/templatetags/truncchar.py''' Copyright (c) 2010, Stanislaw Adaszewski All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Stanislaw Adaszewski nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Stanislaw Adaszewski BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ''' from django import template register = template.Library() @register.filter('truncchar') # truncate after a certain number of characters def truncchar(value, arg): if len(value) < arg: return value else: return value[:arg] + '...' PK݆F"massadmin/templatetags/__init__.pyPKFDWd #massadmin/templatetags/__init__.pyc cwtUc@sdS(N((((sI/usr/local/lib/python2.7/dist-packages/massadmin/templatetags/__init__.pytsPKF&$massadmin/templatetags/truncchar.pyc cwtUc@s>dZddlmZejZejddZdS(s Copyright (c) 2010, Stanislaw Adaszewski All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Stanislaw Adaszewski nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Stanislaw Adaszewski BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. i(ttemplatet trunccharcCs&t||kr|S|| dSdS(Ns...(tlen(tvaluetarg((sJ/usr/local/lib/python2.7/dist-packages/massadmin/templatetags/truncchar.pyR sN(t__doc__tdjangoRtLibrarytregistertfilterR(((sJ/usr/local/lib/python2.7/dist-packages/massadmin/templatetags/truncchar.pyts PK+4G0(L;massadmin/templatetags/__pycache__/truncchar.cpython-34.pyc cwtU@sAdZddlmZejZejdddZdS)a Copyright (c) 2010, Stanislaw Adaszewski All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Stanislaw Adaszewski nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Stanislaw Adaszewski BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. )template trunccharcCs,t||kr|S|d|dSdS)Nz...)len)valueargrJ/usr/local/lib/python3.4/site-packages/massadmin/templatetags/truncchar.pyr sN)__doc__djangorLibraryregisterfilterrrrrrs PK4GKZ:massadmin/templatetags/__pycache__/__init__.cpython-34.pyc cwtU@sdS)NrrrI/usr/local/lib/python3.4/site-packages/massadmin/templatetags/__init__.pysPKB4Gcfftests/tests.pyfrom six.moves.urllib import parse from django.contrib.auth.models import User from django.contrib import admin from django.core.urlresolvers import reverse from django.test import TestCase from massadmin.massadmin import MassAdmin from .admin import CustomAdminForm, BaseAdmin, InheritedAdmin from .models import CustomAdminModel, InheritedAdminModel def get_massadmin_url(objects): if not hasattr(objects, "__iter__"): objects = [objects] opts = objects[0]._meta return reverse("massadmin_change_view", kwargs={"app_name": opts.app_label, "model_name": opts.model_name, "object_ids": ",".join(str(o.pk) for o in objects)}) def get_changelist_url(model): opts = model._meta return reverse("admin:{}_{}_changelist".format( opts.app_label, opts.model_name)) class AdminViewTest(TestCase): def setUp(self): self.user = User.objects.create_superuser( 'temporary', 'temporary@gmail.com', 'temporary') self.client.login(username='temporary', password='temporary') def test_massadmin_form_generation(self): response = self.client.get(get_massadmin_url(self.user)) self.assertContains(response, 'First name') def test_update(self): models = [CustomAdminModel.objects.create(name="model {}".format(i)) for i in range(0, 3)] response = self.client.post(get_massadmin_url(models), {"_mass_change": "name", "name": "new name"}) self.assertRedirects(response, get_changelist_url(CustomAdminModel)) new_names = CustomAdminModel.objects.order_by("pk").values_list("name", flat=True) # all models have changed self.assertEqual(list(new_names), ["new name"] * 3) def test_preserve_filters(self): """ Preserve filters which was choosed in lookup form """ model = CustomAdminModel.objects.create(name="aaaa") # filter model list by some parameter query = "name__startswith=a" changelist_url = get_changelist_url(CustomAdminModel) + "?" + query # choose mass change action response = self.client.post(changelist_url, {"action": "mass_change_selected", "_selected_action": model.pk}) self.assertEqual(response.status_code, 302) mass_change_url = response.get("Location") # filters add to redirect url self.assertEqual(parse.parse_qs(parse.urlparse(mass_change_url).query), {"_changelist_filters": [query]}) # save mass change form with preserved filters response = self.client.post(mass_change_url, {"_mass_change": "name", "name": "new name"}) # we are redirected to changelist with filters self.assertRedirects(response, changelist_url) def test_invalid_form(self): """ Save nothing if some forms are invalid """ models = [CustomAdminModel.objects.create(name="model {}".format(i)) for i in range(0, 3)] response = self.client.post(get_massadmin_url(models), {"_mass_change": "name", "name": "invalid {}".format(models[-1].pk)}) self.assertEqual(response.status_code, 200) self.assertContains(response, 'errornote') new_names = CustomAdminModel.objects.order_by("pk").values_list("name", flat=True) # all models stay the same self.assertEqual(list(new_names), [m.name for m in models]) class CustomizationTestCase(TestCase): """ MassAdmin has all customized options from related ModelAdmin """ def test_custom_from(self): """ If form is overrided in ModelAdmin, it should be overrided in MassAdmin too. """ ma = MassAdmin(CustomAdminModel, admin.site) self.assertEqual(ma.form, CustomAdminForm) def test_inheritance(self): """ If modeladmin is inherited from another customized modeladmin, MassAdmin get overriding from all of them. """ ma = MassAdmin(InheritedAdminModel, admin.site) self.assertEqual(ma.raw_id_fields, InheritedAdmin.raw_id_fields) self.assertEqual(ma.readonly_fields, BaseAdmin.readonly_fields)PKB4G"stests/__init__.py# coding: utf-8PKB4G ~tests/models.py# coding: utf-8 from django.db import models class CustomAdminModel(models.Model): name = models.CharField(max_length=32) class InheritedAdminModel(models.Model): name = models.CharField(max_length=32) fk_field = models.ForeignKey(CustomAdminModel, null=True, blank=True)PKB4Gq鋢tests/admin.py# coding: utf-8 from django.contrib import admin from django import forms from .models import CustomAdminModel, InheritedAdminModel class CustomAdminForm(forms.ModelForm): def clean_name(self): """ Fake cleaning for tests """ name = self.cleaned_data.get("name") if (self.instance.pk and name == "invalid {}".format(self.instance.pk)): raise forms.ValidationError("Invalid model name") return name class Meta: fields = ("name", ) model = CustomAdminModel class CustomAdmin(admin.ModelAdmin): model = CustomAdminModel form = CustomAdminForm admin.site.register(CustomAdminModel, CustomAdmin) class BaseAdmin(admin.ModelAdmin): readonly_fields = ("name", ) class InheritedAdmin(BaseAdmin): model = InheritedAdminModel raw_id_fields = ("fk_field", ) admin.site.register(InheritedAdminModel, InheritedAdmin)PKB4Gh-mmtests/settings.py# coding: utf-8 from uuid import uuid4 SECRET_KEY = uuid4().hex DEBUG = True TEMPLATE_DEBUG = True INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'massadmin', 'tests' ) MIDDLEWARE_CLASSES = ( 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ) DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': ':memory:', } } ROOT_URLCONF = 'tests.urls' STATIC_URL = '/static/'PKB4GIW tests/urls.pyfrom django.conf.urls import patterns, include, url from django.contrib import admin admin.autodiscover() urlpatterns = patterns('', url(r'^admin/', include(admin.site.urls)), (r'^admin/', include("massadmin.urls")), ) PKF'Wmass_demo/wsgi.py""" WSGI config for mass_demo project. It exposes the WSGI callable as a module-level variable named ``application``. For more information on this file, see https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/ """ import os os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mass_demo.settings") from django.core.wsgi import get_wsgi_application application = get_wsgi_application() PKFmass_demo/__init__.pyPKB4G> mass_demo/settings.py""" Django settings for mass_demo project. For more information on this file, see https://docs.djangoproject.com/en/1.7/topics/settings/ For the full list of settings and their values, see https://docs.djangoproject.com/en/1.7/ref/settings/ """ # Build paths inside the project like this: os.path.join(BASE_DIR, ...) import os BASE_DIR = os.path.dirname(os.path.dirname(__file__)) # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = '0)4mwt=!3*dvff#a($-ii3(hf461c%upq@ha21qj7o#m=_*xms' # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True TEMPLATE_DEBUG = True ALLOWED_HOSTS = [] # Application definition INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'massadmin' ) MIDDLEWARE_CLASSES = ( 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ) ROOT_URLCONF = 'mass_demo.urls' WSGI_APPLICATION = 'mass_demo.wsgi.application' # Database # https://docs.djangoproject.com/en/1.7/ref/settings/#databases DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } } # Internationalization # https://docs.djangoproject.com/en/1.7/topics/i18n/ LANGUAGE_CODE = 'en-us' TIME_ZONE = 'UTC' USE_I18N = True USE_L10N = True USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/1.7/howto/static-files/ STATIC_URL = '/static/' PK:gFIWmass_demo/urls.pyfrom django.conf.urls import patterns, include, url from django.contrib import admin admin.autodiscover() urlpatterns = patterns('', url(r'^admin/', include(admin.site.urls)), (r'^admin/', include("massadmin.urls")), ) PK(gFsF&&massadmin2/tests.pyfrom django.contrib.auth.models import User from django.test import TestCase class SimpleTest(TestCase): def setUp(self): user = User.objects.create_user( 'temporary', 'temporary@gmail.com', 'temporary') user.is_staff = True user.is_superuser = True user.save() self.client.login(username='temporary', password='temporary') def test_massadmin_form_generation(self): response = self.client.get('/admin/auth/user-masschange/1/') self.assertContains(response, 'First name') PK:gF jjmassadmin2/__init__.py''' Copyright (c) 2010, Stanislaw Adaszewski All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Stanislaw Adaszewski nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Stanislaw Adaszewski BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ''' from django.contrib import admin from .massadmin import mass_change_selected admin.site.add_action(mass_change_selected) PKF#S55massadmin2/massadmin.py# Updates by David Burke # Orginal code is at # http://algoholic.eu/django-mass-change-admin-site-extension/ """ Copyright (c) 2010, Stanislaw Adaszewski All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Stanislaw Adaszewski nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Stanislaw Adaszewski BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """ from django.contrib import admin from django.conf.urls import patterns from django.core.exceptions import PermissionDenied from django.core.urlresolvers import reverse from django.db import transaction, models from django.contrib.admin.util import unquote from django.contrib.admin import helpers from django.utils.translation import ugettext_lazy as _ try: from django.utils.encoding import force_text except: # 1.4 compat from django.utils.encoding import force_unicode as force_text from django.utils.safestring import mark_safe from django.contrib.admin.views.decorators import staff_member_required from django.http import Http404, HttpResponseRedirect from django.utils.html import escape from django.contrib.contenttypes.models import ContentType from django import template from django.shortcuts import render_to_response from django.forms.formsets import all_valid import sys urls = patterns( '', (r'(?P[^/])/(?P[^/]+)-masschange/(?P[0-9,]+)/$', 'massadmin.massadmin.mass_change_view'), ) # noinspection PyUnusedLocal def mass_change_selected(modeladmin, request, queryset): selected_int = queryset.values_list('pk', flat=True) selected = [] for s in selected_int: selected.append(str(s)) return HttpResponseRedirect( '../%s-masschange/%s' % (modeladmin.model._meta.model_name, ','.join(selected))) mass_change_selected.short_description = _('Mass Edit') def mass_change_view(request, app_name, model_name, object_ids): model = models.get_model(app_name, model_name) ma = MassAdmin(model, admin.site) return ma.mass_change_view(request, object_ids) # noinspection PyRedeclaration mass_change_view = staff_member_required(mass_change_view) class MassAdmin(admin.ModelAdmin): def __init__(self, model, admin_site): try: self.admin_obj = admin_site._registry[model] except KeyError: raise Exception('Model not registered with the admin site.') try: admin_obj_items = self.admin_obj.__class__.__dict__.iteritems() except AttributeError: # Python 2.x compat admin_obj_items = self.admin_obj.__class__.__dict__.items() for (varname, var) in admin_obj_items: if not (varname.startswith('_') or callable(var)): self.__dict__[varname] = var super(MassAdmin, self).__init__(model, admin_site) def response_change(self, request, obj): """ Determines the HttpResponse for the change_view stage. """ opts = obj._meta msg = _('Selected %(name)s were changed successfully.') % { 'name': force_text( opts.verbose_name_plural), 'obj': force_text(obj)} self.message_user(request, msg) if request.POST.has_key('_changelist_filters'): url = request.POST['_changelist_filters'] else: url = reverse('admin:{}_{}_changelist'.format( self.model._meta.app_label, self.model._meta.model_name, )) return HttpResponseRedirect(url) def render_mass_change_form( self, request, context, add=False, change=False, form_url='', obj=None): opts = self.model._meta app_label = opts.app_label 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, 'has_absolute_url': hasattr(self.model, 'get_absolute_url'), 'form_url': mark_safe(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, }) context_instance = template.RequestContext( request, current_app=self.admin_site.name) return render_to_response( self.change_form_template or [ "admin/%s/%s/mass_change_form.html" % (app_label, opts.object_name.lower()), "admin/%s/mass_change_form.html" % app_label, "admin/mass_change_form.html"], context, context_instance=context_instance) def mass_change_view( self, request, comma_separated_object_ids, extra_context=None): """The 'mass change' admin view for this model.""" global new_object model = self.model opts = model._meta general_error = None # Allow model to hide some fields for mass admin exclude_fields = getattr(self.admin_obj, "massadmin_exclude", ()) queryset = getattr( self.admin_obj, "massadmin_queryset", self.get_queryset)(request) object_ids = comma_separated_object_ids.split(',') object_id = object_ids[0] try: obj = queryset.get(pk=unquote(object_id)) except model.DoesNotExist: obj = None if not self.has_change_permission(request, obj): raise PermissionDenied if obj is None: raise Http404( _('%(name)s object with primary key %(key)r does not exist.') % { 'name': force_text( opts.verbose_name), 'key': escape(object_id)}) if request.method == 'POST' and "_saveasnew" in request.POST: return self.add_view(request, form_url='../add/') ModelForm = self.get_form(request, obj) formsets = [] if request.method == 'POST': # commit only when all forms are valid with transaction.atomic(): try: objects_count = 0 changed_count = 0 objects = queryset.filter(pk__in=object_ids) for obj in objects: objects_count += 1 form = ModelForm( request.POST, request.FILES, instance=obj) exclude = [] for fieldname, field in form.fields.items(): mass_change_checkbox = '_mass_change_%s' % fieldname if not ( request.POST.get(mass_change_checkbox) == 'on'): exclude.append(fieldname) for exclude_fieldname in exclude: del form.fields[exclude_fieldname] if form.is_valid(): form_validated = True new_object = self.save_form( request, form, change=True) else: form_validated = False new_object = obj prefixes = {} for FormSet in self.get_formsets(request, new_object): prefix = FormSet.get_default_prefix() prefixes[prefix] = prefixes.get(prefix, 0) + 1 if prefixes[prefix] != 1: prefix = "%s-%s" % (prefix, prefixes[prefix]) mass_change_checkbox = '_mass_change_%s' % prefix if request.POST.get(mass_change_checkbox) == 'on': formset = FormSet( request.POST, request.FILES, instance=new_object, prefix=prefix) formsets.append(formset) if all_valid(formsets) and form_validated: #self.admin_obj.save_model(request, new_object, form, change=True) self.save_model( request, new_object, form, change=True) form.save_m2m() for formset in formsets: self.save_formset( request, form, formset, change=True) change_message = self.construct_change_message( request, form, formsets) self.log_change( request, new_object, change_message) changed_count += 1 if False and changed_count != objects_count: raise Exception( 'Some of the selected objects could\'t be changed.') return self.response_change(request, new_object) finally: if sys.version < '3': general_error = unicode(sys.exc_info()[1]) else: general_error = sys.exc_info()[1] form = ModelForm(instance=obj) prefixes = {} for FormSet in self.get_formsets(request, obj): prefix = FormSet.get_default_prefix() prefixes[prefix] = prefixes.get(prefix, 0) + 1 if prefixes[prefix] != 1: prefix = "%s-%s" % (prefix, prefixes[prefix]) formset = FormSet(instance=obj, prefix=prefix) formsets.append(formset) adminForm = helpers.AdminForm( form, self.get_fieldsets( request, obj), self.prepopulated_fields, self.get_readonly_fields( request, obj), model_admin=self.admin_obj) media = self.media + adminForm.media # We don't want the user trying to mass change unique fields! unique_fields = [] for field_name in model._meta.get_all_field_names(): try: field = model._meta.get_field(field_name) if field.unique: unique_fields.append(field_name) except: pass # Buggy! Use at your own risk #inline_admin_formsets = [] # for inline, formset in zip(self.inline_instances, formsets): # fieldsets = list(inline.get_fieldsets(request, obj)) # inline_admin_formset = helpers.InlineAdminFormSet(inline, formset, fieldsets) # inline_admin_formsets.append(inline_admin_formset) # media = media + inline_admin_formset.media context = { 'title': _('Change %s') % force_text(opts.verbose_name), 'adminform': adminForm, 'object_id': object_id, 'original': obj, 'unique_fields': unique_fields, 'exclude_fields': exclude_fields, 'is_popup': '_popup' in request.REQUEST, 'media': mark_safe(media), #'inline_admin_formsets': inline_admin_formsets, 'errors': helpers.AdminErrorList(form, formsets), 'general_error': general_error, 'app_label': opts.app_label, 'object_ids': comma_separated_object_ids, } context.update(extra_context or {}) return self.render_mass_change_form( request, context, change=True, obj=obj) PK4gF;massadmin2/urls.pyfrom django.conf.urls import url, patterns urlpatterns = patterns('', url(r'(?P[^/]+)/(?P[^/]+)-masschange/(?P[\w,\.]+)/$', 'massadmin.massadmin.mass_change_view'), ) PK:gF5$massadmin2/templatetags/truncchar.py''' Copyright (c) 2010, Stanislaw Adaszewski All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Stanislaw Adaszewski nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Stanislaw Adaszewski BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ''' from django import template register = template.Library() @register.filter('truncchar') # truncate after a certain number of characters def truncchar(value, arg): if len(value) < arg: return value else: return value[:arg] + '...' PK:gF#massadmin2/templatetags/__init__.pyPKYG^- .django_mass_edit-2.5.dist-info/DESCRIPTION.rstUNKNOWN PKYG%j~,django_mass_edit-2.5.dist-info/metadata.json{"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: Django", "Programming Language :: Python", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.4", "Intended Audience :: Developers", "Intended Audience :: System Administrators", "License :: OSI Approved :: BSD License"], "extensions": {"python.details": {"contacts": [{"email": "david@burkesoftware.com", "name": "David Burke", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "https://github.com/burke-software/django-mass-edit"}}}, "extras": [], "generator": "bdist_wheel (0.26.0)", "keywords": ["django", "admin"], "license": "BSD", "metadata_version": "2.0", "name": "django-mass-edit", "run_requires": [{"requires": ["django"]}], "summary": "Make bulk changes in the Django admin interface", "version": "2.5"}PKYGY%%,django_mass_edit-2.5.dist-info/top_level.txtmass_demo massadmin massadmin2 tests PKYG}\\$django_mass_edit-2.5.dist-info/WHEELWheel-Version: 1.0 Generator: bdist_wheel (0.26.0) Root-Is-Purelib: true Tag: py3-none-any PKYG3_'django_mass_edit-2.5.dist-info/METADATAMetadata-Version: 2.0 Name: django-mass-edit Version: 2.5 Summary: Make bulk changes in the Django admin interface Home-page: https://github.com/burke-software/django-mass-edit Author: David Burke Author-email: david@burkesoftware.com License: BSD Keywords: django admin Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Web Environment Classifier: Framework :: Django Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.4 Classifier: Intended Audience :: Developers Classifier: Intended Audience :: System Administrators Classifier: License :: OSI Approved :: BSD License Requires-Dist: django UNKNOWN PKYGm%%django_mass_edit-2.5.dist-info/RECORDdjango_mass_edit-2.5.dist-info/DESCRIPTION.rst,sha256=OCTuuN6LcWulhHS3d5rfjdsQtW22n7HENFRh6jC6ego,10 django_mass_edit-2.5.dist-info/METADATA,sha256=RK2sb0SOg1lAp3F3fRcw9Ql-xkRvJoPrkkGsMwXAuV8,746 django_mass_edit-2.5.dist-info/RECORD,, django_mass_edit-2.5.dist-info/WHEEL,sha256=zX7PHtH_7K-lEzyK75et0UBa3Bj8egCBMXe1M4gc6SU,92 django_mass_edit-2.5.dist-info/metadata.json,sha256=m9s9eONXJfGnvs2fxbd1Y-HpLyg2NSIXj2X6s8-SuiE,904 django_mass_edit-2.5.dist-info/top_level.txt,sha256=XEOEmwR0RuwAE1m_CDNrHDHrEVGC_n5t6LkxGwXzOuE,37 mass_demo/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 mass_demo/settings.py,sha256=gZ5i1kJUf0Sho9SDlZ5Z8xQgR8OJfJb6QOgwI5lMBAI,1997 mass_demo/urls.py,sha256=BisfjcPJwZluZEJ4Luc86YCxXh13goN6PgzxSzP7F54,228 mass_demo/wsgi.py,sha256=2HT-9lpXNsmH4qvTvzo_Hww-B1pOYYa3BM109RF-Ddk,393 massadmin/__init__.py,sha256=U8Ddbo_6w2zTUChd4Hw3LH4iIMKvxCwJHSrSWI-ES8E,1642 massadmin/massadmin.py,sha256=xrrtSYil1FKB-uPxetJLd7eNA_UH5ksGrbZ7fVRNX5o,14203 massadmin/urls.py,sha256=0Av_wJTY9oUUXCrJwQFYIppCscStuJZkLHujZD8QBpY,247 massadmin/locale/cs/LC_MESSAGES/django.mo,sha256=qS1dbCzGhBWb7N2v9IHD8wSbp1eWw-DZvw-fsM6VBQg,971 massadmin/locale/cs/LC_MESSAGES/django.po,sha256=24Q6zyxcwJ3Rrbg5UCEzGFVA9__969TlzhdhPfukHWE,1482 massadmin/locale/es/LC_MESSAGES/django.mo,sha256=9og14mejTNeXy8F7FRLFVQIPIUis-M2FiMsJTd8zHXU,1261 massadmin/locale/es/LC_MESSAGES/django.po,sha256=DcbYT_nRWB3Gx4lwOUdJlXXOsOGoqV3wFYQWzyCpE5o,2012 massadmin/locale/pl/LC_MESSAGES/django.mo,sha256=2npTiJ82zsp66GFEXTroQRaflNTQ38R_ThEYq6E1sTM,1281 massadmin/locale/pl/LC_MESSAGES/django.po,sha256=hPY7XEPtso2d1tm9EpDQHC_jcY-LZLHn1xD0D-vbVJ8,2036 massadmin/locale/pt/LC_MESSAGES/django.mo,sha256=4OBY6C0Fn2fdceA4kL6mhQRQhuTs_O9Mmhw3gqGQBHM,1275 massadmin/locale/pt/LC_MESSAGES/django.po,sha256=P6fbH5mlxIxlznEpTvvSifLRxyZIJKY8QvIcSHMjkKI,2026 massadmin/templates/admin/mass_change_form.html,sha256=tX-7ttGIxsyT7_Fjpsftrnp6q2nTaIwXD8fwk5v7R7g,2862 massadmin/templates/admin/save_only_submit_line.html,sha256=BhrlD9V34fv040DwuQxJg0pcCL5HKlaXizBhph-AQtk,200 massadmin/templates/admin/includes/mass_fieldset.html,sha256=9wZ9rqUqsevc9_8PnDel5q5LR6hgv3oomYFyGA-VM30,2113 massadmin/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 massadmin/templatetags/__init__.pyc,sha256=aj_FwhRgBWGpc6auoIhWDu4GmxEM4y8wH2AwNDt9SwE,160 massadmin/templatetags/truncchar.py,sha256=Qx49M24ZsSLArsFqKrHFwJsyuyc8ULc30njnLB0JxJs,1776 massadmin/templatetags/truncchar.pyc,sha256=KtxHhoH7x8Br-zN1Lnf-KgzTSZyWMAlmCnrOg8BZHno,2067 massadmin/templatetags/__pycache__/__init__.cpython-34.pyc,sha256=CCdEB-vE6xeIG8_PYGDH-ikggeOsq2FHGSFzrOSDtDQ,156 massadmin/templatetags/__pycache__/truncchar.cpython-34.pyc,sha256=0wwTaTb57CqZZGnijPiBX8UzdFscpAechZhWYVUrGHE,1954 massadmin2/__init__.py,sha256=U8Ddbo_6w2zTUChd4Hw3LH4iIMKvxCwJHSrSWI-ES8E,1642 massadmin2/massadmin.py,sha256=vRSrWUlPy56-naQLfP_80EQoJNyVkTntKB8IgEMWk8M,13781 massadmin2/tests.py,sha256=3sWJ2hZSThUMejSdqShvVtblGwX1HqgpzaFP3XtEvtw,550 massadmin2/urls.py,sha256=JHw6VXfbdqXR-OWpAS3dPuBpG6C5lSzx0A3wM1haXXY,212 massadmin2/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 massadmin2/templatetags/truncchar.py,sha256=Qx49M24ZsSLArsFqKrHFwJsyuyc8ULc30njnLB0JxJs,1776 tests/__init__.py,sha256=q_xcMjhQy8xCi5_8MkbuwrOpKydUMU9s6DRybQzHRi8,15 tests/admin.py,sha256=X9IRCPWQ6jJjIksIjmydRpKlCptEm_LiyscwzVL0ru0,930 tests/models.py,sha256=oZDX6M1D1LeTSU4Q6XiU7jFZitSXlpAxd2IqBxsLx6k,287 tests/settings.py,sha256=Jic-_x1bJqcXOjFN-fto24tccdg5bAcXn-slSMkbSm8,877 tests/tests.py,sha256=Fsji_ZHjFdzJ7Pakq9HlgVlMJolrCxefGKfcSf3Pc0k,4454 tests/urls.py,sha256=BisfjcPJwZluZEJ4Luc86YCxXh13goN6PgzxSzP7F54,228 PK݆F jjmassadmin/__init__.pyPKB4Gk{7{7massadmin/massadmin.pyPKB4G7L>massadmin/urls.pyPKFY84r?massadmin/templates/admin/save_only_submit_line.htmlPKF8. . /@massadmin/templates/admin/mass_change_form.htmlPKB4GAA5Lmassadmin/templates/admin/includes/mass_fieldset.htmlPKF(c)Tmassadmin/locale/cs/LC_MESSAGES/django.poPKFo)Zmassadmin/locale/cs/LC_MESSAGES/django.moPKF14)^massadmin/locale/pt/LC_MESSAGES/django.poPKFu)fmassadmin/locale/pt/LC_MESSAGES/django.moPKG׆*)1lmassadmin/locale/pl/LC_MESSAGES/django.poPKGpBk)ltmassadmin/locale/pl/LC_MESSAGES/django.moPKF}\)ymassadmin/locale/es/LC_MESSAGES/django.poPKFc)ׁmassadmin/locale/es/LC_MESSAGES/django.moPK݆F5# massadmin/templatetags/truncchar.pyPK݆F"<massadmin/templatetags/__init__.pyPKFDWd #|massadmin/templatetags/__init__.pycPKF&$]massadmin/templatetags/truncchar.pycPK+4G0(L;massadmin/templatetags/__pycache__/truncchar.cpython-34.pycPK4GKZ:massadmin/templatetags/__pycache__/__init__.cpython-34.pycPKB4Gcfftests/tests.pyPKB4G"s3tests/__init__.pyPKB4G ~qtests/models.pyPKB4Gq鋢tests/admin.pyPKB4Gh-mmtests/settings.pyPKB4GIW 'tests/urls.pyPKF'W6mass_demo/wsgi.pyPKFmass_demo/__init__.pyPKB4G> !mass_demo/settings.pyPK:gFIW!mass_demo/urls.pyPK(gFsF&&4massadmin2/tests.pyPK:gF jjmassadmin2/__init__.pyPKF#S55)massadmin2/massadmin.pyPK4gF;3massadmin2/urls.pyPK:gF5$7massadmin2/templatetags/truncchar.pyPK:gF#imassadmin2/templatetags/__init__.pyPKYG^- .django_mass_edit-2.5.dist-info/DESCRIPTION.rstPKYG%j~,django_mass_edit-2.5.dist-info/metadata.jsonPKYGY%%,django_mass_edit-2.5.dist-info/top_level.txtPKYG}\\$Adjango_mass_edit-2.5.dist-info/WHEELPKYG3_'django_mass_edit-2.5.dist-info/METADATAPKYGm%%django_mass_edit-2.5.dist-info/RECORDPK** %