Почему метод `` `'не вызывается в моем подклассе MultiValueField?
Я реализовал кастом DurationField
в Django, который хранит целое число, представляющее продолжительность в количестве секунд. Я также определил пользовательский мультивиджет, который принимает пять различных числовых входов (представляющих количество недель, дней, часов, минут и секунд).
Мне удалось заставить его работать в админке, и decompress
кажется, работает как ожидалось; когда я изменяю значения в интерпретаторе и сохраняю их, они правильно отображаются в пяти полях. Тем не мение, compress
не кажется, что меня зовут; когда я пытаюсь изменить значения (или просто сохранить форму, не меняя их), я получаю Enter a whole number.
ошибка от IntegerField
, Похоже, что весь список значений (например, [u'0', u'1', u'2', u'0', u'0']
) передается to_python
,
Я чувствую, что упускаю / пропускаю что-то маленькое, но думаю, что слишком долго смотрел на свой код, чтобы понять, что это может быть.
Вот мой model_fields.py
:
from datetime import timedelta
from django.db.models import PositiveIntegerField
from django.forms import IntegerField, MultiWidget
from django.forms.fields import MultiValueField
from django.forms.widgets import TextInput # NumberInput in Django 1.6
DURATION_FORM_FIELDS = ('weeks', 'days', 'hours', 'minutes', 'seconds')
class DurationMultiWidget(MultiWidget):
def __init__(self, attrs=None):
_widgets = tuple(
[TextInput(attrs=attrs) for field in DURATION_FORM_FIELDS]
)
super(DurationMultiWidget, self).__init__(_widgets, attrs)
def decompress(self, value):
if value:
td = timedelta(seconds=value)
return [
getattr(td, label, 0) for label in DURATION_FORM_FIELDS
]
return [None for field in DURATION_FORM_FIELDS]
class DurationMultiValueField(MultiValueField):
def __init__(self, *args, **kwargs):
fields = tuple(
[IntegerField(label=field_label) for field_label in DURATION_FORM_FIELDS]
)
super(DurationMultiValueField, self).__init__(fields=fields, *args, **kwargs)
def compress(self, data_list):
duration_dict = dict(zip(DURATION_FORM_FIELDS, data_list))
timedelta_object = timedelta(**duration_dict)
return int(timedelta_object.total_seconds())
class DurationField(PositiveIntegerField):
def get_internal_type(self):
return 'DurationField'
def formfield(self, **kwargs):
defaults = {'form_class': DurationMultiValueField}
defaults.update(kwargs)
return super(DurationField, self).formfield(**kwargs)
from south.modelsinspector import add_introspection_rules
add_introspection_rules([], ["^polls\.model_fields\.DurationField"])
Вот admin.py
:
from django import forms
from django.contrib import admin
from .models import Poll
from .model_fields import DurationMultiWidget
class PollAdminForm(forms.ModelForm):
class Meta:
model = Poll
widgets = {
'limit': DurationMultiWidget(),
}
...
class PollAdmin(admin.ModelAdmin):
form = PollAdminForm
admin.site.register(Poll, PollAdmin)
И вот models.py
, так, на всякий случай:
from django.db import models
from django.utils.translation import ugettext_lazy as _
class Poll(models.Model):
...
limit = DurationField(_('limit'), default=0)
1 ответ
Тьфу, это была опечатка: под formfield()
метод, я случайно прошел в **kwargs
вместо **defaults
,
Кроме того, в редких случаях, когда кто-то пытается сделать то же самое, вы должны сделать kwargs.pop('min_value')
в DurationMultiValueField.__init__
(так как это PositiveIntegerField).