forked from sshwsfc/xadmin
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbatch.py
More file actions
156 lines (127 loc) · 5.78 KB
/
batch.py
File metadata and controls
156 lines (127 loc) · 5.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
import copy
from django import forms
from django.db import models
from django.core.exceptions import PermissionDenied
from django.forms.models import modelform_factory
from django.template.response import TemplateResponse
from django.utils.encoding import force_unicode
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext as _, ugettext_lazy
from xadmin.layout import FormHelper, Layout, Fieldset, Container, Col
from xadmin.plugins.actions import BaseActionView, ACTION_CHECKBOX_NAME
from xadmin.util import model_ngettext, vendor
from xadmin.views.base import filter_hook
from xadmin.views.edit import ModelFormAdminView
BATCH_CHECKBOX_NAME = '_batch_change_fields'
class ChangeFieldWidgetWrapper(forms.Widget):
def __init__(self, widget):
self.needs_multipart_form = widget.needs_multipart_form
self.attrs = widget.attrs
self.widget = widget
def __deepcopy__(self, memo):
obj = copy.copy(self)
obj.widget = copy.deepcopy(self.widget, memo)
obj.attrs = self.widget.attrs
memo[id(self)] = obj
return obj
@property
def media(self):
media = self.widget.media + vendor('xadmin.plugin.batch.js')
return media
def render(self, name, value, attrs=None):
output = []
is_required = self.widget.is_required
output.append(u'<label class="btn btn-info btn-xs">'
'<input type="checkbox" class="batch-field-checkbox" name="%s" value="%s"%s/> %s</label>' %
(BATCH_CHECKBOX_NAME, name, (is_required and ' checked="checked"' or ''), _('Change this field')))
output.extend([('<div class="control-wrap" style="margin-top: 10px;%s" id="id_%s_wrap_container">' %
((not is_required and 'display: none;' or ''), name)),
self.widget.render(name, value, attrs), '</div>'])
return mark_safe(u''.join(output))
def build_attrs(self, extra_attrs=None, **kwargs):
"Helper function for building an attribute dictionary."
self.attrs = self.widget.build_attrs(extra_attrs=None, **kwargs)
return self.attrs
def value_from_datadict(self, data, files, name):
return self.widget.value_from_datadict(data, files, name)
def id_for_label(self, id_):
return self.widget.id_for_label(id_)
class BatchChangeAction(BaseActionView):
action_name = "change_selected"
description = ugettext_lazy(
u'Batch Change selected %(verbose_name_plural)s')
batch_change_form_template = None
model_perm = 'change'
batch_fields = []
def change_models(self, queryset, cleaned_data):
n = queryset.count()
data = {}
fields = self.opts.fields + self.opts.many_to_many
for f in fields:
if not f.editable or isinstance(f, models.AutoField) \
or not f.name in cleaned_data:
continue
data[f] = cleaned_data[f.name]
if n:
for obj in queryset:
for f, v in data.items():
f.save_form_data(obj, v)
obj.save()
self.message_user(_("Successfully change %(count)d %(items)s.") % {
"count": n, "items": model_ngettext(self.opts, n)
}, 'success')
def get_change_form(self, is_post, fields):
edit_view = self.get_model_view(ModelFormAdminView, self.model)
def formfield_for_dbfield(db_field, **kwargs):
formfield = edit_view.formfield_for_dbfield(db_field, required=is_post, **kwargs)
formfield.widget = ChangeFieldWidgetWrapper(formfield.widget)
return formfield
defaults = {
"form": edit_view.form,
"fields": fields,
"formfield_callback": formfield_for_dbfield,
}
return modelform_factory(self.model, **defaults)
def do_action(self, queryset):
if not self.has_change_permission():
raise PermissionDenied
change_fields = [f for f in self.request.POST.getlist(BATCH_CHECKBOX_NAME) if f in self.batch_fields]
if change_fields and self.request.POST.get('post'):
self.form_obj = self.get_change_form(True, change_fields)(
data=self.request.POST, files=self.request.FILES)
if self.form_obj.is_valid():
self.change_models(queryset, self.form_obj.cleaned_data)
return None
else:
self.form_obj = self.get_change_form(False, self.batch_fields)()
helper = FormHelper()
helper.form_tag = False
helper.include_media = False
helper.add_layout(Layout(Container(Col('full',
Fieldset("", *self.form_obj.fields.keys(), css_class="unsort no_title"), horizontal=True, span=12)
)))
self.form_obj.helper = helper
count = len(queryset)
if count == 1:
objects_name = force_unicode(self.opts.verbose_name)
else:
objects_name = force_unicode(self.opts.verbose_name_plural)
context = self.get_context()
context.update({
"title": _("Batch change %s") % objects_name,
'objects_name': objects_name,
'form': self.form_obj,
'queryset': queryset,
'count': count,
"opts": self.opts,
"app_label": self.app_label,
'action_checkbox_name': ACTION_CHECKBOX_NAME,
})
return TemplateResponse(self.request, self.batch_change_form_template or
self.get_template_list('views/batch_change_form.html'), context, current_app=self.admin_site.name)
@filter_hook
def get_media(self):
media = super(BatchChangeAction, self).get_media()
media = media + self.form_obj.media + self.vendor(
'xadmin.page.form.js', 'xadmin.form.css')
return media