Esempio n. 1
0
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))
Esempio n. 2
0
def merge(master, other, fields=None, commit=False, m2m=None, related=None):  # noqa
    """
        Merge 'other' into master.

        `fields` is a list of fieldnames that must be readed from ``other`` to put into master.
        If ``fields`` is None ``master`` will get all the ``other`` values except primary_key.
        Finally ``other`` will be deleted and master will be preserved

    @param master:  Model instance
    @param other: Model instance
    @param fields: list of fieldnames to  merge
    @param m2m: list of m2m fields to merge. If empty will be removed
    @param related: list of related fieldnames to merge. If empty will be removed
    @return:
    """

    fields = fields or [f.name for f in master._meta.fields]

    all_m2m = {}
    all_related = {}

    if related == ALL_FIELDS:
        related = [rel.get_accessor_name()
                   for rel in compat.get_all_related_objects(master)]
# for rel in master._meta.get_all_related_objects(False, False, False)]

    if m2m == ALL_FIELDS:
        m2m = [field.name for field in master._meta.many_to_many]

    if m2m and not commit:
        raise ValueError('Cannot save related with `commit=False`')
    with compat.atomic():
        result = clone_instance(master)

        for fieldname in fields:
            f = get_field_by_path(master, fieldname)
            if f and not f.primary_key:
                setattr(result, fieldname, getattr(other, fieldname))

        if m2m:
            for fieldname in set(m2m):
                all_m2m[fieldname] = []
                field_object = get_field_by_path(master, fieldname)
                if not isinstance(field_object, ManyToManyField):
                    raise ValueError('{0} is not a ManyToManyField field'.format(fieldname))
                source_m2m = getattr(other, field_object.name)
                for r in source_m2m.all():
                    all_m2m[fieldname].append(r)
        if related:
            for name in set(related):
                related_object = get_field_by_path(master, name)
                all_related[name] = []
                if related_object and isinstance(related_object.field, OneToOneField):
                    try:
                        accessor = getattr(other, name)
                        all_related[name] = [(related_object.field.name, accessor)]
                    except ObjectDoesNotExist:
                        pass
                else:
                    accessor = getattr(other, name, None)
                    if accessor:
                        rel_fieldname = list(accessor.core_filters.keys())[0].split('__')[0]
                        for r in accessor.all():
                            all_related[name].append((rel_fieldname, r))

        if commit:
            for name, elements in list(all_related.items()):
                for rel_fieldname, element in elements:
                    setattr(element, rel_fieldname, master)
                    element.save()

            other.delete()
            result.save()
            for fieldname, elements in list(all_m2m.items()):
                dest_m2m = getattr(result, fieldname)
                for element in elements:
                    dest_m2m.add(element)
    return result
Esempio n. 3
0
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))
Esempio n. 4
0
def merge(modeladmin, request, queryset):
    """
    Merge two model instances. Move all foreign keys.

    """

    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))
Esempio n. 5
0
def merge(modeladmin, request, queryset):
    """
    Merge two model instances. Move all foreign keys.

    """

    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))