Wie zeige ich den Wert eines Django-Formularfelds in einer Vorlage an?


79

Ich habe ein Formular mit einer E-Mail-Eigenschaft.

Bei Verwendung {{ form.email }}im Falle eines Validierungsfehlers rendert Django weiterhin den vorherigen Wert im Wertattribut des Eingabe-Tags:

<input type="text" id="id_email" maxlength="75" class="required"
       value="some@email.com" name="email">

Ich möchte das Eingabe-Tag selbst rendern (um im Fehlerfall JavaScript-Code und eine Fehlerklasse hinzuzufügen). Zum Beispiel ist dies meine Vorlage anstelle von {{ form.email }}:

<input type="text" autocomplete="on" id="id_email" name="email"
       class="email {% if form.email.errors %} error {% endif %}">

Dies zeigt some@email.comdem Benutzer jedoch nicht den fehlerhaften Wert ( in diesem Beispiel) an.

Wie erhalte ich den Feldwert in der Vorlage?


Die Dokumentation enthält einige nützliche Beispiele für die Arbeit mit Formularvorlagen.
DJVG

Antworten:


130

Dies war eine Funktionsanforderung, die in Django 1.3 behoben wurde.

Hier ist der Fehler: https://code.djangoproject.com/ticket/10427

Wenn Sie etwas nach 1.3 ausführen, können Sie in Django-Vorlagen grundsätzlich Folgendes tun:

{{ form.field.value|default_if_none:"" }}

Oder in Jinja2:

{{ form.field.value()|default("") }}

Beachten Sie, dass dies field.value()eine Methode ist, aber in Django werden Vorlagen ()weggelassen, während in Jinja2 Methodenaufrufe explizit sind.

Wenn Sie wissen möchten, welche Version von Django Sie ausführen, erfahren Sie, wann Sie den Befehl runserver ausführen.

Wenn Sie sich vor 1.3 befinden, können Sie wahrscheinlich den im obigen Fehler angegebenen Fix verwenden: https://code.djangoproject.com/ticket/10427#comment:24


Dies ist die richtige Antwort für Django> = 1.3. Dies fehlte auffällig in der Django-Dokumentation, aber das scheint nun behoben worden zu sein (zumindest in der Dev-Version). code.djangoproject.com/ticket/16851
zlovelady

19
Dies hat den bösen Effekt, dass wenn dies der Fall form.field.valueist None, der Text "Keine" angezeigt wird. Um stattdessen eine leere Zeichenfolge anzuzeigen, verwenden Sie{{ form.field.value|default_if_none:"" }}
cberzan

+1 für die Erwähnung funktioniert nur in> = 1.3. Ich verwende immer noch 1.2 und konnte nicht herausfinden, warum es nicht funktioniert hat, bis ich dies gelesen habe.
Wipqozn

Arbeiten mit {{ form.initial.fieldname }}hier (Django 1.2.3).
Santiagopim

1
Ich könnte mich bei @santiagopim irren, aber ich glaube, das gibt Ihnen jedes Mal den Anfangswert, anstatt Ihnen den Wert zu geben, den der Benutzer eingibt. Erstellen Sie beispielsweise ein Formular, das einen Fehler auslöst, anstatt gesendet zu werden, und Sie werden sehen, dass die Benutzereingabe nach der Übermittlung auf den Anfangswert umgeschaltet wurde, anstatt die Benutzereingaben beizubehalten.
mlissner

42

Sie können dies aus der Vorlage heraus mit folgendem tun:

{% if form.instance.some_field %}
      {{form.instance.some_field}}
{% else %}
      {{form.data.some_field}}
{% endif %}

Dadurch wird der Instanzwert angezeigt (wenn das Formular mit einer Instanz erstellt wurde, können Sie stattdessen initial verwenden, wenn Sie möchten) oder die POST-Daten anzeigen, z. B. wenn ein Validierungsfehler auftritt.


2
Schade, dass diese Antwort so tief vergraben ist! Dies ist der Weg, ohne Code zu Ihrem Projekt hinzuzufügen oder Ihren Django zu patchen.
w--

2
Können Sie das, was ich ausfülle, auf diese zusammengesetzten Felder erweitern? Ich habe ein paar Variationen ausprobiert und es hat nicht funktioniert.
Jordaninternets

17

Das scheint zu funktionieren.

{{ form.fields.email.initial }}

11
Ich kann mich irren, aber ich glaube, dass dies jedes Mal den Anfangswert anzeigen wird. Versuchen Sie beispielsweise, das Formular so zu senden, dass ein Fehler ausgegeben wird, und Sie werden feststellen, dass das Formular, das den Fehler erneut lädt, wieder den Anfangswert hat und nicht den Wert, den der Benutzer eingegeben hat, bevor er den Fehler ausgelöst hat.
mlissner

16

Ich habe eine einfache Lösung für Sie!

{{ form.data.email }}

Ich habe es versucht und es hat funktioniert. Dazu muss Ihre Ansicht die Formularklasse mit den POST-Daten füllen.

Sehr einfaches Beispiel:

def your_view(request):
  if request.method == 'POST':
    form = YourForm(request.POST)
    if form.is_valid():
      # some code here
  else:
    form = YourForm()

  return render_to_response('template.html', {'form':form})

Hoffe das hilft dir. Wenn Sie Fragen haben, lassen Sie es mich bitte wissen.


Die bereinigten Daten enthalten kein E-Mail-Feld, wenn sie während der Validierung nicht bereinigt werden konnten.
Shanyu

Du hast recht. Sie können nicht auf bereinigte Daten zugreifen, wenn is_valid () fehlschlägt. Ich suche nach einer anderen Lösung.
Jens

Ich habe meinen Code aktualisiert. Es gab eine einfache Lösung. Verwenden Sie anstelle von bereinigten Daten einfach Daten. Das hat auch funktioniert, wenn die Validierung fehlschlägt!
Jens

Daten funktionieren bei mir nicht ... {{form.description}} gibt ein Steuerelement mit dem korrekten Wert {{form.data.description}} ist leer (tatsächlich gibt {{form.data}} {} zurück)
Eran Kampf

Übrigens initialisiere ich das Formular folgendermaßen: form_details = forms.UserDetailsForm (instance = request.user)
Eran Kampf


5

Die von Jens vorgeschlagene Lösung ist richtig. Es stellt sich jedoch heraus, dass Django die Daten nicht auffüllt, wenn Sie Ihre ModelForm mit einer Instanz initialisieren (Beispiel unten):

def your_view(request):   
    if request.method == 'POST':
        form = UserDetailsForm(request.POST)
        if form.is_valid():
          # some code here   
        else:
          form = UserDetailsForm(instance=request.user)

Also habe ich meine eigene ModelForm-Basisklasse erstellt, die die Anfangsdaten auffüllt:

from django import forms 
class BaseModelForm(forms.ModelForm):
    """
    Subclass of `forms.ModelForm` that makes sure the initial values
    are present in the form data, so you don't have to send all old values
    for the form to actually validate.
    """
    def merge_from_initial(self):
        filt = lambda v: v not in self.data.keys()
        for field in filter(filt, getattr(self.Meta, 'fields', ())):
            self.data[field] = self.initial.get(field, None)

Das einfache Ansichtsbeispiel sieht dann folgendermaßen aus:

def your_view(request):   if request.method == 'POST':
    form = UserDetailsForm(request.POST)
    if form.is_valid():
      # some code here   
    else:
      form = UserDetailsForm(instance=request.user)
      form.merge_from_initial()

Ich verstehe nicht, warum Django dies nicht standardmäßig tut ... Ich denke, ich werde einen Patch einreichen und sehen, was die Leute dazu sagen.
Eran Kampf

3

Ich habe einige der genannten Möglichkeiten ausprobiert und so mein Problem gelöst:

#forms.py
class EditProfileForm(forms.ModelForm):
    first_name = forms.CharField(label='First Name',
                                 widget=forms.TextInput(
                                 attrs={'class': 'form-control'}),
                                 required=False)
    last_name = forms.CharField(label='Last Name',
                                 widget=forms.TextInput(
                                 attrs={'class': 'form-control'}),
                                 required=False)
    # username = forms.CharField(widget=forms.TextInput(
    #                              attrs={'class': 'form-control'}),
    #                              required=True)
    address = forms.CharField(max_length=255, widget=forms.TextInput(
                                 attrs={'class': 'form-control'}),
                                 required=False)
    phoneNumber = forms.CharField(max_length=11,
                                 widget=forms.TextInput(
                                 attrs={'class': 'form-control'}),
                                 required=False)
    photo = forms.ImageField(label='Change Profile Image', required=False)

    class Meta:
        model = User
        fields = ['photo', 'first_name', 'last_name', 'phoneNumber', 'address']
                  # 'username',



#views.py
def edit_user_profile(request, username):
    user = request.user
    username = User.objects.get(username=username)
    user_extended_photo = UserExtended.objects.get(user=user.id)
    form = EditProfileForm(request.POST or None, request.FILES, instance=user)
    user_extended = UserExtended.objects.get(user=user)
    if request.method == 'POST':
        if form.is_valid():
            # photo = UserExtended(photo=request.FILES['photo'] or None, )
            user.first_name = request.POST['first_name']
            user.last_name = request.POST['last_name']
            user_extended.address = request.POST['address']
            user_extended.phoneNumber = request.POST['phoneNumber']
            user_extended.photo = form.cleaned_data["photo"]
            # username = request.POST['username']
            user_extended.save()
            user.save()

            context = {
                'form': form,
                'username': username,
                'user_extended_photo': user_extended_photo,
            }

            return render(request, 'accounts/profile_updated.html', context)
    else:
        photo = user_extended.photo
        first_name = user.first_name
        last_name = user.last_name
        address = user_extended.address
        phoneNumber = user_extended.phoneNumber
        form = EditProfileForm(
            initial={'first_name': first_name, 'last_name': last_name,
                                   'address': address, 'phoneNumber': phoneNumber,
                                   'photo': photo})
    context = {
        'form': form,
        'username': username,
        'user_extended_photo': user_extended_photo,

    }
    return render_to_response('accounts/edit_profile.html', context,
                                 context_instance=RequestContext(request))

#edit_profile.html
  <form action="/accounts/{{ user.username }}/edit_profile/" method="post" enctype='multipart/form-data'>
                                    {% csrf_token %}
                                        <div class="col-md-6">
                                            <div class="form-group">
                                                {{ form.as_p }}
                                            </div>
                                        </div>
                                    <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
                                    <button type="submit"  value="Update Profile" class="btn btn-info btn-fill pull-right">Update Profile</button>
                                    <div class="clearfix"></div>
                                </form>

Ich versuche dies so zu erklären, dass Anfänger es leichter verstehen können. Achten Sie genau auf dieelse:

        photo = user_extended.photo
        first_name = user.first_name
        last_name = user.last_name
        address = user_extended.address
        phoneNumber = user_extended.phoneNumber
        form = EditProfileForm(
            initial={'first_name': first_name, 'last_name': last_name,
                                  'address': address, 'phoneNumber': phoneNumber,
                                  'photo': photo}) 

Es ist das, was den Wert zuschreibt, zB:

<p><label for="id_first_name">First Name:</label> <input class="form-control" id="id_first_name" name="first_name" type="text" value="Emmanuel" /></p>
<p><label for="id_last_name">Last Name:</label> <input class="form-control" id="id_last_name" name="last_name" type="text" value="Castor" /></p>

2

Wenn Sie das Formular mit einer Instanz und nicht mit POST-Daten gefüllt haben (wie in der vorgeschlagenen Antwort erforderlich), können Sie über {{form.instance.my_field_name}} auf die Daten zugreifen.


2

Ich wollte den Wert eines Formset-Feldes anzeigen. Ich schloss diese Lösung, die auch für normale Formen funktionieren sollte:

{% if form.email.data %} {{ form.email.data }}
{% else %} {{ form.initial.email }} 
{% endif %}

Die oben genannten Lösungen haben bei mir nicht sehr gut funktioniert, und ich bezweifle, dass sie bei vorangestellten Formularen (wie Assistenten und Formularsätzen) funktionieren würden. Die verwendeten Lösungen {{ form.data.email }}können nicht funktionieren, da es sich um eine Wörterbuchsuche handelt. Bei vorangestellten Formularen würde Ihr Feldname ungefähr wie "1-E-Mail" (Assistent und vorangestelltes Formular) oder "Formular-1-E-Mail" (Formularsatz) aussehen Das Minuszeichen (-) ist in gepunkteten Vorlagen-Suchausdrücken nicht zulässig.

{{form.field_name.value}} ist nur Django 1.3+.



-1
{{form.fields.email}}

Dies ergibt: <django.forms.fields.RegexField Objekt um 0x083235B0>
Eran Kampf

Sie können einen Filter schreiben, um den Wert abzurufen.
Shanyu

Es gibt keinen eingebauten Weg, um es zu bekommen?
Eran Kampf
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.