Support datetime in admin pickle widgets/forms
This commit is contained in:
parent
5064242ef8
commit
3416db98d7
1 changed files with 40 additions and 22 deletions
|
|
@ -30,6 +30,7 @@ Modified for Evennia by Griatch and the Evennia community.
|
||||||
"""
|
"""
|
||||||
from builtins import object
|
from builtins import object
|
||||||
from ast import literal_eval
|
from ast import literal_eval
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from base64 import b64encode, b64decode
|
from base64 import b64encode, b64decode
|
||||||
|
|
@ -38,9 +39,8 @@ from zlib import compress, decompress
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
from django.forms import CharField, Textarea
|
from django.forms.fields import CharField
|
||||||
from django.forms.utils import flatatt
|
from django.forms.widgets import Textarea
|
||||||
from django.utils.html import format_html
|
|
||||||
|
|
||||||
from pickle import loads, dumps
|
from pickle import loads, dumps
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
|
|
@ -107,36 +107,41 @@ def dbsafe_decode(value, compress_object=False):
|
||||||
|
|
||||||
|
|
||||||
class PickledWidget(Textarea):
|
class PickledWidget(Textarea):
|
||||||
|
"""
|
||||||
|
This is responsible for outputting HTML representing a given field.
|
||||||
|
"""
|
||||||
def render(self, name, value, attrs=None, renderer=None):
|
def render(self, name, value, attrs=None, renderer=None):
|
||||||
"""Display of the PickledField in django admin"""
|
"""Display of the PickledField in django admin"""
|
||||||
|
|
||||||
value = repr(value)
|
repr_value = repr(value)
|
||||||
try:
|
|
||||||
# necessary to convert it back after repr(), otherwise validation errors will mutate it
|
|
||||||
value = literal_eval(value)
|
|
||||||
except ValueError:
|
|
||||||
return value
|
|
||||||
|
|
||||||
# fix since the signature of build_attrs changed in Django 1.11
|
# analyze represented value to see how big the field should be
|
||||||
if attrs is not None:
|
if attrs is not None:
|
||||||
attrs["name"] = name
|
attrs["name"] = name
|
||||||
else:
|
else:
|
||||||
attrs = {"name": name}
|
attrs = {"name": name}
|
||||||
attrs['cols'] = 30
|
attrs['cols'] = 30
|
||||||
# adapt rows to width
|
# adapt number of rows to number of lines in string
|
||||||
rows = 1
|
rows = 1
|
||||||
if isinstance(value, str) and "\n" in value:
|
if isinstance(value, str) and "\n" in repr_value:
|
||||||
rows = max(1, len(value.split('\n')))
|
rows = max(1, len(value.split('\n')))
|
||||||
attrs['rows'] = rows
|
attrs['rows'] = rows
|
||||||
attrs = self.build_attrs(attrs)
|
attrs = self.build_attrs(attrs)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# necessary to convert it back after repr(), otherwise validation errors will mutate it
|
||||||
|
value = literal_eval(repr_value)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
return super().render(name, value, attrs=attrs, renderer=renderer)
|
return super().render(name, value, attrs=attrs, renderer=renderer)
|
||||||
# return format_html('<textarea{0}>\r\n{1}</textarea>',
|
|
||||||
# flatatt(final_attrs),
|
|
||||||
# value)
|
|
||||||
|
|
||||||
|
|
||||||
class PickledFormField(CharField):
|
class PickledFormField(CharField):
|
||||||
|
"""
|
||||||
|
This represents one input field for the form.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
widget = PickledWidget
|
widget = PickledWidget
|
||||||
default_error_messages = dict(CharField.default_error_messages)
|
default_error_messages = dict(CharField.default_error_messages)
|
||||||
default_error_messages['invalid'] = (
|
default_error_messages['invalid'] = (
|
||||||
|
|
@ -146,27 +151,40 @@ class PickledFormField(CharField):
|
||||||
"surrounded by quote marks. We have converted it to a string for your "
|
"surrounded by quote marks. We have converted it to a string for your "
|
||||||
"convenience. If it is acceptable, please hit save again.")
|
"convenience. If it is acceptable, please hit save again.")
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
# This needs to fall through to literal_eval.
|
# This needs to fall through to literal_eval.
|
||||||
kwargs['required'] = False
|
kwargs['required'] = False
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
|
value = super().clean(value)
|
||||||
|
|
||||||
|
# handle empty input
|
||||||
try:
|
try:
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
# Field was left blank. Make this None.
|
# Field was left blank. Make this None.
|
||||||
value = 'None'
|
value = 'None'
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
value = 'None'
|
pass
|
||||||
|
|
||||||
|
# parse raw Python
|
||||||
try:
|
try:
|
||||||
return literal_eval(value)
|
return literal_eval(value)
|
||||||
except (ValueError, SyntaxError):
|
except (ValueError, SyntaxError):
|
||||||
try:
|
pass
|
||||||
value = repr(value)
|
|
||||||
return literal_eval(value)
|
# handle datetime objects
|
||||||
except (ValueError, SyntaxError):
|
try:
|
||||||
raise ValidationError(self.error_messages['invalid'])
|
return datetime.strptime(value, "%Y-%m-%d %H:%M:%S.%f")
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# fall through to parsing the repr() of the data
|
||||||
|
try:
|
||||||
|
value = repr(value)
|
||||||
|
return literal_eval(value)
|
||||||
|
except (ValueError, SyntaxError):
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
|
|
||||||
class PickledObjectField(models.Field):
|
class PickledObjectField(models.Field):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue