2010-08-04 34 views
6

我知道,如果我需要在django-admin中爲字段定製「選擇器」,我需要創建一個自定義小部件。 但是,如果小部件必須生成兩個值(例如X和Y座標),那麼如何將它們填充到模型的兩個不同字段中呢?在兩個字段中的Widget填充值

+0

你能解釋一下你的問題在details.Is有X&Y – ha22109 2010-08-08 22:12:08

+0

X和Y之間的關係是從地圖座標拍攝,我想將它們存儲在單獨的領域該模型。有沒有辦法實現這個小部件,或者我必須修改模型的保存功能? – 2010-08-09 07:24:13

+0

Similar questions:http://stackoverflow.com/questions/2856790/ http://stackoverflow.com/questions/9333406/ – Jelko 2013-08-21 14:54:34

回答

3

Jannis Leidel在很久以前發佈了一個小部件。​​ 據我記得,它從地圖上的座標,並通過它一個單一的領域和一些JavaScript剪切成2個領域的2個座標。

具有自定義form結合它應該工作得很好

+2

@downvoter:請解釋你爲什麼找到這個答案向下投票值得 – vikingosegundo 2011-03-14 22:38:00

7

你可以看一下日期時間字段的實施,呈現在管理員2場。

去自上而下,

管理員使用

class AdminSplitDateTime(forms.SplitDateTimeWidget): 
    """ 
    A SplitDateTime Widget that has some admin-specific styling. 
    """ 
    def __init__(self, attrs=None): 
     widgets = [AdminDateWidget, AdminTimeWidget] 
     # Note that we're calling MultiWidget, not SplitDateTimeWidget, because 
     # we want to define widgets. 
     forms.MultiWidget.__init__(self, widgets, attrs) 

    def format_output(self, rendered_widgets): 
     return mark_safe(u'<p class="datetime">%s %s<br />%s %s</p>' % \ 
      (_('Date:'), rendered_widgets[0], _('Time:'), rendered_widgets[1])) 

又使用SplitDateTimeWidget

class SplitDateTimeWidget(MultiWidget): 
    """ 
    A Widget that splits datetime input into two <input type="text"> boxes. 
    """ 
    date_format = DateInput.format 
    time_format = TimeInput.format 

    def __init__(self, attrs=None, date_format=None, time_format=None): 
     if date_format: 
      self.date_format = date_format 
     if time_format: 
      self.time_format = time_format 
     widgets = (DateInput(attrs=attrs, format=self.date_format), 
        TimeInput(attrs=attrs, format=self.time_format)) 
     super(SplitDateTimeWidget, self).__init__(widgets, attrs) 

    def decompress(self, value): 
     if value: 
      return [value.date(), value.time().replace(microsecond=0)] 
     return [None, None] 

這反過來又擴展了django.forms.widgets定義的MultiWidget,你也應該擴展。它有很多有用的方法可以覆蓋。

class MultiWidget(Widget): 
""" 
A widget that is composed of multiple widgets. 

Its render() method is different than other widgets', because it has to 
figure out how to split a single value for display in multiple widgets. 
The ``value`` argument can be one of two things: 

    * A list. 
    * A normal value (e.g., a string) that has been "compressed" from 
     a list of values. 

In the second case -- i.e., if the value is NOT a list -- render() will 
first "decompress" the value into a list before rendering it. It does so by 
calling the decompress() method, which MultiWidget subclasses must 
implement. This method takes a single "compressed" value and returns a 
list. 

When render() does its HTML rendering, each value in the list is rendered 
with the corresponding widget -- the first value is rendered in the first 
widget, the second value is rendered in the second widget, etc. 

Subclasses may implement format_output(), which takes the list of rendered 
widgets and returns a string of HTML that formats them any way you'd like. 

You'll probably want to use this class with MultiValueField. 
""" 
def __init__(self, widgets, attrs=None): 
    self.widgets = [isinstance(w, type) and w() or w for w in widgets] 
    super(MultiWidget, self).__init__(attrs) 

def render(self, name, value, attrs=None): 
    # value is a list of values, each corresponding to a widget 
    # in self.widgets. 
    if not isinstance(value, list): 
     value = self.decompress(value) 
    output = [] 
    final_attrs = self.build_attrs(attrs) 
    id_ = final_attrs.get('id', None) 
    for i, widget in enumerate(self.widgets): 
     try: 
      widget_value = value[i] 
     except IndexError: 
      widget_value = None 
     if id_: 
      final_attrs = dict(final_attrs, id='%s_%s' % (id_, i)) 
     output.append(widget.render(name + '_%s' % i, widget_value, final_attrs)) 
    return mark_safe(self.format_output(output)) 

def id_for_label(self, id_): 
    # See the comment for RadioSelect.id_for_label() 
    if id_: 
     id_ += '_0' 
    return id_ 
id_for_label = classmethod(id_for_label) 

def value_from_datadict(self, data, files, name): 
    return [widget.value_from_datadict(data, files, name + '_%s' % i) for i, widget in enumerate(self.widgets)] 

def _has_changed(self, initial, data): 
    if initial is None: 
     initial = [u'' for x in range(0, len(data))] 
    else: 
     if not isinstance(initial, list): 
      initial = self.decompress(initial) 
    for widget, initial, data in zip(self.widgets, initial, data): 
     if widget._has_changed(initial, data): 
      return True 
    return False 

def format_output(self, rendered_widgets): 
    """ 
    Given a list of rendered widgets (as strings), returns a Unicode string 
    representing the HTML for the whole lot. 

    This hook allows you to format the HTML design of the widgets, if 
    needed. 
    """ 
    return u''.join(rendered_widgets) 

def decompress(self, value): 
    """ 
    Returns a list of decompressed values for the given compressed value. 
    The given value can be assumed to be valid, but not necessarily 
    non-empty. 
    """ 
    raise NotImplementedError('Subclasses must implement this method.') 

def _get_media(self): 
    "Media for a multiwidget is the combination of all media of the subwidgets" 
    media = Media() 
    for w in self.widgets: 
     media = media + w.media 
    return media 
media = property(_get_media) 

def __deepcopy__(self, memo): 
    obj = super(MultiWidget, self).__deepcopy__(memo) 
    obj.widgets = copy.deepcopy(self.widgets) 
    return obj 
+0

我沒有完成我的小部件,但從目前的進展,我認爲這是我正在尋找的解決方案。奇怪的是,我在官方的django文檔中找不到關於multiwidget的任何信息,所以如果你知道一些信息,請提供它。 – 2010-08-16 07:04:03

+0

我發現multiwidget只是一種處理來自不同的多個小部件的方法,然後將數據綁定在單個字段中。所以它現在看起來更像是vikingosegundo提供的JS wasy是正確的一個 – 2010-08-18 08:12:59

+4

解決了問題的相反問題,這是如何做單個字段 - >兩個小部件 – Anentropic 2011-04-21 15:14:30

0

可以使部件呈現兩(隱藏)HTML的輸入,他們的名字涉及到需要填補,並通過JavaScript分配必要的值給他們的模特的領域!

+0

如果它們不是形式的一部分,這是否工作? – 2010-08-15 12:00:32