【问题标题】:Why is the `compress` method not being called on my subclass of MultiValueField?为什么我的 MultiValueField 子类没有调用 `compress` 方法?
【发布时间】:2014-04-08 07:26:32
【问题描述】:

我在 Django 中实现了一个自定义 DurationField,它存储了一个整数,表示持续时间(以秒为单位)。我还定义了一个自定义的 multiwidget,它接受五个不同的数字输入(表示周数、天数、小时数、分钟数和秒数)。

我已经设法让它在管理员中工作,decompress 似乎按预期工作;当我更改解释器中的值并保存它们时,它们会正确显示在五个字段中。但是,compress 似乎没有被调用;当我尝试更改值(或只是保存表单而不更改它们)时,我从IntegerField 收到Enter a whole number. 错误。似乎整个值列表(例如[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) 

【问题讨论】:

    标签: python django django-forms django-models django-multiwidget


    【解决方案1】:

    呃,这是一个错字:在formfield() 方法下,我不小心传入了**kwargs 而不是**defaults

    顺便说一句,在极少数情况下,有人试图做完全相同的事情,您必须在 DurationMultiValueField.__init__ 中执行 kwargs.pop('min_value')(因为它是 PositiveIntegerField)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-08-01
      • 2018-08-22
      • 1970-01-01
      • 2016-05-08
      • 2014-10-13
      • 1970-01-01
      • 2017-12-07
      • 2019-07-03
      相关资源
      最近更新 更多