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
Antwort
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
@Downvoter: Bitte erklären Sie, warum Sie diese Antwort gefunden Down-Vote würdig – vikingosegundo
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
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. –
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 –
löst das umgekehrte Problem zu der gestellten Frage, das ist, wie man einzelnes Feld tut -> zwei Widgets – Anentropic
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!
Funktioniert das, wenn sie nicht Teil des Formulars sind? –
Hier ist ein Beispiel für eine Modelform: http://www.adamalton.co.uk/blog/displaying-django-genericforeignkey-as-single-form-field/
ein zusätzliches Formularfeld zum Formular hinzufügen (für die einzelnen Widget) und die beiden ‚echten‘ Felder ausschließen, dann die init außer Kraft setzen und Methoden speichern die tun zusätzliche Logik, die es funktioniert.
Auch gleiche Frage: How to get a single widget to set 2 fields in Django?
können Sie Ihre Frage in details.Is erklären es eine Beziehung zwischen x & y – ha22109
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? –
Ähnliche Fragen: http://StackOverflow.com/Questions/2856790/ http://StackOverflow.com/Questions/9333406/ – Jelko