def mass_update(modeladmin, request, queryset): """ mass update queryset """ def not_required(field, **kwargs): """ force all fields as not required""" kwargs['required'] = False return field.formfield(**kwargs) opts = modeladmin.model._meta perm = "{0}.{1}".format(opts.app_label.lower(), get_permission_codename('adminactions_massupdate', opts)) if not request.user.has_perm(perm): messages.error(request, _('Sorry you do not have rights to execute this action')) return try: adminaction_requested.send(sender=modeladmin.model, action='mass_update', request=request, queryset=queryset, modeladmin=modeladmin) except ActionInterrupted as e: messages.error(request, str(e)) return # Allows to specified a custom mass update Form in the ModelAdmin mass_update_form = getattr(modeladmin, 'mass_update_form', MassUpdateForm) MForm = modelform_factory(modeladmin.model, form=mass_update_form, formfield_callback=not_required) grouped = defaultdict(lambda: []) selected_fields = [] initial = {'_selected_action': request.POST.getlist(helpers.ACTION_CHECKBOX_NAME), 'select_across': request.POST.get('select_across') == '1', 'action': 'mass_update'} if 'apply' in request.POST: form = MForm(request.POST) if form.is_valid(): try: adminaction_start.send(sender=modeladmin.model, action='mass_update', request=request, queryset=queryset, modeladmin=modeladmin, form=form) except ActionInterrupted as e: messages.error(request, str(e)) return HttpResponseRedirect(request.get_full_path()) need_transaction = form.cleaned_data.get('_unique_transaction', False) validate = form.cleaned_data.get('_validate', False) clean = form.cleaned_data.get('_clean', False) updated = 0 errors = {} if validate: if need_transaction: transaction.enter_transaction_management() transaction.managed(True) for record in queryset: for field_name, value_or_func in form.cleaned_data.items(): if callable(value_or_func): old_value = getattr(record, field_name) setattr(record, field_name, value_or_func(old_value)) else: setattr(record, field_name, value_or_func) try: if clean: record.clean() record.save() except IntegrityError as e: errors[record.pk] = str(e) if need_transaction: transaction.rollback() updated = 0 break else: updated += 1 if updated: messages.info(request, _("Updated %s records") % updated) if len(errors): messages.error(request, "%s records not updated due errors" % len(errors)) try: adminaction_end.send(sender=modeladmin.model, action='mass_update', request=request, queryset=queryset, modeladmin=modeladmin, form=form, errors=errors, updated=updated) if need_transaction: transaction.commit() except ActionInterrupted: if need_transaction: transaction.rollback() finally: if need_transaction: transaction.leave_transaction_management() else: values = {} for field_name, value in form.cleaned_data.items(): if isinstance(form.fields[field_name], ModelMultipleChoiceField): messages.error(request, "Unable no mass update ManyToManyField without 'validate'") return HttpResponseRedirect(request.get_full_path()) elif callable(value): messages.error(request, "Unable no mass update using operators without 'validate'") return HttpResponseRedirect(request.get_full_path()) elif field_name not in ['_selected_action', '_validate', 'select_across', 'action']: values[field_name] = value queryset.update(**values) return HttpResponseRedirect(request.get_full_path()) else: initial.update({'action': 'mass_update', '_validate': 1}) #form = MForm(initial=initial) prefill_with = request.POST.get('prefill-with', None) prefill_instance = None try: # Gets the instance directly from the queryset for data security prefill_instance = queryset.get(pk=prefill_with) except ObjectDoesNotExist: pass form = MForm(initial=initial, instance=prefill_instance) for el in queryset.all()[:10]: for f in modeladmin.model._meta.fields: if f.name not in form._no_sample_for: if hasattr(f, 'flatchoices') and f.flatchoices: grouped[f.name] = dict(getattr(f, 'flatchoices')).values() elif hasattr(f, 'choices') and f.choices: grouped[f.name] = dict(getattr(f, 'choices')).values() elif isinstance(f, df.BooleanField): grouped[f.name] = [True, False] else: value = getattr(el, f.name) if value is not None and value not in grouped[f.name]: grouped[f.name].append(value) initial[f.name] = initial.get(f.name, value) adminForm = helpers.AdminForm(form, modeladmin.get_fieldsets(request), {}, [], model_admin=modeladmin) media = modeladmin.media + adminForm.media dthandler = lambda obj: obj.isoformat() if isinstance(obj, datetime.date) else str(obj) tpl = 'adminactions/mass_update.html' ctx = {'adminform': adminForm, 'form': form, 'title': u"Mass update %s" % force_unicode(modeladmin.opts.verbose_name_plural), 'grouped': grouped, 'fieldvalues': json.dumps(grouped, default=dthandler), 'change': True, 'selected_fields': selected_fields, 'is_popup': False, 'save_as': False, 'has_delete_permission': False, 'has_add_permission': False, 'has_change_permission': True, 'opts': modeladmin.model._meta, 'app_label': modeladmin.model._meta.app_label, # 'action': 'mass_update', # 'select_across': request.POST.get('select_across')=='1', 'media': mark_safe(media), 'selection': queryset} return render_to_response(tpl, RequestContext(request, ctx))
def merge(modeladmin, request, queryset): """ Merge two model instances. Move all foreign keys. """ opts = modeladmin.model._meta perm = "{0}.{1}".format( opts.app_label.lower(), get_permission_codename('adminactions_merge', opts)) if not request.user.has_perm(perm): messages.error( request, _('Sorry you do not have rights to execute this action (%s)' % perm)) return def raw_widget(field, **kwargs): """ force all fields as not required""" kwargs['widget'] = TextInput({'class': 'raw-value'}) return field.formfield(**kwargs) merge_form = getattr(modeladmin, 'merge_form', MergeForm) MForm = modelform_factory(modeladmin.model, form=merge_form, exclude=('pk', ), formfield_callback=raw_widget) OForm = modelform_factory(modeladmin.model, exclude=('pk', ), formfield_callback=raw_widget) tpl = 'adminactions/merge.html' # transaction_supported = model_supports_transactions(modeladmin.model) ctx = { '_selected_action': request.POST.getlist(helpers.ACTION_CHECKBOX_NAME), 'transaction_supported': 'Un', 'select_across': request.POST.get('select_across') == '1', 'action': request.POST.get('action'), 'fields': [ f for f in queryset.model._meta.fields if not f.primary_key and f.editable ], 'app_label': queryset.model._meta.app_label, 'result': '', 'opts': queryset.model._meta } if 'preview' in request.POST: master = queryset.get(pk=request.POST.get('master_pk')) original = clone_instance(master) other = queryset.get(pk=request.POST.get('other_pk')) formset = formset_factory(OForm)( initial=[model_to_dict(master), model_to_dict(other)]) with transaction.nocommit(): form = MForm(request.POST, instance=master) other.delete() form_is_valid = form.is_valid() if form_is_valid: ctx.update({'original': original}) tpl = 'adminactions/merge_preview.html' else: master = queryset.get(pk=request.POST.get('master_pk')) other = queryset.get(pk=request.POST.get('other_pk')) elif 'apply' in request.POST: master = queryset.get(pk=request.POST.get('master_pk')) other = queryset.get(pk=request.POST.get('other_pk')) formset = formset_factory(OForm)( initial=[model_to_dict(master), model_to_dict(other)]) with transaction.nocommit(): form = MForm(request.POST, instance=master) stored_pk = other.pk other.delete() ok = form.is_valid() other.pk = stored_pk if ok: if form.cleaned_data['dependencies'] == MergeForm.DEP_MOVE: related = api.ALL_FIELDS else: related = None fields = form.cleaned_data['field_names'] api.merge(master, other, fields=fields, commit=True, related=related) return HttpResponseRedirect(request.path) else: messages.error(request, form.errors) else: try: master, other = queryset.all() # django 1.4 need to remove the trailing milliseconds for field in master._meta.fields: if isinstance(field, models.DateTimeField): for target in (master, other): raw_value = getattr(target, field.name) fixed_value = datetime(raw_value.year, raw_value.month, raw_value.day, raw_value.hour, raw_value.minute, raw_value.second) setattr(target, field.name, fixed_value) except ValueError: messages.error(request, _('Please select exactly 2 records')) return initial = { '_selected_action': request.POST.getlist(helpers.ACTION_CHECKBOX_NAME), 'select_across': 0, 'generic': MergeForm.GEN_IGNORE, 'dependencies': MergeForm.DEP_MOVE, 'action': 'merge', 'master_pk': master.pk, 'other_pk': other.pk } formset = formset_factory(OForm)( initial=[model_to_dict(master), model_to_dict(other)]) form = MForm(initial=initial, instance=master) adminForm = helpers.AdminForm(form, modeladmin.get_fieldsets(request), {}, [], model_admin=modeladmin) media = modeladmin.media + adminForm.media ctx.update({ 'adminform': adminForm, 'formset': formset, 'media': mark_safe(media), 'title': u"Merge %s" % force_unicode(modeladmin.opts.verbose_name_plural), 'master': master, 'other': other }) return render_to_response(tpl, RequestContext(request, ctx))
def export_delete_tree(modeladmin, request, queryset): # noqa """ Export as fixture selected queryset and all the records that belong to. That mean that dump what will be deleted if the queryset was deleted """ opts = modeladmin.model._meta perm = "{0}.{1}".format(opts.app_label, get_permission_codename('adminactions_export', opts)) if not request.user.has_perm(perm): messages.error(request, _('Sorry you do not have rights to execute this action')) return try: adminaction_requested.send(sender=modeladmin.model, action='export_delete_tree', request=request, queryset=queryset, modeladmin=modeladmin) except ActionInterrupted as e: messages.error(request, str(e)) return initial = {'_selected_action': request.POST.getlist(helpers.ACTION_CHECKBOX_NAME), 'select_across': request.POST.get('select_across') == '1', 'action': get_action(request), 'serializer': 'json', 'indent': 4} if 'apply' in request.POST: form = FixtureOptions(request.POST) if form.is_valid(): try: adminaction_start.send(sender=modeladmin.model, action='export_delete_tree', request=request, queryset=queryset, modeladmin=modeladmin, form=form) except ActionInterrupted as e: messages.error(request, str(e)) return try: collect_related = form.cleaned_data.get('add_foreign_keys') using = router.db_for_write(modeladmin.model) c = Collector(using) c.collect(queryset, collect_related=collect_related) data = [] for model, instances in list(c.data.items()): data.extend(instances) adminaction_end.send(sender=modeladmin.model, action='export_delete_tree', request=request, queryset=queryset, modeladmin=modeladmin, form=form) if hasattr(modeladmin, 'get_export_delete_tree_filename'): filename = modeladmin.get_export_delete_tree_filename(request, queryset) else: filename = None return _dump_qs(form, queryset, data, filename) except AttributeError as e: messages.error(request, str(e)) return HttpResponseRedirect(request.path) else: form = FixtureOptions(initial=initial) adminForm = helpers.AdminForm(form, modeladmin.get_fieldsets(request), {}, model_admin=modeladmin) media = modeladmin.media + adminForm.media tpl = 'adminactions/export_fixture.html' ctx = {'adminform': adminForm, 'change': True, 'action_short_description': export_delete_tree.short_description, 'title': u"%s (%s)" % ( export_delete_tree.short_description.capitalize(), modeladmin.opts.verbose_name_plural, ), 'is_popup': False, 'save_as': False, 'has_delete_permission': False, 'has_add_permission': False, 'has_change_permission': True, 'queryset': queryset, 'opts': queryset.model._meta, 'app_label': queryset.model._meta.app_label, 'media': mark_safe(media)} if django.VERSION[:2] > (1, 7): ctx.update(modeladmin.admin_site.each_context(request)) else: ctx.update(modeladmin.admin_site.each_context()) return render_to_response(tpl, RequestContext(request, ctx))
def base_export(modeladmin, request, queryset, title, impl, # noqa name, action_short_description, template, form_class, ): """ export a queryset to csv file """ opts = modeladmin.model._meta perm = "{0}.{1}".format(opts.app_label, get_permission_codename('adminactions_export', opts)) if not request.user.has_perm(perm): messages.error(request, _('Sorry you do not have rights to execute this action')) return try: adminaction_requested.send(sender=modeladmin.model, action=name, request=request, queryset=queryset, modeladmin=modeladmin) except ActionInterrupted as e: messages.error(request, str(e)) return cols = [(f.name, f.verbose_name) for f in queryset.model._meta.fields] initial = {'_selected_action': request.POST.getlist(helpers.ACTION_CHECKBOX_NAME), 'select_across': request.POST.get('select_across') == '1', 'action': get_action(request), 'columns': [x for x, v in cols]} if initial["action"] == "export_as_csv": initial.update(getattr( settings, "ADMINACTIONS_CSV_OPTIONS_DEFAULT", {})) if 'apply' in request.POST: form = form_class(request.POST) form.fields['columns'].choices = cols if form.is_valid(): try: adminaction_start.send(sender=modeladmin.model, action=name, request=request, queryset=queryset, modeladmin=modeladmin, form=form) except ActionInterrupted as e: messages.error(request, str(e)) return if hasattr(modeladmin, 'get_%s_filename' % name): filename = modeladmin.get_export_as_csv_filename(request, queryset) else: filename = None try: response = impl(queryset, fields=form.cleaned_data['columns'], header=form.cleaned_data.get('header', False), filename=filename, options=form.cleaned_data) except Exception as e: messages.error(request, "Error: (%s)" % str(e)) else: adminaction_end.send(sender=modeladmin.model, action=name, request=request, queryset=queryset, modeladmin=modeladmin, form=form) return response else: form = form_class(initial=initial) form.fields['columns'].choices = cols adminForm = helpers.AdminForm(form, modeladmin.get_fieldsets(request), {}, [], model_admin=modeladmin) media = modeladmin.media + adminForm.media # tpl = 'adminactions/export_csv.html' ctx = {'adminform': adminForm, 'change': True, 'action_short_description': action_short_description, 'title': title, 'is_popup': False, 'save_as': False, 'has_delete_permission': False, 'has_add_permission': False, 'has_change_permission': True, 'queryset': queryset, 'opts': queryset.model._meta, 'app_label': queryset.model._meta.app_label, 'media': mark_safe(media)} if django.VERSION[:2] > (1, 7): ctx.update(modeladmin.admin_site.each_context(request)) else: ctx.update(modeladmin.admin_site.each_context()) return render_to_response(template, RequestContext(request, ctx))
def export_as_fixture(modeladmin, request, queryset): initial = {'_selected_action': request.POST.getlist(helpers.ACTION_CHECKBOX_NAME), 'select_across': request.POST.get('select_across') == '1', 'action': request.POST.get('action'), 'serializer': 'json', 'indent': 4} opts = modeladmin.model._meta perm = "{0}.{1}".format(opts.app_label.lower(), get_permission_codename('adminactions_export', opts)) if not request.user.has_perm(perm): messages.error(request, _('Sorry you do not have rights to execute this action (%s)' % perm)) return try: adminaction_requested.send(sender=modeladmin.model, action='export_as_fixture', request=request, queryset=queryset, modeladmin=modeladmin) except ActionInterrupted as e: messages.error(request, str(e)) return if 'apply' in request.POST: form = FixtureOptions(request.POST) if form.is_valid(): try: adminaction_start.send(sender=modeladmin.model, action='export_as_fixture', request=request, queryset=queryset, modeladmin=modeladmin, form=form) except ActionInterrupted as e: messages.error(request, str(e)) return try: _collector = ForeignKeysCollector if form.cleaned_data.get('add_foreign_keys') else FlatCollector c = _collector(None) c.collect(queryset) adminaction_end.send(sender=modeladmin.model, action='export_as_fixture', request=request, queryset=queryset, modeladmin=modeladmin, form=form) if hasattr(modeladmin, 'get_export_as_fixture_filename'): filename = modeladmin.get_export_as_fixture_filename(request, queryset) else: filename = None return _dump_qs(form, queryset, c.data, filename) except AttributeError as e: messages.error(request, str(e)) return HttpResponseRedirect(request.path) else: form = FixtureOptions(initial=initial) adminForm = helpers.AdminForm(form, modeladmin.get_fieldsets(request), {}, model_admin=modeladmin) media = modeladmin.media + adminForm.media tpl = 'adminactions/export_fixture.html' ctx = {'adminform': adminForm, 'change': True, 'title': _('Export as Fixture'), 'is_popup': False, 'save_as': False, 'has_delete_permission': False, 'has_add_permission': False, 'has_change_permission': True, 'queryset': queryset, 'opts': queryset.model._meta, 'app_label': queryset.model._meta.app_label, 'media': mark_safe(media)} return render_to_response(tpl, RequestContext(request, ctx))
def mass_update(modeladmin, request, queryset): # noqa """ mass update queryset """ def not_required(field, **kwargs): """ force all fields as not required""" kwargs['required'] = False return field.formfield(**kwargs) def _doit(): errors = {} updated = 0 for record in queryset: for field_name, value_or_func in list(form.cleaned_data.items()): if callable(value_or_func): old_value = getattr(record, field_name) setattr(record, field_name, value_or_func(old_value)) else: setattr(record, field_name, value_or_func) if clean: record.clean() record.save() updated += 1 if updated: messages.info(request, _("Updated %s records") % updated) if len(errors): messages.error(request, "%s records not updated due errors" % len(errors)) adminaction_end.send(sender=modeladmin.model, action='mass_update', request=request, queryset=queryset, modeladmin=modeladmin, form=form, errors=errors, updated=updated) opts = modeladmin.model._meta perm = "{0}.{1}".format( opts.app_label.lower(), get_permission_codename('adminactions_massupdate', opts)) if not request.user.has_perm(perm): messages.error( request, _('Sorry you do not have rights to execute this action')) return try: adminaction_requested.send(sender=modeladmin.model, action='mass_update', request=request, queryset=queryset, modeladmin=modeladmin) except ActionInterrupted as e: messages.error(request, str(e)) return # Allows to specified a custom mass update Form in the ModelAdmin mass_update_form = getattr(modeladmin, 'mass_update_form', MassUpdateForm) MForm = modelform_factory(modeladmin.model, form=mass_update_form, exclude=('pk', ), formfield_callback=not_required) grouped = defaultdict(lambda: []) selected_fields = [] initial = { '_selected_action': request.POST.getlist(helpers.ACTION_CHECKBOX_NAME), 'select_across': request.POST.get('select_across') == '1', 'action': 'mass_update' } if 'apply' in request.POST: form = MForm(request.POST) if form.is_valid(): try: adminaction_start.send(sender=modeladmin.model, action='mass_update', request=request, queryset=queryset, modeladmin=modeladmin, form=form) except ActionInterrupted as e: messages.error(request, str(e)) return HttpResponseRedirect(request.get_full_path()) # need_transaction = form.cleaned_data.get('_unique_transaction', False) validate = form.cleaned_data.get('_validate', False) clean = form.cleaned_data.get('_clean', False) if validate: with compat.atomic(): _doit() else: values = {} for field_name, value in list(form.cleaned_data.items()): if isinstance(form.fields[field_name], ModelMultipleChoiceField): messages.error( request, "Unable no mass update ManyToManyField without 'validate'" ) return HttpResponseRedirect(request.get_full_path()) elif callable(value): messages.error( request, "Unable no mass update using operators without 'validate'" ) return HttpResponseRedirect(request.get_full_path()) elif field_name not in [ '_selected_action', '_validate', 'select_across', 'action', '_unique_transaction', '_clean' ]: values[field_name] = value queryset.update(**values) return HttpResponseRedirect(request.get_full_path()) else: initial.update({'action': 'mass_update', '_validate': 1}) # form = MForm(initial=initial) prefill_with = request.POST.get('prefill-with', None) prefill_instance = None try: # Gets the instance directly from the queryset for data security prefill_instance = queryset.get(pk=prefill_with) except ObjectDoesNotExist: pass form = MForm(initial=initial, instance=prefill_instance) for el in queryset.all()[:10]: for f in modeladmin.model._meta.fields: if f.name not in form._no_sample_for: if hasattr(f, 'flatchoices') and f.flatchoices: grouped[f.name] = list( dict(getattr(f, 'flatchoices')).values()) elif hasattr(f, 'choices') and f.choices: grouped[f.name] = list( dict(getattr(f, 'choices')).values()) elif isinstance(f, df.BooleanField): grouped[f.name] = [True, False] else: value = getattr(el, f.name) if value is not None and value not in grouped[f.name]: grouped[f.name].append(value) initial[f.name] = initial.get(f.name, value) adminForm = helpers.AdminForm(form, modeladmin.get_fieldsets(request), {}, [], model_admin=modeladmin) media = modeladmin.media + adminForm.media dthandler = lambda obj: obj.isoformat() if isinstance(obj, datetime.date ) else str(obj) tpl = 'adminactions/mass_update.html' ctx = { 'adminform': adminForm, 'form': form, 'title': u"Mass update %s" % smart_text(modeladmin.opts.verbose_name_plural), 'grouped': grouped, 'fieldvalues': json.dumps(grouped, default=dthandler), 'change': True, 'selected_fields': selected_fields, 'is_popup': False, 'save_as': False, 'has_delete_permission': False, 'has_add_permission': False, 'has_change_permission': True, 'opts': modeladmin.model._meta, 'app_label': modeladmin.model._meta.app_label, # 'action': 'mass_update', # 'select_across': request.POST.get('select_across')=='1', 'media': mark_safe(media), 'selection': queryset } return render_to_response(tpl, RequestContext(request, ctx))
def base_export(modeladmin, request, queryset, title, impl, name, template, form_class, ): """ export a queryset to csv file """ opts = modeladmin.model._meta perm = "{0}.{1}".format(opts.app_label.lower(), get_permission_codename('adminactions_export', opts)) if not request.user.has_perm(perm): messages.error(request, _('Sorry you do not have rights to execute this action (%s)' % perm)) return try: adminaction_requested.send(sender=modeladmin.model, action=name, request=request, queryset=queryset, modeladmin=modeladmin) except ActionInterrupted as e: messages.error(request, str(e)) return cols = [(f.name, f.verbose_name) for f in queryset.model._meta.fields] initial = {'_selected_action': request.POST.getlist(helpers.ACTION_CHECKBOX_NAME), 'select_across': request.POST.get('select_across') == '1', 'action': request.POST.get('action'), 'columns': [x for x, v in cols]} # initial.update(csv_options_default) if 'apply' in request.POST: form = form_class(request.POST) form.fields['columns'].choices = cols if form.is_valid(): try: adminaction_start.send(sender=modeladmin.model, action=name, request=request, queryset=queryset, modeladmin=modeladmin, form=form) except ActionInterrupted as e: messages.error(request, str(e)) return if hasattr(modeladmin, 'get_%s_filename' % name): filename = modeladmin.get_export_as_csv_filename(request, queryset) else: filename = None try: response = impl(queryset, fields=form.cleaned_data['columns'], header=form.cleaned_data.get('header', False), filename=filename, options=form.cleaned_data) except Exception as e: messages.error(request, "Error: (%s)" % str(e)) else: adminaction_end.send(sender=modeladmin.model, action=name, request=request, queryset=queryset, modeladmin=modeladmin, form=form) return response else: form = form_class(initial=initial) form.fields['columns'].choices = cols adminForm = helpers.AdminForm(form, modeladmin.get_fieldsets(request), {}, [], model_admin=modeladmin) media = modeladmin.media + adminForm.media # tpl = 'adminactions/export_csv.html' ctx = {'adminform': adminForm, 'change': True, 'title': title, 'is_popup': False, 'save_as': False, 'has_delete_permission': False, 'has_add_permission': False, 'has_change_permission': True, 'queryset': queryset, 'opts': queryset.model._meta, 'app_label': queryset.model._meta.app_label, 'media': mark_safe(media)} return render_to_response(template, RequestContext(request, ctx))
def export_delete_tree(modeladmin, request, queryset): """ Export as fixture selected queryset and all the records that belong to. That mean that dump what will be deleted if the queryset was deleted """ opts = modeladmin.model._meta perm = "{0}.{1}".format(opts.app_label.lower(), get_permission_codename('adminactions_export', opts)) if not request.user.has_perm(perm): messages.error(request, _('Sorry you do not have rights to execute this action (%s)' % perm)) return try: adminaction_requested.send(sender=modeladmin.model, action='export_delete_tree', request=request, queryset=queryset, modeladmin=modeladmin) except ActionInterrupted as e: messages.error(request, str(e)) return initial = {'_selected_action': request.POST.getlist(helpers.ACTION_CHECKBOX_NAME), 'select_across': request.POST.get('select_across') == '1', 'action': request.POST.get('action'), 'serializer': 'json', 'indent': 4} if 'apply' in request.POST: form = FixtureOptions(request.POST) if form.is_valid(): try: adminaction_start.send(sender=modeladmin.model, action='export_delete_tree', request=request, queryset=queryset, modeladmin=modeladmin, form=form) except ActionInterrupted as e: messages.error(request, str(e)) return try: collect_related = form.cleaned_data.get('add_foreign_keys') using = router.db_for_write(modeladmin.model) c = Collector(using) c.collect(queryset, collect_related=collect_related) data = [] for model, instances in c.data.items(): data.extend(instances) adminaction_end.send(sender=modeladmin.model, action='export_delete_tree', request=request, queryset=queryset, modeladmin=modeladmin, form=form) if hasattr(modeladmin, 'get_export_delete_tree_filename'): filename = modeladmin.get_export_delete_tree_filename(request, queryset) else: filename = None return _dump_qs(form, queryset, data, filename) except AttributeError as e: messages.error(request, str(e)) return HttpResponseRedirect(request.path) else: form = FixtureOptions(initial=initial) adminForm = helpers.AdminForm(form, modeladmin.get_fieldsets(request), {}, model_admin=modeladmin) media = modeladmin.media + adminForm.media tpl = 'adminactions/export_fixture.html' ctx = {'adminform': adminForm, 'change': True, 'title': _('Export Delete Tree'), 'is_popup': False, 'save_as': False, 'has_delete_permission': False, 'has_add_permission': False, 'has_change_permission': True, 'queryset': queryset, 'opts': queryset.model._meta, 'app_label': queryset.model._meta.app_label, 'media': mark_safe(media)} return render_to_response(tpl, RequestContext(request, ctx))
def byrows_update(modeladmin, request, queryset): # noqa """ by rows update queryset :type modeladmin: ModelAdmin :type request: HttpRequest :type queryset: QuerySet """ opts = modeladmin.model._meta perm = "{0}.{1}".format(opts.app_label.lower(), get_permission_codename('adminactions_byrowsupdate', opts)) if not request.user.has_perm(perm): messages.error(request, _('Sorry you do not have rights to execute this action')) return class modelform(modeladmin.form): def __init__(self, *args, **kwargs): super(modeladmin.form, self).__init__(*args, **kwargs) if self.instance: readonly_fields = (modeladmin.model._meta.pk.name,) + modeladmin.get_readonly_fields(request) for fname in readonly_fields: if fname in self.fields: self.fields[fname].widget.attrs['readonly'] = 'readonly' self.fields[fname].widget.attrs['class'] = 'readonly' fields = byrows_update_get_fields(modeladmin) ActionForm = modelform_factory(modeladmin.model, form=GenericActionForm, fields=fields) MFormSet = modelformset_factory(modeladmin.model, form=modelform, fields=fields, extra=0) if 'apply' in request.POST: actionform = ActionForm(request.POST) formset = MFormSet(request.POST) if formset.is_valid(): formset.save() messages.info(request, _("Updated record(s)")) return HttpResponseRedirect(request.get_full_path()) else: action_form_initial = {'_selected_action': request.POST.getlist(helpers.ACTION_CHECKBOX_NAME), 'select_across': request.POST.get('select_across') == '1', 'action': 'byrows_update'} actionform = ActionForm(initial=action_form_initial, instance=None) formset = MFormSet(queryset=queryset) adminform = helpers.AdminForm( actionform, modeladmin.get_fieldsets(request), {}, [], model_admin=modeladmin) tpl = 'adminactions/byrows_update.html' ctx = { 'adminform': adminform, 'actionform': actionform, 'action_short_description': byrows_update.short_description, 'title': u"%s (%s)" % ( byrows_update.short_description.capitalize(), smart_text(modeladmin.opts.verbose_name_plural), ), 'formset': formset, 'opts': modeladmin.model._meta, 'app_label': modeladmin.model._meta.app_label, } if django.VERSION[:2] > (1, 7): ctx.update(modeladmin.admin_site.each_context(request)) else: ctx.update(modeladmin.admin_site.each_context()) return render_to_response(tpl, RequestContext(request, ctx))
def merge(modeladmin, request, queryset): # noqa """ Merge two model instances. Move all foreign keys. """ opts = modeladmin.model._meta perm = "{0}.{1}".format(opts.app_label, get_permission_codename('adminactions_merge', opts)) if not request.user.has_perm(perm): messages.error(request, _('Sorry you do not have rights to execute this action (%s)' % perm)) return def raw_widget(field, **kwargs): """ force all fields as not required""" kwargs['widget'] = TextInput({'class': 'raw-value'}) return field.formfield(**kwargs) merge_form = getattr(modeladmin, 'merge_form', MergeForm) MForm = modelform_factory(modeladmin.model, form=merge_form, exclude=('pk', ), formfield_callback=raw_widget) OForm = modelform_factory(modeladmin.model, exclude=('pk', ), formfield_callback=raw_widget) tpl = 'adminactions/merge.html' # transaction_supported = model_supports_transactions(modeladmin.model) ctx = { '_selected_action': request.POST.getlist(helpers.ACTION_CHECKBOX_NAME), 'transaction_supported': 'Un', 'select_across': request.POST.get('select_across') == '1', 'action': request.POST.get('action'), 'fields': [f for f in queryset.model._meta.fields if not f.primary_key and f.editable], 'app_label': queryset.model._meta.app_label, 'result': '', 'opts': queryset.model._meta} if 'preview' in request.POST: master = queryset.get(pk=request.POST.get('master_pk')) original = clone_instance(master) other = queryset.get(pk=request.POST.get('other_pk')) formset = formset_factory(OForm)(initial=[model_to_dict(master), model_to_dict(other)]) with transaction.nocommit(): form = MForm(request.POST, instance=master) other.delete() form_is_valid = form.is_valid() if form_is_valid: ctx.update({'original': original}) tpl = 'adminactions/merge_preview.html' else: master = queryset.get(pk=request.POST.get('master_pk')) other = queryset.get(pk=request.POST.get('other_pk')) elif 'apply' in request.POST: master = queryset.get(pk=request.POST.get('master_pk')) other = queryset.get(pk=request.POST.get('other_pk')) formset = formset_factory(OForm)(initial=[model_to_dict(master), model_to_dict(other)]) with transaction.nocommit(): form = MForm(request.POST, instance=master) stored_pk = other.pk other.delete() ok = form.is_valid() other.pk = stored_pk if ok: if form.cleaned_data['dependencies'] == MergeForm.DEP_MOVE: related = api.ALL_FIELDS else: related = None fields = form.cleaned_data['field_names'] api.merge(master, other, fields=fields, commit=True, related=related) return HttpResponseRedirect(request.path) else: messages.error(request, form.errors) else: try: master, other = queryset.all() # django 1.4 need to remove the trailing milliseconds for field in master._meta.fields: if isinstance(field, models.DateTimeField): for target in (master, other): raw_value = getattr(target, field.name) fixed_value = datetime(raw_value.year, raw_value.month, raw_value.day, raw_value.hour, raw_value.minute, raw_value.second) setattr(target, field.name, fixed_value) except ValueError: messages.error(request, _('Please select exactly 2 records')) return initial = {'_selected_action': request.POST.getlist(helpers.ACTION_CHECKBOX_NAME), 'select_across': 0, 'generic': MergeForm.GEN_IGNORE, 'dependencies': MergeForm.DEP_MOVE, 'action': 'merge', 'master_pk': master.pk, 'other_pk': other.pk} formset = formset_factory(OForm)(initial=[model_to_dict(master), model_to_dict(other)]) form = MForm(initial=initial, instance=master) adminForm = helpers.AdminForm(form, modeladmin.get_fieldsets(request), {}, [], model_admin=modeladmin) media = modeladmin.media + adminForm.media ctx.update({'adminform': adminForm, 'formset': formset, 'media': mark_safe(media), 'title': u"Merge %s" % smart_text(modeladmin.opts.verbose_name_plural), 'master': master, 'other': other}) return render_to_response(tpl, RequestContext(request, ctx))
def byrows_update(modeladmin, request, queryset): # noqa """ by rows update queryset :type modeladmin: ModelAdmin :type request: HttpRequest :type queryset: QuerySet """ opts = modeladmin.model._meta perm = "{0}.{1}".format( opts.app_label.lower(), get_permission_codename('adminactions_byrowsupdate', opts)) if not request.user.has_perm(perm): messages.error( request, _('Sorry you do not have rights to execute this action')) return class modelform(modeladmin.form): def __init__(self, *args, **kwargs): super(modeladmin.form, self).__init__(*args, **kwargs) if self.instance: readonly_fields = (modeladmin.model._meta.pk.name, ) + modeladmin.get_readonly_fields(request) for fname in readonly_fields: if fname in self.fields: self.fields[fname].widget.attrs[ 'readonly'] = 'readonly' self.fields[fname].widget.attrs['class'] = 'readonly' fields = byrows_update_get_fields(modeladmin) ActionForm = modelform_factory(modeladmin.model, form=GenericActionForm, fields=fields) MFormSet = modelformset_factory(modeladmin.model, form=modelform, fields=fields, extra=0) if 'apply' in request.POST: actionform = ActionForm(request.POST) formset = MFormSet(request.POST) if formset.is_valid(): formset.save() messages.info(request, _("Updated record(s)")) return HttpResponseRedirect(request.get_full_path()) else: action_form_initial = { '_selected_action': request.POST.getlist(helpers.ACTION_CHECKBOX_NAME), 'select_across': request.POST.get('select_across') == '1', 'action': 'byrows_update' } actionform = ActionForm(initial=action_form_initial, instance=None) formset = MFormSet(queryset=queryset) adminform = helpers.AdminForm(actionform, modeladmin.get_fieldsets(request), {}, [], model_admin=modeladmin) tpl = 'adminactions/byrows_update.html' ctx = { 'adminform': adminform, 'actionform': actionform, 'action_short_description': byrows_update.short_description, 'title': u"%s (%s)" % ( byrows_update.short_description.capitalize(), smart_text(modeladmin.opts.verbose_name_plural), ), 'formset': formset, 'opts': modeladmin.model._meta, 'app_label': modeladmin.model._meta.app_label, } if django.VERSION[:2] > (1, 7): ctx.update(modeladmin.admin_site.each_context(request)) else: ctx.update(modeladmin.admin_site.each_context()) return render_to_response(tpl, RequestContext(request, ctx))
def graph_queryset(modeladmin, request, queryset): # noqa opts = modeladmin.model._meta perm = "{0}.{1}".format(opts.app_label.lower(), get_permission_codename('adminactions_chart', opts)) if not request.user.has_perm(perm): messages.error(request, _('Sorry you do not have rights to execute this action')) return MForm = graph_form_factory(modeladmin.model) graph_type = table = None extra = '{}' try: adminaction_requested.send(sender=modeladmin.model, action='graph_queryset', request=request, queryset=queryset, modeladmin=modeladmin) except ActionInterrupted as e: messages.error(request, str(e)) return if 'apply' in request.POST: form = MForm(request.POST) if form.is_valid(): try: adminaction_start.send(sender=modeladmin.model, action='graph_queryset', request=request, queryset=queryset, modeladmin=modeladmin, form=form) except ActionInterrupted as e: messages.error(request, str(e)) return try: x = form.cleaned_data['axes_x'] # y = form.cleaned_data['axes_y'] graph_type = form.cleaned_data['graph_type'] field, model, direct, m2m = get_field_by_name(modeladmin.model, x) cc = queryset.values_list(x).annotate(Count(x)).order_by() if isinstance(field, ForeignKey): data_labels = [] for value, cnt in cc: data_labels.append(str(field.rel.to.objects.get(pk=value))) elif isinstance(field, BooleanField): data_labels = [str(l) for l, v in cc] elif hasattr(modeladmin.model, 'get_%s_display' % field.name): data_labels = [] for value, cnt in cc: data_labels.append(smart_text(dict(field.flatchoices).get(value, value), strings_only=True)) else: data_labels = [str(l) for l, v in cc] data = [v for l, v in cc] if graph_type == 'BarChart': table = [data] extra = """{seriesDefaults:{renderer:$.jqplot.BarRenderer, rendererOptions: {fillToZero: true, barDirection: 'horizontal'}, shadowAngle: -135, }, series:[%s], axes: {yaxis: {renderer: $.jqplot.CategoryAxisRenderer, ticks: %s}, xaxis: {pad: 1.05, tickOptions: {formatString: '%%d'}} } }""" % (json.dumps(data_labels), json.dumps(data_labels)) elif graph_type == 'PieChart': table = [list(zip(data_labels, data))] extra = """{seriesDefaults: {renderer: jQuery.jqplot.PieRenderer, rendererOptions: {fill: true, showDataLabels: true, sliceMargin: 4, lineWidth: 5}}, legend: {show: true, location: 'e'}}""" except Exception as e: messages.error(request, 'Unable to produce valid data: %s' % str(e)) else: adminaction_end.send(sender=modeladmin.model, action='graph_queryset', request=request, queryset=queryset, modeladmin=modeladmin, form=form) elif request.method == 'POST': # total = queryset.all().count() initial = {helpers.ACTION_CHECKBOX_NAME: request.POST.getlist(helpers.ACTION_CHECKBOX_NAME), 'select_across': request.POST.get('select_across', 0)} form = MForm(initial=initial) else: initial = {helpers.ACTION_CHECKBOX_NAME: request.POST.getlist(helpers.ACTION_CHECKBOX_NAME), 'select_across': request.POST.get('select_across', 0)} form = MForm(initial=initial) adminForm = helpers.AdminForm(form, modeladmin.get_fieldsets(request), {}, [], model_admin=modeladmin) media = modeladmin.media + adminForm.media ctx = {'adminform': adminForm, 'action': 'graph_queryset', 'opts': modeladmin.model._meta, 'action_short_description': graph_queryset.short_description, 'title': u"%s (%s)" % ( graph_queryset.short_description.capitalize(), smart_text(modeladmin.opts.verbose_name_plural), ), 'app_label': queryset.model._meta.app_label, 'media': media, 'extra': extra, 'as_json': json.dumps(table), 'graph_type': graph_type} if django.VERSION[:2] > (1, 7): ctx.update(modeladmin.admin_site.each_context(request)) else: ctx.update(modeladmin.admin_site.each_context()) return render_to_response('adminactions/charts.html', RequestContext(request, ctx))
def merge(modeladmin, request, queryset): """ Merge two model instances. Move all foreign keys. """ opts = modeladmin.model._meta perm = "{0}.{1}".format(opts.app_label.lower(), get_permission_codename('adminactions_merge', opts)) if not request.user.has_perm(perm): messages.error(request, _('Sorry you do not have rights to execute this action (%s)' % perm)) return def raw_widget(field, **kwargs): """ force all fields as not required""" kwargs['widget'] = TextInput({'class': 'raw-value', 'readonly': 'readonly'}) kwargs['widget'] = TextInput({'class': 'raw-value', 'size': '30'}) return field.formfield(**kwargs) # Allows to specified a custom Form in the ModelAdmin # MForm = getattr(modeladmin, 'merge_form', MergeForm) merge_form = getattr(modeladmin, 'merge_form', MergeForm) MForm = modelform_factory(modeladmin.model, form=merge_form, formfield_callback=raw_widget) OForm = modelform_factory(modeladmin.model, formfield_callback=raw_widget) tpl = 'adminactions/merge.html' ctx = { '_selected_action': request.POST.getlist(helpers.ACTION_CHECKBOX_NAME), 'select_across': request.POST.get('select_across') == '1', 'action': request.POST.get('action'), 'fields': [f for f in queryset.model._meta.fields if not f.primary_key and f.editable], 'app_label': queryset.model._meta.app_label, 'result': '', 'opts': queryset.model._meta} if 'preview' in request.POST: master = queryset.get(pk=request.POST.get('master_pk')) original = clone_instance(master) other = queryset.get(pk=request.POST.get('other_pk')) formset = formset_factory(OForm)(initial=[model_to_dict(master), model_to_dict(other)]) with transaction.commit_manually(): form = MForm(request.POST, instance=master) other.delete() form_is_valid = form.is_valid() transaction.rollback() if form_is_valid: ctx.update({'original': original}) tpl = 'adminactions/merge_preview.html' elif 'apply' in request.POST: master = queryset.get(pk=request.POST.get('master_pk')) other = queryset.get(pk=request.POST.get('other_pk')) formset = formset_factory(OForm)(initial=[model_to_dict(master), model_to_dict(other)]) with transaction.commit_manually(): form = MForm(request.POST, instance=master) other.delete() if form.is_valid(): form.save() transaction.commit() return HttpResponseRedirect(request.path) else: messages.error(request, form.errors) transaction.rollback() else: try: master, other = queryset.all() except ValueError: messages.error(request, _('Please select exactly 2 records')) return initial = {'_selected_action': request.POST.getlist(helpers.ACTION_CHECKBOX_NAME), 'select_across': 0, 'generic': MergeForm.GEN_IGNORE, 'dependencies': MergeForm.DEP_MOVE, 'action': 'merge', 'master_pk': master.pk, 'other_pk': other.pk} formset = formset_factory(OForm)(initial=[model_to_dict(master), model_to_dict(other)]) form = MForm(initial=initial, instance=master) adminForm = helpers.AdminForm(form, modeladmin.get_fieldsets(request), {}, [], model_admin=modeladmin) media = modeladmin.media + adminForm.media ctx.update({'adminform': adminForm, 'formset': formset, 'media': mark_safe(media), 'master': master, 'other': other}) return render_to_response(tpl, RequestContext(request, ctx))
def graph_queryset(modeladmin, request, queryset): # noqa opts = modeladmin.model._meta perm = "{0}.{1}".format( opts.app_label.lower(), get_permission_codename('adminactions_chart', opts)) if not request.user.has_perm(perm): messages.error( request, _('Sorry you do not have rights to execute this action')) return MForm = graph_form_factory(modeladmin.model) graph_type = table = None extra = '{}' try: adminaction_requested.send(sender=modeladmin.model, action='graph_queryset', request=request, queryset=queryset, modeladmin=modeladmin) except ActionInterrupted as e: messages.error(request, str(e)) return if 'apply' in request.POST: form = MForm(request.POST) if form.is_valid(): try: adminaction_start.send(sender=modeladmin.model, action='graph_queryset', request=request, queryset=queryset, modeladmin=modeladmin, form=form) except ActionInterrupted as e: messages.error(request, str(e)) return try: x = form.cleaned_data['axes_x'] # y = form.cleaned_data['axes_y'] graph_type = form.cleaned_data['graph_type'] field, model, direct, m2m = get_field_by_name( modeladmin.model, x) cc = queryset.values_list(x).annotate(Count(x)).order_by() if isinstance(field, ForeignKey): data_labels = [] for value, cnt in cc: data_labels.append( str(field.rel.to.objects.get(pk=value))) elif isinstance(field, BooleanField): data_labels = [str(l) for l, v in cc] elif hasattr(modeladmin.model, 'get_%s_display' % field.name): data_labels = [] for value, cnt in cc: data_labels.append( smart_text(dict(field.flatchoices).get( value, value), strings_only=True)) else: data_labels = [str(l) for l, v in cc] data = [v for l, v in cc] if graph_type == 'BarChart': table = [data] extra = """{seriesDefaults:{renderer:$.jqplot.BarRenderer, rendererOptions: {fillToZero: true, barDirection: 'horizontal'}, shadowAngle: -135, }, series:[%s], axes: {yaxis: {renderer: $.jqplot.CategoryAxisRenderer, ticks: %s}, xaxis: {pad: 1.05, tickOptions: {formatString: '%%d'}} } }""" % (json.dumps(data_labels), json.dumps(data_labels)) elif graph_type == 'PieChart': table = [list(zip(data_labels, data))] extra = """{seriesDefaults: {renderer: jQuery.jqplot.PieRenderer, rendererOptions: {fill: true, showDataLabels: true, sliceMargin: 4, lineWidth: 5}}, legend: {show: true, location: 'e'}}""" except Exception as e: messages.error(request, 'Unable to produce valid data: %s' % str(e)) else: adminaction_end.send(sender=modeladmin.model, action='graph_queryset', request=request, queryset=queryset, modeladmin=modeladmin, form=form) elif request.method == 'POST': # total = queryset.all().count() initial = { helpers.ACTION_CHECKBOX_NAME: request.POST.getlist(helpers.ACTION_CHECKBOX_NAME), 'select_across': request.POST.get('select_across', 0) } form = MForm(initial=initial) else: initial = { helpers.ACTION_CHECKBOX_NAME: request.POST.getlist(helpers.ACTION_CHECKBOX_NAME), 'select_across': request.POST.get('select_across', 0) } form = MForm(initial=initial) adminForm = helpers.AdminForm(form, modeladmin.get_fieldsets(request), {}, [], model_admin=modeladmin) media = modeladmin.media + adminForm.media ctx = { 'adminform': adminForm, 'action': 'graph_queryset', 'opts': modeladmin.model._meta, 'action_short_description': graph_queryset.short_description, 'title': u"%s (%s)" % ( graph_queryset.short_description.capitalize(), smart_text(modeladmin.opts.verbose_name_plural), ), 'app_label': queryset.model._meta.app_label, 'media': media, 'extra': extra, 'as_json': json.dumps(table), 'graph_type': graph_type } if django.VERSION[:2] > (1, 7): ctx.update(modeladmin.admin_site.each_context(request)) else: ctx.update(modeladmin.admin_site.each_context()) return render_to_response('adminactions/charts.html', RequestContext(request, ctx))