1
from copy import deepcopy
2
from django.conf import settings
3
from django.contrib.admin.widgets import AdminSplitDateTime, AdminDateWidget
4
from django.forms.models import modelform_factory
5
from django.template.loader import render_to_string
6
from django.utils import simplejson
8
from django.utils.translation import ugettext
10
from inplaceeditform.commons import apply_filters, import_module, has_transmeta, get_static_url, get_admin_static_url
11
from inplaceeditform.perms import SuperUserPermEditInline
14
class BaseAdaptorField(object):
16
def __init__(self, request, obj, field_name,
19
self.request = request
21
self.field_name = field_name
22
self.filters_to_show = filters_to_show and filters_to_show.split('|')
24
self.model = obj.__class__
25
self.field_name_render = field_name # To transmeta
27
self.config = config or {}
28
self.config['obj_id'] = self.obj.id
29
self.config['field_name'] = self.field_name_render
30
self.config['filters_to_show'] = self.filters_to_show
31
self.config['app_label'] = self.model._meta.app_label
32
self.config['module_name'] = self.model._meta.module_name
33
self.config['filters_to_show'] = filters_to_show
34
self.config['can_auto_save'] = 1
36
filters_to_edit = self.config.get('filters_to_edit', None)
37
self.filters_to_edit = filters_to_edit and filters_to_edit.split('|') or []
39
self.class_inplace = self.config.get('class_inplace', '')
40
self.tag_name_cover = self.config.get('tag_name_cover', 'span')
41
font_size = self.config.get('font_size', '12')
42
if font_size.endswith('px'):
43
self.font_size = float(font_size.replace('px', ''))
46
loads = self.config.get('loads', None)
47
self.loads = loads and loads.split(':') or []
49
self._transmeta_processing()
57
return 'inplaceedit %s' % (self.name)
60
def get_config(self, **kwargs):
62
Get the arguments given to the template tag element and complete these
63
with the ones from the settings.py if necessary.
67
config_from_settings = getattr(
68
settings, "DEFAULT_INPLACE_EDIT_OPTIONS", {})
69
config_one_by_one = getattr(
70
settings, "DEFAULT_INPLACE_EDIT_OPTIONS_ONE_BY_ONE", False)
72
if not config_one_by_one:
73
# Solution 1: Using default config only if none specified.
74
if not config and config_from_settings:
75
config = config_from_settings
77
# Solution 2: Updating the configured config with the default one.
78
config = dict(config_from_settings, **config)
82
def get_form_class(self):
83
return modelform_factory(self.model)
86
form_class = self.get_form_class()
87
return form_class(instance=self.obj,
89
prefix=id(form_class))
92
field = self.get_form()[self.field_name]
93
field = self._adding_size(field)
96
def get_value_editor(self, value):
97
return self.get_field().field.clean(value)
99
def render_value(self, field_name=None):
100
field_name = field_name or self.field_name_render
101
value = getattr(self.obj, field_name)
104
return apply_filters(value, self.filters_to_show, self.loads)
106
def render_value_edit(self):
107
value = self.render_value()
110
return self.empty_value()
112
def empty_value(self):
114
Get the text to display when the field is empty.
116
edit_empty_value = self.config.get('edit_empty_value', False)
118
return edit_empty_value
120
return ugettext(getattr(settings, 'INPLACEEDIT_EDIT_EMPTY_VALUE',
121
'Dobleclick to edit'))
123
def render_field(self, template_name="inplaceeditform/render_field.html", extra_context=None):
124
extra_context = extra_context or {}
125
context = {'form': self.get_form(),
126
'field': self.get_field(),
127
'STATIC_URL': get_static_url(),
128
'class_inplace': self.class_inplace}
129
context.update(extra_context)
130
return render_to_string(template_name, context)
132
def render_media_field(self, template_name="inplaceeditform/render_media_field.html", extra_context=None):
133
extra_context = extra_context or {}
134
context = {'field': self.get_field(),
135
'STATIC_URL': get_static_url(),
136
'ADMIN_MEDIA_PREFIX': get_admin_static_url()}
137
context.update(extra_context)
139
return render_to_string(template_name, context)
141
def render_config(self, template_name="inplaceeditform/render_config.html"):
142
return render_to_string(template_name,
143
{'config': self.config})
146
can_edit_adaptor_path = getattr(settings, 'ADAPTOR_INPLACEEDIT_EDIT', None)
147
if can_edit_adaptor_path:
148
path_module, class_adaptor = ('.'.join(can_edit_adaptor_path.split('.')[:-1]),
149
can_edit_adaptor_path.split('.')[-1])
150
cls_perm = getattr(import_module(path_module), class_adaptor)
152
cls_perm = SuperUserPermEditInline
153
return cls_perm.can_edit(self)
155
def loads_to_post(self, request):
156
return simplejson.loads(request.POST.get('value'))
158
def save(self, value):
159
setattr(self.obj, self.field_name, value)
162
def get_auto_height(self):
163
return self.config.get('auto_height', False)
165
def get_auto_width(self):
166
return self.config.get('auto_width', False)
168
def treatment_height(self, height, width=None):
169
if isinstance(height, basestring) and not height.endswith('px') or not isinstance(height, basestring):
170
height = "%spx" % height
173
def treatment_width(self, width, height=None):
174
if isinstance(width, basestring) and not width.endswith('px') or not isinstance(width, basestring):
175
width = "%spx" % width
178
def _adding_size(self, field):
179
attrs = field.field.widget.attrs
180
widget_options = self.config and self.config.get('widget_options', {})
181
auto_height = self.get_auto_height()
182
auto_width = self.get_auto_width()
183
if not 'style' in attrs:
185
height = int(widget_options.get('height', '0').replace('px', ''))
186
width = int(widget_options.get('width', '0').replace('px', ''))
187
if height and not auto_height:
188
style += "height: %s; " % self.treatment_height(height, width)
189
if width and not auto_width:
190
style += "width: %s; " % self.treatment_width(width, height)
191
if not auto_height or not auto_width:
192
style += "font-size: %spx; " % self.font_size
193
for key, value in widget_options.items():
194
if key in ('height', 'width'):
196
style += "%s: %s; " % (key, value)
197
attrs['style'] = style
198
field.field.widget.attrs = attrs
201
def _transmeta_processing(self):
204
translatable_fields = self._get_translatable_fields(self.model)
205
if self.field_name in translatable_fields:
206
self.field_name = transmeta.get_real_fieldname(self.field_name)
207
self.transmeta = True
208
if not self.render_value(self.field_name):
209
message_translation = ugettext(getattr(settings, 'INPLACEEDIT_EDIT_MESSAGE_TRANSLATION',
210
'Write a traslation'))
211
self.initial = {self.field_name: message_translation}
213
self.transmeta = False
215
def _get_translatable_fields(self, cls):
217
translatable_fields = []
218
[translatable_fields.extend(cl._meta.translatable_fields) for cl in classes \
219
if getattr(cl, '_meta', None) and getattr(cl._meta, 'translatable_fields', None)]
220
return translatable_fields
223
class AdaptorTextField(BaseAdaptorField):
226
MULTIPLIER_WIDTH = 1.25
232
def treatment_height(self, height, width=None):
233
return "%spx" % (self.font_size + self.INCREASE_HEIGHT)
235
def treatment_width(self, width, height=None):
236
return "%spx" % (width * self.MULTIPLIER_WIDTH)
239
class AdaptorTextAreaField(BaseAdaptorField):
246
class AdaptorBooleanField(BaseAdaptorField):
252
def render_value(self, field_name=None, template_name="inplaceeditform/adaptor_boolean/render_value.html"):
253
value = super(AdaptorBooleanField, self).render_value(field_name)
254
return render_to_string(template_name, {'value': value, 'STATIC_URL': get_static_url()})
256
def render_field(self, template_name="inplaceeditform/adaptor_boolean/render_field.html"):
257
return super(AdaptorBooleanField, self).render_field(template_name)
259
def render_media_field(self, template_name="inplaceeditform/adaptor_boolean/render_media_field.html"):
260
return super(AdaptorBooleanField, self).render_media_field(template_name)
263
class BaseDateField(BaseAdaptorField):
265
def __init__(self, *args, **kwargs):
266
super(BaseDateField, self).__init__(*args, **kwargs)
267
self.config['can_auto_save'] = 0
269
def render_media_field(self, template_name="inplaceeditform/adaptor_date/render_media_field.html"):
270
return super(BaseDateField, self).render_media_field(template_name)
273
class AdaptorDateField(BaseDateField):
279
def render_field(self, template_name="inplaceeditform/adaptor_date/render_field.html"):
280
return super(AdaptorDateField, self).render_field(template_name)
283
field = super(AdaptorDateField, self).get_field()
284
field.field.widget = AdminDateWidget()
287
def render_value(self, field_name=None):
288
val = super(AdaptorDateField, self).render_value(field_name)
289
if not isinstance(val, str) and not isinstance(val, unicode):
290
val = apply_filters(val, ["date:'%s'" % settings.DATE_FORMAT])
294
class AdaptorDateTimeField(BaseDateField):
300
def render_field(self, template_name="inplaceeditform/adaptor_datetime/render_field.html"):
301
return super(AdaptorDateTimeField, self).render_field(template_name)
303
def render_media_field(self, template_name="inplaceeditform/adaptor_datetime/render_media_field.html"):
304
return super(AdaptorDateTimeField, self).render_media_field(template_name)
307
field = super(AdaptorDateTimeField, self).get_field()
308
field.field.widget = AdminSplitDateTime()
311
def render_value(self, field_name=None):
312
val = super(AdaptorDateTimeField, self).render_value(field_name)
313
if not isinstance(val, str) and not isinstance(val, unicode):
314
val = apply_filters(val, ["date:'%s'" % settings.DATETIME_FORMAT])
318
class AdaptorChoicesField(BaseAdaptorField):
320
MULTIPLIER_HEIGHT = 1.75
327
def treatment_height(self, height, width=None):
328
return "%spx" % (self.font_size * self.MULTIPLIER_HEIGHT)
330
def treatment_width(self, width, height=None):
331
return "%spx" % (width + self.INCREASE_WIDTH)
333
def render_value(self, field_name=None):
334
field_name = field_name or self.field_name
335
return super(AdaptorChoicesField, self).render_value('get_%s_display' % field_name)
338
class AdaptorForeingKeyField(BaseAdaptorField):
340
MULTIPLIER_HEIGHT = 1.75
347
def treatment_height(self, height, width=None):
348
return "%spx" % int(self.font_size * self.MULTIPLIER_HEIGHT)
350
def treatment_width(self, width, height=None):
351
return "%spx" % (width + self.INCREASE_WIDTH)
353
def render_value(self, field_name=None):
354
value = super(AdaptorForeingKeyField, self).render_value(field_name)
355
value = getattr(value, '__unicode__', None) and value.__unicode__() or None
358
def get_value_editor(self, value):
359
value = super(AdaptorForeingKeyField, self).get_value_editor(value)
360
return value and value.pk
362
def save(self, value):
363
setattr(self.obj, "%s_id" % self.field_name, value)
367
class AdaptorManyToManyField(BaseAdaptorField):
369
MULTIPLIER_HEIGHT = 6
376
def treatment_height(self, height, width=None):
377
return "%spx" % (self.font_size * self.MULTIPLIER_HEIGHT)
379
def treatment_width(self, width, height=None):
380
return "%spx" % (width + self.INCREASE_WIDTH)
382
def get_value_editor(self, value):
383
return [item.pk for item in super(AdaptorManyToManyField, self).get_value_editor(value)]
385
def render_value(self, field_name=None):
386
return super(AdaptorManyToManyField, self).render_value(field_name).all()
389
class AdaptorCommaSeparatedManyToManyField(AdaptorManyToManyField):
395
def __init__(self, *args, **kwargs):
396
super(AdaptorCommaSeparatedManyToManyField, self).__init__(*args, **kwargs)
397
self.config['can_auto_save'] = 0
399
def render_value(self, field_name=None, template_name="inplaceeditform/adaptor_m2m/render_commaseparated_value.html"):
400
queryset = super(AdaptorCommaSeparatedManyToManyField, self).render_value(field_name)
401
return render_to_string(template_name, {'queryset': queryset})
404
class AdaptorFileField(BaseAdaptorField):
406
MULTIPLIER_HEIGHT = 2
408
def __init__(self, *args, **kwargs):
409
super(AdaptorFileField, self).__init__(*args, **kwargs)
410
self.config['can_auto_save'] = 0
412
def loads_to_post(self, request):
413
files = request.FILES.values()
414
return files and files[0] or None
416
def treatment_height(self, height, width=None):
417
return "%spx" % (self.font_size * self.MULTIPLIER_HEIGHT)
419
def render_field(self, template_name="inplaceeditform/adaptor_file/render_field.html"):
421
from django.core.context_processors import csrf
422
extra_context = csrf(self.request)
425
return super(AdaptorFileField, self).render_field(template_name, extra_context)
427
def render_media_field(self, template_name="inplaceeditform/adaptor_file/render_media_field.html"):
428
return super(AdaptorFileField, self).render_media_field(template_name)
430
def render_value(self, field_name=None, template_name='inplaceeditform/adaptor_file/render_value.html'):
431
field_name = field_name or self.field_name_render
432
value = getattr(self.obj, field_name)
435
config = deepcopy(self.config)
436
context = {'value': value,
438
config.update(context)
439
return render_to_string(template_name, config)
441
def save(self, value):
442
file_name = value and value.name
444
super(AdaptorFileField, self).save(value)
446
getattr(self.obj, self.field_name).save(file_name, value)
449
class AdaptorImageField(AdaptorFileField):
451
def render_field(self, template_name="inplaceeditform/adaptor_image/render_field.html"):
452
return super(AdaptorImageField, self).render_field(template_name)
454
def render_media_field(self, template_name="inplaceeditform/adaptor_image/render_media_field.html"):
455
return super(AdaptorImageField, self).render_media_field(template_name)
457
def render_value(self, field_name=None, template_name='inplaceeditform/adaptor_image/render_value.html'):
458
return super(AdaptorImageField, self).render_value(field_name=field_name, template_name=template_name)