2010-08-04 34 views
6

Ich weiß, wenn ich einen benutzerdefinierten "Selektor" für ein Feld in Django-Admin brauche, muss ich ein benutzerdefiniertes Widget erstellen. Was aber, wenn das Widget zwei Werte erzeugen muss, zum Beispiel X- und Y-Koordinaten, wie kann ich sie in zwei verschiedene Felder aus dem Modell füllen?Widget Füllwerte in zwei Felder

+0

können Sie Ihre Frage in details.Is erklären es eine Beziehung zwischen x & y – ha22109

+0

X und Y Koordinaten aus einer Karte genommen und ich möchte, dass sie speichern, in separaten Bereichen das Model. Gibt es eine Möglichkeit, dies mit dem Widget zu erreichen, oder muss ich die Speicherfunktion des Modells ändern? –

+0

Ähnliche Fragen: http://StackOverflow.com/Questions/2856790/ http://StackOverflow.com/Questions/9333406/ – Jelko

Antwort

3

Jannis Leidel hat vor ziemlich langer Zeit ein Widget veröffentlicht. django-coordinatesfield Soweit ich mich erinnere, dauerte es die Koordinaten von einer Karte und reichte es ein einzelnes Feld und einige Javascript schneiden Sie es in 2 Koordinaten für 2 Felder.

mit einem benutzerdefinierten form In Kombination sollte

+2

@Downvoter: Bitte erklären Sie, warum Sie diese Antwort gefunden Down-Vote würdig – vikingosegundo

7

Sie bei der Umsetzung des Datums-Zeitfeld aussehen kann sehr gut funktionieren, die als 2 Felder im Admin macht.

top-down Going

der Administrator verwendet

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])) 

die wiederum verwendet 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] 

was wiederum die MultiWidget in django.forms.widgets definiert erstreckt, die Sie auch verlängern sollte . Es hat viele nützliche Methoden, die Sie überschreiben können.

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

Ich bin nicht fertig mit dem Bau meiner Widget, aber aus dem aktuellen Fortschritt denke ich, dass dies die Lösung ist, nach der ich gesucht habe. Es ist seltsam, dass ich in der offiziellen Django-Dokumentation keine Informationen über das Multiwidget finden konnte. Wenn Sie also etwas wissen, geben Sie es bitte an. –

+0

Ich fand, dass Multiwidget nur eine Möglichkeit ist, mehrere Widgets aus verschiedenen zu behandeln und dann die Daten in einem einzelnen Feld zu verbinden. So sieht es jetzt mehr wie das JS wasy aus, das vikingosegundo angeboten wird, ist das richtige –

+4

löst das umgekehrte Problem zu der gestellten Frage, das ist, wie man einzelnes Feld tut -> zwei Widgets – Anentropic

0

Sie können das Widget zwei (versteckt) html Eingaben machen machen, deren Namen beziehen sich auf die Felder des Modells, das die erforderlichen Werte über Javascript ihnen werden müssen gefüllt und weisen!

+0

Funktioniert das, wenn sie nicht Teil des Formulars sind? –

Verwandte Themen